常见面试代码总结

排序

归并排序

#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;  
}  

转载于:https://www.cnblogs.com/readlearn/p/10806407.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值