常见面试代码总结
排序
歸并排序
#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++];elsetemp[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;}elsebreak;}} }; 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, 02 1 0* 3 4 5 9 5 *6這時begin在3位置,end也會走到3位置,循環結束交換arr[left]與arr[begin]2 1 0 3 4 5 9 5 63 1 0 2 4 5 9 5 6結果不對。arr[end]>=keyarr[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, 42 1 3 *6 #4 5 9 5 42 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設置為true2. 若該節點只有左孩子沒有右孩子繼續遍歷,若繼續遍歷的節點度不為0返回false3. 若該節點只有右孩子沒有左孩子返回false4. 若棧為空返回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);elseflag = 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
總結
- 上一篇: D3DPOOL(资源池)
- 下一篇: 【互联网安全】DDoS攻防原理及实战