排序
归并排序
#include<iostream>
#include<cassert>
using namespace std;
void Merge(int *arr, int left,int mid, int right, int *temp)
{
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int idx = left;
while (begin1 <= end1&&begin2<=end2)
{
if (arr[begin1] < arr[begin2])
temp[idx++] = arr[begin1++];
else
temp[idx++] = arr[begin2++];
}
while (begin1<=end1)
temp[idx++] = arr[begin1++];
while (begin2<=end2)
temp[idx++] = arr[begin2++];
for (int i = left; i<=right; i++)
arr[i] = temp[i];
}
void _Merge_Sort(int *arr, int left, int right, int *temp)
{
if (right > left)
{
int mid = left + ((right - left) >> 1);
_Merge_Sort(arr, left, mid, temp);
_Merge_Sort(arr, mid + 1, right, temp);
Merge(arr, left, mid,right, temp);
}
}
void Merge_Sort(int *arr, int left, int right)
{
assert(right - left > 1);
int *temp = new int[right - left + 1];
_Merge_Sort(arr, left, right, temp);
delete[]temp;
}
int main()
{
int arr[] = { 2, 3, 45, 2, 5, 1, 8, 5, 2, 3, 0 };
int len = sizeof(arr) / sizeof(arr[0]);
Merge_Sort(arr, 0, len-1);
for (int i = 0; i < len; i++)
{
cout <<arr[i] << " ";
}
cout << endl;
system("pause");
}
插入排序
#include<iostream>
using namespace std;
void InsertSort(int *arr, int len)
{
if (len < 2)
return;
for (int i = 0; i < len; i++)
{
int j = i - 1;
int key = arr[i];
while (j>-1 && arr[j]>key)
{
arr[j + 1] = arr[j];
--j;
}
arr[j + 1] = key;
}
}
int main()
{
int arr[] = { 2, 3, 1, 5, 12, 3, 7, 3, 9, 3, 0, 2 };
int len = sizeof(arr) / sizeof(arr[0]);
InsertSort(arr, len);
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
system("pause");
return 0;
}
堆排序
#include<iostream>
using namespace std;
class Heap_Sort
{
public:
void Sort(int *arr, int len)
{
_Build_Heap(arr, len);
while (len > 1)
{
swap(arr[0], arr[len - 1]);
len--;
_AdjustDown(arr,0,len);
}
}
private:
void _Build_Heap(int *arr, int len)
{
for (int i = ((len - 2) >> 1); i >= 0; i--)
{
_AdjustDown(arr, i,len);
}
}
void _AdjustDown(int *arr, int root,int size)
{
int parent = root;
int child = 2 * parent + 1;
while (child <size)
{
if (child < size&&arr[child] < arr[child + 1])
child += 1;
if (child < size&&arr[parent] < arr[child])
{
swap(arr[parent], arr[child]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
};
int main()
{
int arr[] = { 5, 3, 1, 7, 4, 0, 6, 8, 4, 7 };
int len = sizeof(arr) / sizeof(arr[0]);
Heap_Sort s;
s.Sort(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << " ";
cout << endl;
system("pause");
}
快速排序
#include<iostream>
using namespace std;
//普通法
int partion1(int *arr, int left, int right)
{
//快排若选用左边的为基准值,则指针应当从右边开始走
//反之若选右边的则应当从左边走
/*
如本例,若从左边开始走则
2, 1, 6, 3, 4, 5, 9, 5, 0
2 1 0* 3 4 5 9 5 *6
这时begin在3位置,end也会走到3位置,循环结束
交换arr[left]与arr[begin]
2 1 0 3 4 5 9 5 6
3 1 0 2 4 5 9 5 6
结果不对。
arr[end]>=key
arr[begin] <=key
必须都是大于等于或小于等于号,不能没有等号,
*/
int key = arr[left];
int begin = left;
int end = right-1;
while (begin < end)
{
while (begin<end&&arr[end]>=key)
--end;
while (begin < end&&arr[begin] <=key)
++begin;
if (begin < end)
swap(arr[begin], arr[end]);
}
swap(arr[begin], arr[left]);
return begin;
}
//挖坑法
int partion2(int *arr, int left, int right)
{
int key = arr[left];
int end = right - 1;
int begin = left;
while (begin < end)
{
while (begin<end&&arr[end]>=key)
--end;
arr[begin] = arr[end];
while (begin < end&&arr[begin] <= key)
++begin;
arr[end] = arr[begin];
}
arr[begin] = key;
return begin;
}
//极简双指针法
int partion3(int *arr, int left, int right)
{
int pCur = left;
int pPre = left - 1;
/*
例
2, 1, 6, 3, 4, 5, 9, 5, 4
2 1 3 *6 #4 5 9 5 4
2 1 3 *4 4 5 9 5 6
*/
while (pCur < right)
{
while (arr[pCur] < arr[right - 1] && ++pPre != pCur)
swap(arr[pCur], arr[pPre]);
pCur++;
}
swap(arr[++pPre], arr[right - 1]);
return pPre;
}
void qSort(int *arr,int left, int right)
{
if (right - left < 2)
return;
if (left < right)
{
int Boundary = partion3(arr, left, right);
qSort(arr, left, Boundary);
qSort(arr, Boundary+1, right);
}
}
int main()
{
int arr[] = { 2, 1, 6, 3, 4, 5, 9, 5, 0 };
int len = sizeof(arr) / sizeof(arr[0]);
qSort(arr, 0,len);
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
system("pause");
}
希尔排序
void ShellSort(int *a, int len) //插入排序的变形,通过预排序使得元素大致有序,再通过插入排序使得数组整体有序
{
int gap = len; //增量
while (gap > 1)
{
gap = gap / 3 + 1; //增量要减小,直到增减为1
for (int index = gap; index<len;++index)
{
int pos = index-gap; //有序区的最后一个元素
int tmp = a[index];
while (pos > 0 && a[pos] > tmp)
{
a[pos + gap] = a[pos];
pos -= gap;
}
a[pos + gap] = tmp;
}
}
}
select、poll、epoll的区别
select、poll、epoll这三组I/O复用系统调用都能同时监听多个文件描述符,他们都通过timeout参数指定要等待的时间。直到事件就绪时返回,返回值就是就绪的文件描述符的数量。
下面我们从事件集、最大支持文件描述符数量,工作模式和具体实现方面比较一下他们的异同:
1、事件集
select的参数没有将文件描述符和事件绑定,他仅仅是一个文件描述符的集合,所以select需要分别用三个参数来区分传入的可读,可写及异常事件,这不仅限制了select只能处理这三种事件,另外由于内核对fd_set集合的在线修改,所以下次再调用select之前还需要重置这3个文件描述符集合。
poll将文件描述符和事件都定义在pollfd结构体中,使得任何事件都能被统一处理,而且pollfd将监测事件和就绪事件分开了,保证events不被改变,因此pollfd不需要重置pllfd结构中的events成员。但是因为select和poll返回的都是整个事件集合,所以他们查找就绪事件的文件描述符的效率都是O(n)。
epoll在内核中维护了一个事件表,而且还提供一个函数epoll_ctl来向事件表中添加、删除、修改事件,所以它无须每次都重置事件。因为epoll返回的都是就绪事件,所以epoll查找就绪事件的文件描述符的时间复杂度都是O(1)。
2、最大支持的文件描述符数量
poll和epoll都能达到系统允许打开的文件描述符的最大值。
select允许监听的最大文件描述符数量通常有限制,虽然可以修改,但是不建议修改。
3、工作模式
select和poll都只能处在相对低效的LT模式,而epoll可以处于ET高效模式。
4、具体实现
select和poll采用的都是轮询的方式,每次都要扫描整个事件集合,才能找到就绪事件的文件描述符。而epoll采用的是callback(回调机制),只要内核检测到就绪事件,就触发回调机制,将就绪事件移到就绪队列中等待用户处理。
select、poll和epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,epoll是通过内核用于用户空间mmapp同一块内存实现的,所以epoll就减少了一些不必要的拷贝。
二叉树
二叉树的创建
二叉树的高度
二叉树某层节点的个数
二叉树的镜像
二叉树最远两个节点的距离
二叉树的前中后层序递归非递归遍历
判断二叉树是否是完全二叉树
二叉树叶子节点的个数
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
template<class T>
struct BinaryTreeNode
{
T _data;
BinaryTreeNode<T> *_pRight;
BinaryTreeNode<T> *_pLeft;
BinaryTreeNode(T data) : _data(data), _pRight(nullptr), _pLeft(nullptr)
{}
};
template<class T>
class BinaryTree
{
private:
typedef BinaryTreeNode<T> Node;
public:
BinaryTree() :_pRoot(nullptr)
{}
//创建二叉树
BinaryTree(const T *arr, const size_t size, const T invalid)
{
size_t index = 0;
_CreateTree(_pRoot, arr, size, index, invalid);
}
void PreOrder()
{
cout << "前序遍历递归版" << endl;
_PreOrder(_pRoot);
cout << endl;
}
void PreOrder_Nor()
{
cout << "前序遍历栈版" << endl;
_PreOrder_Nor(_pRoot);
cout << endl;
}
void PostOrder()
{
cout << "后续遍历递归版" << endl;
_PostOrder(_pRoot);
cout << endl;
}
void PostOrder_Nor()
{
cout << "后序遍历栈版" << endl;
_PostOrder_Nor(_pRoot);
cout << endl;
}
~BinaryTree()
{
_DestroyTree(_pRoot);
}
//判断是否是完全二叉树
bool IsCompleteBinaryTree()
{
return _IsCompleteBinaryTree(_pRoot);
}
//获取二叉树的镜像
void GetBinaryMirror()
{
return _GetBinaryMirror(_pRoot);
}
//获取二叉树的高度
size_t Height()
{
return _Height(_pRoot);
}
//得到二叉树叶子节点的个数
size_t GetLeefNode()
{
return _GetLeefNode(_pRoot);
}
//得到二叉树第K层的节点数目
size_t GetKLevelNode(size_t k)
{
cout << "树的第K层有多少节点" << endl;
return _GetKLevelNode(_pRoot, k);
}
//得到二叉树中距离最远的两个结点之间的距离
int GetFarthestDistance()
{
int distance = 0;
_GetFarthestDistance(_pRoot, distance);
return distance;
}
private:
//index记得给引用
void _CreateTree(Node *&pRoot, const T *arr, const size_t size, size_t &index, T invalid)
{
if ((index < size) && (arr[index] != invalid))
{
pRoot = new Node(arr[index]);
_CreateTree(pRoot->_pLeft, arr, size, ++index, invalid);
_CreateTree(pRoot->_pRight, arr, size, ++index, invalid);
}
}
void _PreOrder(Node *pRoot)
{
if (pRoot)
{
cout << pRoot->_data << " ";
_PreOrder(pRoot->_pLeft);
_PreOrder(pRoot->_pRight);
}
}
void _PreOrder_Nor(Node *pRoot)
{
stack<Node*> st;
Node *pCur = pRoot;
while (pCur || !st.empty())
{
while (pCur)
{
cout << pCur->_data << " ";
st.push(pCur);
pCur = pCur->_pLeft;
}
Node *pTop = st.top();
st.pop();
pCur = pTop->_pRight;
}
cout << endl;
}
void _PostOrder(Node *pRoot)
{
if (pRoot)
{
_PostOrder(pRoot->_pLeft);
_PostOrder(pRoot->_pRight);
cout << pRoot->_data << " ";
}
}
void _PostOrder_Nor(Node *pRoot)
{
stack<Node *> st;
Node *pCur = pRoot;
Node *pFlag = nullptr;
while (pCur || !st.empty())
{
while (pCur)
{
st.push(pCur);
pCur = pCur->_pLeft;
}
pCur = st.top();
if ((nullptr == pCur->_pRight) || (pFlag == pCur->_pRight))
{
st.pop();
cout << pCur->_data << " ";
pFlag = pCur;
pCur = nullptr;
}
else if (pCur->_pRight)
{
pCur = pCur->_pRight;
}
}
}
void _DestroyTree(Node *pRoot)
{
if (pRoot)
{
_DestroyTree(pRoot->_pLeft);
_DestroyTree(pRoot->_pRight);
delete pRoot;
pRoot = nullptr;
}
}
/*
1. 层序遍历找到第一个度不为2的节点,把flag设置为true
2. 若该节点只有左孩子没有右孩子继续遍历,若继续遍历的节点度不为0返回false
3. 若该节点只有右孩子没有左孩子返回false
4. 若栈为空返回true
*/
bool _IsCompleteBinaryTree(Node *pRoot)
{
queue<Node *> q;
q.push(pRoot);
if (NULL == pRoot->_pLeft&&NULL == pRoot->_pRight)
{
return true;
}
bool flag = false;
while (!q.empty())
{
Node *pTop = q.front();
if (flag && ((pTop->_pLeft) || (pTop->_pRight)))
return false;
if (pTop->_pLeft)
q.push(pTop->_pLeft);
if (pTop->_pRight && (NULL == pTop->_pLeft))
return false;
if (pTop->_pRight)
q.push(pTop->_pRight);
else
flag = true;
q.pop();
}
return true;
}
//找到二叉树中距离最远的两个节点
int _GetFarthestDistance(Node* pRoot, int& distance)
{
if (NULL == pRoot)
return 0;
int left = _GetFarthestDistance(pRoot->_pLeft,distance);
int right = _GetFarthestDistance(pRoot->_pRight, distance);
if (left + right > distance)
distance = left + right;
return left > right ? left + 1 : right + 1;
}
//得到二叉树的镜像
//层序或者前序后序遍历节点交换左右孩子
void _GetBinaryMirror(Node *pRoot)
{
queue<Node *> q;
q.push(pRoot);
while (!q.empty())
{
Node *pTop = q.front();
if (pTop)
{
swap(pTop->_pLeft, pTop->_pRight);
}
if (pTop->_pLeft)
q.push(pTop->_pLeft);
if (pTop->_pRight)
q.push(pTop->_pRight);
q.pop();
}
}
size_t _Height(Node *pRoot)
{
if (NULL == pRoot)
return 0;
size_t highLeft = 1 + _Height(pRoot->_pLeft);
size_t highRight = 1 + _Height(pRoot->_pRight);
return highLeft > highRight ? highLeft : highRight;
}
size_t _GetLeefNode(Node *pRoot)
{
if (pRoot == NULL)
return 0;
if (NULL == pRoot->_pLeft&&NULL == pRoot->_pRight)
return 1;
return _GetLeefNode(pRoot->_pLeft) + _GetLeefNode(pRoot->_pRight);
}
size_t _GetKLevelNode(Node *pRoot, size_t k)
{
if (k<1 || k>_Height(pRoot) || NULL == pRoot)
return 0;
if (k == 1 || NULL == pRoot->_pLeft || NULL == pRoot->_pRight)
return 1;
return _GetKLevelNode(pRoot->_pRight, k - 1) + _GetKLevelNode(pRoot->_pLeft, k - 1);
}
private:
Node *_pRoot;
};
void test()
{
char arr[] = { '1', '2', '4', '#', '#', '#', '3', '5', '#', '#', '6' };
char arr2[] = { '1', '2', '4', '#', '#', '9', '#', '#', '3', '5', '#', '#', '6' };
size_t sz = sizeof(arr) / sizeof(arr[0]);
BinaryTree<char> b(arr, sz, '#');
size_t sz2 = sizeof(arr2) / sizeof(arr2[0]);
BinaryTree<char> w(arr2, sz2, '#');
cout << b.GetFarthestDistance() << endl;
b.PreOrder();
cout << "得到镜像" << endl;
b.GetBinaryMirror();
b.PreOrder_Nor();
b.PostOrder();
b.PostOrder_Nor();
cout << w.GetKLevelNode(3) << endl;
cout << "b是否是完全二叉树" << endl << b.IsCompleteBinaryTree() << endl;
w.PostOrder_Nor();
cout << "w的距离最大" << endl;
cout << w.GetFarthestDistance() << endl;
cout << "树的高度是:" << endl << b.Height() << endl;
cout << "w是否是完全二叉树" << endl << w.IsCompleteBinaryTree() << endl;
system("pause");
}
int main()
{
test();
system("pause");
}
重建二叉树
void CreatSubTree(BinaryTreeNode<int>* &root,
int* InOrder,
int *PrevOrder,
int len)
{
if (len<=0)
return;
root= new BinaryTreeNode<int>(PrevOrder[0]);
int index = 0; //父节点在数组中的下标
for (; index < len; ++index)
{
if (PrevOrder[0] == InOrder[index])
break;
}
int subTreeL =index; //左子树结点个数
int subTreeR = len - index - 1; //右子树结点个数
CreatSubTree(root->_left, InOrder, PrevOrder + 1, subTreeL);
CreatSubTree(root->_right,InOrder + index + 1, PrevOrder + index + 1, subTreeR);
}
BinaryTreeNode<int>* RebuildBinaryTree(int *InOrder, int *PrevOrder, int len)
{
assert(InOrder);
assert(PrevOrder);
BinaryTreeNode<int>* root;
CreatSubTree(root, InOrder, PrevOrder,len);
return root;
}
公共祖先
void _GetAncestor(BinaryTreeNode<int>* root,
BinaryTreeNode<int>* node,
vector<BinaryTreeNode<int>* >& v,int &flag)
{
if (root == NULL||flag==1)
return;
_GetAncestor(root->_left,node,v,flag);
_GetAncestor(root->_right,node,v,flag);
if (root == node || flag == 1)
{
v.push_back(root);
flag = 1;
}
}
BinaryTreeNode<int>* GetAncestor(BinaryTreeNode<int>* root,
BinaryTreeNode<int>* node1,
BinaryTreeNode<int>* node2)
{
if (root == NULL || node1 == NULL || node2 == NULL)
return NULL;
vector<BinaryTreeNode<int>*> v1; //保存从node1到root的路径
vector<BinaryTreeNode<int>*> v2; //保存node2到root的路径
int flag = 0;
_GetAncestor(root,node1,v1,flag);
flag = 0;
_GetAncestor(root, node2, v2, flag);
vector<BinaryTreeNode<int>*>::reverse_iterator rv1 = v1.rbegin();
vector<BinaryTreeNode<int>*>::reverse_iterator rv2 = v2.rbegin();
while ((rv1!=v1.rend())&&(rv2!=v2.rend()))
{
if (*rv1 == *rv2)
{
rv1++;
rv2++;
}
else
{
if (rv1!=v1.rbegin())
--rv1;
return *rv1;
}
}
if (rv1 == v1.rend() && rv2 != v2.rend())
return node1;
if (rv1 != v1.rend() && rv2 == v2.rend())
return node2;
return NULL;
}