常见面试代码总结

来源:互联网 发布:万网域名后台 编辑:程序博客网 时间:2024/06/05 18:36

排序

归并排序

#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        这时begin3位置,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;  }