├── .gitignore ├── Algorithm ├── BSTSearch.h ├── BinarySearch.h ├── BubbleSort.h ├── BucketSort.cpp ├── CountSort.cpp ├── FibonacciSearch.cpp ├── HeapSort.cpp ├── InsertSort.h ├── InsertionSearch.h ├── MergeSort.h ├── QuickSort.h ├── RadixSort.h ├── SelectionSort.h ├── SequentialSearch.h └── ShellSort.h ├── DataStructure ├── BinaryTree.cpp ├── HashTable.cpp ├── LinkList.cpp ├── LinkList_with_head.cpp ├── RedBlackTree.cpp ├── SqList.cpp └── SqStack.cpp ├── DesignPattern ├── AbstractFactoryPattern │ ├── Factory.cpp │ ├── Factory.h │ ├── FactoryMain.cpp │ ├── FactoryMain.h │ ├── concrete_factory.h │ ├── concrete_product.h │ └── product.h ├── AdapterPattern │ ├── AdapterMain.h │ ├── adaptee.h │ ├── adapter.h │ └── target.h ├── BridgePattern │ ├── BridgeMain.cpp │ ├── BridgeMain.h │ ├── abstraction.h │ ├── concrete_implementor.h │ ├── implementor.h │ └── refined_abstraction.h ├── CMakeLists.txt ├── ObserverPattern │ ├── ObserverMain.cpp │ ├── ObserverMain.h │ ├── concrete_observer.h │ ├── concrete_subject.h │ ├── observer.h │ └── subject.h ├── README.md ├── SingletonPattern │ ├── README.md │ ├── Singleton.cpp │ ├── Singleton.h │ └── SingletonMain.h └── main.cpp ├── LICENSE ├── Problems ├── ChessboardCoverageProblem │ ├── ChessboardCoverage.cpp │ ├── ChessboardCoverage.exe │ └── README.md ├── KnapsackProblem │ ├── README.md │ ├── pack.cpp │ └── pack.exe ├── NeumannNeighborProblem │ ├── Formula │ │ ├── Neumann2_3_12.cpp │ │ ├── Neumann2_3_12.exe │ │ └── README.md │ ├── README.md │ └── Recursive │ │ ├── Neumann2_4_12.cpp │ │ ├── Neumann2_4_12.exe │ │ └── README.md ├── RoundRobinProblem │ ├── MatchTable.cpp │ ├── MatchTable.exe │ └── README.md └── TubingProblem │ ├── README.md │ ├── Tubing.cpp │ └── Tubing.exe ├── README.md ├── README_en.md ├── STL ├── README.md └── STL.md ├── docs ├── .nojekyll ├── CNAME ├── README.md ├── _navbar.md ├── en.md └── index.html └── images ├── CPU-Big-Endian.svg.png ├── CPU-Little-Endian.svg.png ├── CirLinkList.png ├── DuLinkList.png ├── GeneralizedList1.png ├── GeneralizedList2.png ├── GoogleCppStyleGuide.png ├── HashTable.png ├── ICMP报文格式.png ├── IP数据报格式.png ├── ISOOSI七层网络模型.png ├── LinkBinaryTree.png ├── LinkList.png ├── LinkQueue.png ├── Self-balancingBinarySearchTree.png ├── SqBinaryTree.png ├── SqList.png ├── SqLoopStack.png ├── SqQueue.png ├── SqStack.png ├── TCP-transport-connection-management.png ├── TCPIP协议四层模型.png ├── TCP三次握手建立连接.png ├── TCP四次挥手释放连接.png ├── TCP报文.png ├── TCP拥塞窗口cwnd在拥塞控制时的变化情况.png ├── TCP的拥塞控制流程图.png ├── TCP的有限状态机.png ├── TCP首部.png ├── TOC预览.png ├── UDP报文.png ├── UDP首部.png ├── WindowsFreeLibrary.png ├── WindowsLoadLibrary.png ├── socket客户端服务器通讯.jpg ├── 利用可变窗口进行流量控制举例.png ├── 快重传示意图.png ├── 打印预览.png ├── 计算机网络体系结构.png └── 面向对象基本特征.png /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.txt 3 | *.bat -------------------------------------------------------------------------------- /Algorithm/BSTSearch.h: -------------------------------------------------------------------------------- 1 | /* 2 | 二叉搜索树的查找算法: 3 | 4 | 在二叉搜索树b中查找x的过程为: 5 | 6 | 1. 若b是空树,则搜索失败,否则: 7 | 2. 若x等于b的根节点的数据域之值,则查找成功;否则: 8 | 3. 若x小于b的根节点的数据域之值,则搜索左子树;否则: 9 | 4. 查找右子树。 10 | 11 | */ 12 | 13 | // 在根指针T所指二叉查找树中递归地查找其关键字等于key的数据元素,若查找成功, 14 | // 则指针p指向該数据元素节点,并返回TRUE,否则指针指向查找路径上访问的最终 15 | // 一个节点并返回FALSE,指针f指向T的双亲,其初始调用值为NULL 16 | Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p){ 17 | 18 | if(!T) { //查找不成功 19 | p=f; 20 | return false; 21 | } 22 | else if (key == T->data.key) { //查找成功 23 | p=T; 24 | return true; 25 | } 26 | else if (key < T->data.key) //在左子树中继续查找 27 | return SearchBST(T->lchild, key, T, p); 28 | else //在右子树中继续查找 29 | return SearchBST(T->rchild, key, T, p); 30 | } -------------------------------------------------------------------------------- /Algorithm/BinarySearch.h: -------------------------------------------------------------------------------- 1 | // 二分查找(折半查找):对于已排序,若无序,需要先排序 2 | 3 | // 非递归 4 | 5 | int BinarySearch(vector v, int value , int low, int high) { 6 | if (v.size() <= 0) { 7 | return -1; 8 | } 9 | while (low <= high) { 10 | int mid = low + (high - low) / 2; 11 | if (v[mid] == value) { 12 | return mid; 13 | } 14 | else if (v[mid] > value) { 15 | high = mid - 1; 16 | } 17 | else { 18 | low = mid + 1; 19 | } 20 | } 21 | 22 | return -1; 23 | } 24 | 25 | // 递归 26 | int BinarySearch2(vector v, int value, int low, int high) 27 | { 28 | if (low > high) 29 | return -1; 30 | int mid = low + (high - low) / 2; 31 | if (v[mid] == value) 32 | return mid; 33 | else if (v[mid] > value) 34 | return BinarySearch2(v, value, low, mid - 1); 35 | else 36 | return BinarySearch2(v, value, mid + 1, high); 37 | } 38 | -------------------------------------------------------------------------------- /Algorithm/BubbleSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | (无序区,有序区)。从无序区通过交换找出最大元素放到有序区前端。 4 | 5 | 选择排序思路: 6 | 1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 7 | 2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。 8 | 3. 针对所有的元素重复以上的步骤,除了最后一个。 9 | 4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 10 | 11 | */ 12 | 13 | // 冒泡排序 14 | void BubbleSort(vector& v) { 15 | int len = v.size(); 16 | for (int i = 0; i < len - 1; ++i) 17 | for (int j = 0; j < len - 1 - i; ++j) 18 | if (v[j] > v[j + 1]) 19 | swap(v[j], v[j + 1]); 20 | } 21 | 22 | // 模板实现冒泡排序 23 | template //整數或浮點數皆可使用,若要使用物件(class)時必須設定大於(>)的運算子功能 24 | void bubble_sort(T arr[], int len) { 25 | for (int i = 0; i < len - 1; i++) 26 | for (int j = 0; j < len - 1 - i; j++) 27 | if (arr[j] > arr[j + 1]) 28 | swap(arr[j], arr[j + 1]); 29 | } 30 | 31 | // 冒泡排序(改进版) 32 | void BubbleSort_orderly(vector& v) { 33 | int len = v.size(); 34 | bool orderly = false; 35 | for (int i = 0; i < len - 1 && !orderly; ++i) { 36 | orderly = true; 37 | for (int j = 0; j < len - 1 - i; ++j) { 38 | if (v[j] > v[j + 1]) { // 从小到大 39 | orderly = false; // 发生交换则仍非有序 40 | swap(v[j], v[j + 1]); 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Algorithm/BucketSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using std::vector; 5 | 6 | /***************** 7 | 8 | 桶排序:将值为i的元素放入i号桶,最后依次把桶里的元素倒出来。 9 | 10 | 桶排序序思路: 11 | 1. 设置一个定量的数组当作空桶子。 12 | 2. 寻访序列,并且把项目一个一个放到对应的桶子去。 13 | 3. 对每个不是空的桶子进行排序。 14 | 4. 从不是空的桶子里把项目再放回原来的序列中。 15 | 16 | 假设数据分布在[0,100)之间,每个桶内部用链表表示,在数据入桶的同时插入排序,然后把各个桶中的数据合并。 17 | 18 | *****************/ 19 | 20 | 21 | const int BUCKET_NUM = 10; 22 | 23 | struct ListNode{ 24 | explicit ListNode(int i=0):mData(i),mNext(NULL){} 25 | ListNode* mNext; 26 | int mData; 27 | }; 28 | 29 | ListNode* insert(ListNode* head,int val){ 30 | ListNode dummyNode; 31 | ListNode *newNode = new ListNode(val); 32 | ListNode *pre,*curr; 33 | dummyNode.mNext = head; 34 | pre = &dummyNode; 35 | curr = head; 36 | while(NULL!=curr && curr->mData<=val){ 37 | pre = curr; 38 | curr = curr->mNext; 39 | } 40 | newNode->mNext = curr; 41 | pre->mNext = newNode; 42 | return dummyNode.mNext; 43 | } 44 | 45 | 46 | ListNode* Merge(ListNode *head1,ListNode *head2){ 47 | ListNode dummyNode; 48 | ListNode *dummy = &dummyNode; 49 | while(NULL!=head1 && NULL!=head2){ 50 | if(head1->mData <= head2->mData){ 51 | dummy->mNext = head1; 52 | head1 = head1->mNext; 53 | }else{ 54 | dummy->mNext = head2; 55 | head2 = head2->mNext; 56 | } 57 | dummy = dummy->mNext; 58 | } 59 | if(NULL!=head1) dummy->mNext = head1; 60 | if(NULL!=head2) dummy->mNext = head2; 61 | 62 | return dummyNode.mNext; 63 | } 64 | 65 | void BucketSort(int n,int arr[]){ 66 | vector buckets(BUCKET_NUM,(ListNode*)(0)); 67 | for(int i=0;imData; 78 | head = head->mNext; 79 | } 80 | } -------------------------------------------------------------------------------- /Algorithm/CountSort.cpp: -------------------------------------------------------------------------------- 1 | /***************** 2 | 3 | 计数排序:统计小于等于该元素值的元素的个数i,于是该元素就放在目标数组的索引i位(i≥0)。 4 | 5 | 计数排序基于一个假设,待排序数列的所有数均为整数,且出现在(0,k)的区间之内。 6 | 如果 k(待排数组的最大值) 过大则会引起较大的空间复杂度,一般是用来排序 0 到 100 之间的数字的最好的算法,但是它不适合按字母顺序排序人名。 7 | 计数排序不是比较排序,排序的速度快于任何比较排序算法。 8 | 时间复杂度为 O(n+k),空间复杂度为 O(n+k) 9 | 10 | 算法的步骤如下: 11 | 12 | 1. 找出待排序的数组中最大和最小的元素 13 | 2. 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项 14 | 3. 对所有的计数累加(从 C 中的第一个元素开始,每一项和前一项相加) 15 | 4. 反向填充目标数组:将每个元素 i 放在新数组的第 C[i] 项,每放一个元素就将 C[i] 减去 1 16 | 17 | *****************/ 18 | 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace std; 25 | 26 | // 计数排序 27 | void CountSort(vector& vecRaw, vector& vecObj) 28 | { 29 | // 确保待排序容器非空 30 | if (vecRaw.size() == 0) 31 | return; 32 | 33 | // 使用 vecRaw 的最大值 + 1 作为计数容器 countVec 的大小 34 | int vecCountLength = (*max_element(begin(vecRaw), end(vecRaw))) + 1; 35 | vector vecCount(vecCountLength, 0); 36 | 37 | // 统计每个键值出现的次数 38 | for (int i = 0; i < vecRaw.size(); i++) 39 | vecCount[vecRaw[i]]++; 40 | 41 | // 后面的键值出现的位置为前面所有键值出现的次数之和 42 | for (int i = 1; i < vecCountLength; i++) 43 | vecCount[i] += vecCount[i - 1]; 44 | 45 | // 将键值放到目标位置 46 | for (int i = vecRaw.size(); i > 0; i--) // 此处逆序是为了保持相同键值的稳定性 47 | vecObj[--vecCount[vecRaw[i - 1]]] = vecRaw[i - 1]; 48 | } 49 | 50 | int main() 51 | { 52 | vector vecRaw = { 0,5,7,9,6,3,4,5,2,8,6,9,2,1 }; 53 | vector vecObj(vecRaw.size(), 0); 54 | 55 | CountSort(vecRaw, vecObj); 56 | 57 | for (int i = 0; i < vecObj.size(); ++i) 58 | cout << vecObj[i] << " "; 59 | cout << endl; 60 | 61 | return 0; 62 | } -------------------------------------------------------------------------------- /Algorithm/FibonacciSearch.cpp: -------------------------------------------------------------------------------- 1 | // 斐波那契查找 2 | 3 | #include "stdafx.h" 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int max_size=20;//斐波那契数组的长度 9 | 10 | /*构造一个斐波那契数组*/ 11 | void Fibonacci(int * F) 12 | { 13 | F[0]=0; 14 | F[1]=1; 15 | for(int i=2;iF[k]-1)//计算n位于斐波那契数列的位置 30 | ++k; 31 | 32 | int * temp;//将数组a扩展到F[k]-1的长度 33 | temp=new int [F[k]-1]; 34 | memcpy(temp,a,n*sizeof(int)); 35 | 36 | for(int i=n;itemp[mid]) 48 | { 49 | low=mid+1; 50 | k-=2; 51 | } 52 | else 53 | { 54 | if(mid=n则说明是扩展的数值,返回n-1 58 | } 59 | } 60 | delete [] temp; 61 | return -1; 62 | } 63 | 64 | int main() 65 | { 66 | int a[] = {0,16,24,35,47,59,62,73,88,99}; 67 | int key=100; 68 | int index=FibonacciSearch(a,sizeof(a)/sizeof(int),key); 69 | cout< 2 | #include 3 | using namespace std; 4 | 5 | // 堆排序:(最大堆,有序区)。从堆顶把根卸出来放在有序区之前,再恢复堆。 6 | 7 | void max_heapify(int arr[], int start, int end) { 8 | //建立父節點指標和子節點指標 9 | int dad = start; 10 | int son = dad * 2 + 1; 11 | while (son <= end) { //若子節點指標在範圍內才做比較 12 | if (son + 1 <= end && arr[son] < arr[son + 1]) //先比較兩個子節點大小,選擇最大的 13 | son++; 14 | if (arr[dad] > arr[son]) //如果父節點大於子節點代表調整完畢,直接跳出函數 15 | return; 16 | else { //否則交換父子內容再繼續子節點和孫節點比較 17 | swap(arr[dad], arr[son]); 18 | dad = son; 19 | son = dad * 2 + 1; 20 | } 21 | } 22 | } 23 | 24 | void heap_sort(int arr[], int len) { 25 | //初始化,i從最後一個父節點開始調整 26 | for (int i = len / 2 - 1; i >= 0; i--) 27 | max_heapify(arr, i, len - 1); 28 | //先將第一個元素和已经排好的元素前一位做交換,再從新調整(刚调整的元素之前的元素),直到排序完畢 29 | for (int i = len - 1; i > 0; i--) { 30 | swap(arr[0], arr[i]); 31 | max_heapify(arr, 0, i - 1); 32 | } 33 | } 34 | 35 | int main() { 36 | int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 }; 37 | int len = (int) sizeof(arr) / sizeof(*arr); 38 | heap_sort(arr, len); 39 | for (int i = 0; i < len; i++) 40 | cout << arr[i] << ' '; 41 | cout << endl; 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Algorithm/InsertSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | (有序区,无序区)。把无序区的第一个元素插入到有序区的合适的位置。对数组:比较得少,换得多。 4 | 5 | 插入排序思路: 6 | 1. 从第一个元素开始,该元素可以认为已经被排序 7 | 2. 取出下一个元素,在已经排序的元素序列中从后向前扫描 8 | 3. 如果该元素(已排序)大于新元素,将该元素移到下一位置 9 | 4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置 10 | 5. 将新元素插入到该位置后 11 | 6. 重复步骤2~5 12 | 13 | */ 14 | 15 | // 插入排序 16 | void InsertSort(vector& v) 17 | { 18 | int len = v.size(); 19 | for (int i = 1; i < len; ++i) { 20 | int temp = v[i]; 21 | for(int j = i - 1; j >= 0; --j) 22 | { 23 | if(v[j] > temp) 24 | { 25 | v[j + 1] = v[j]; 26 | v[j] = temp; 27 | } 28 | else 29 | break; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Algorithm/InsertionSearch.h: -------------------------------------------------------------------------------- 1 | //插值查找 2 | int InsertionSearch(int a[], int value, int low, int high) 3 | { 4 | int mid = low+(value-a[low])/(a[high]-a[low])*(high-low); 5 | if(a[mid]==value) 6 | return mid; 7 | if(a[mid]>value) 8 | return InsertionSearch(a, value, low, mid-1); 9 | if(a[mid] 9 | void merge_sort(T arr[], int len) { 10 | T* a = arr; 11 | T* b = new T[len]; 12 | for (int seg = 1; seg < len; seg += seg) { 13 | for (int start = 0; start < len; start += seg + seg) { 14 | int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len); 15 | int k = low; 16 | int start1 = low, end1 = mid; 17 | int start2 = mid, end2 = high; 18 | while (start1 < end1 && start2 < end2) 19 | b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++]; 20 | while (start1 < end1) 21 | b[k++] = a[start1++]; 22 | while (start2 < end2) 23 | b[k++] = a[start2++]; 24 | } 25 | T* temp = a; 26 | a = b; 27 | b = temp; 28 | } 29 | if (a != arr) { 30 | for (int i = 0; i < len; i++) 31 | b[i] = a[i]; 32 | b = a; 33 | } 34 | delete[] b; 35 | } 36 | 37 | /***************** 38 | 递归版 39 | *****************/ 40 | template 41 | void merge_sort_recursive(T arr[], T reg[], int start, int end) { 42 | if (start >= end) 43 | return; 44 | int len = end - start, mid = (len >> 1) + start; 45 | int start1 = start, end1 = mid; 46 | int start2 = mid + 1, end2 = end; 47 | merge_sort_recursive(arr, reg, start1, end1); 48 | merge_sort_recursive(arr, reg, start2, end2); 49 | int k = start; 50 | while (start1 <= end1 && start2 <= end2) 51 | reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++]; 52 | while (start1 <= end1) 53 | reg[k++] = arr[start1++]; 54 | while (start2 <= end2) 55 | reg[k++] = arr[start2++]; 56 | for (k = start; k <= end; k++) 57 | arr[k] = reg[k]; 58 | } 59 | //整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)的運算子功能 60 | template 61 | void merge_sort(T arr[], const int len) { 62 | T *reg = new T[len]; 63 | merge_sort_recursive(arr, reg, 0, len - 1); 64 | delete[] reg; 65 | } -------------------------------------------------------------------------------- /Algorithm/QuickSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | (小数,基准元素,大数)。在区间中随机挑选一个元素作基准,将小于基准的元素放在基准之前,大于基准的元素放在基准之后,再分别对小数区与大数区进行排序。 4 | 5 | 快速排序思路: 6 | 1. 选取第一个数为基准 7 | 2. 将比基准小的数交换到前面,比基准大的数交换到后面 8 | 3. 对左右区间重复第二步,直到各区间只有一个数 9 | 10 | */ 11 | 12 | // ---------------------------------------------------- 13 | 14 | // 快速排序(递归) 15 | void QuickSort(vector& v, int low, int high) { 16 | if (low >= high) // 结束标志 17 | return; 18 | int first = low; // 低位下标 19 | int last = high; // 高位下标 20 | int key = v[first]; // 设第一个为基准 21 | 22 | while (first < last) 23 | { 24 | // 将比第一个小的移到前面 25 | while (first < last && v[last] >= key) 26 | last--; 27 | if (first < last) 28 | v[first++] = v[last]; 29 | 30 | // 将比第一个大的移到后面 31 | while (first < last && v[first] <= key) 32 | first++; 33 | if (first < last) 34 | v[last--] = v[first]; 35 | } 36 | // 基准置位 37 | v[first] = key; 38 | // 前半递归 39 | QuickSort(v, low, first - 1); 40 | // 后半递归 41 | QuickSort(v, first + 1, high); 42 | } 43 | 44 | // ---------------------------------------------------- 45 | 46 | // 模板实现快速排序(递归) 47 | template 48 | void quick_sort_recursive(T arr[], int start, int end) { 49 | if (start >= end) 50 | return; 51 | T mid = arr[end]; 52 | int left = start, right = end - 1; 53 | while (left < right) { 54 | while (arr[left] < mid && left < right) 55 | left++; 56 | while (arr[right] >= mid && left < right) 57 | right--; 58 | std::swap(arr[left], arr[right]); 59 | } 60 | if (arr[left] >= arr[end]) 61 | std::swap(arr[left], arr[end]); 62 | else 63 | left++; 64 | quick_sort_recursive(arr, start, left - 1); 65 | quick_sort_recursive(arr, left + 1, end); 66 | } 67 | template //整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能 68 | void quick_sort(T arr[], int len) { 69 | quick_sort_recursive(arr, 0, len - 1); 70 | } 71 | 72 | // ---------------------------------------------------- 73 | 74 | // 模板实现快速排序(迭代) 75 | struct Range { 76 | int start, end; 77 | Range(int s = 0, int e = 0) { 78 | start = s, end = e; 79 | } 80 | }; 81 | template // 整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能 82 | void quick_sort(T arr[], const int len) { 83 | if (len <= 0) 84 | return; // 避免len等於負值時宣告堆疊陣列當機 85 | // r[]模擬堆疊,p為數量,r[p++]為push,r[--p]為pop且取得元素 86 | Range r[len]; 87 | int p = 0; 88 | r[p++] = Range(0, len - 1); 89 | while (p) { 90 | Range range = r[--p]; 91 | if (range.start >= range.end) 92 | continue; 93 | T mid = arr[range.end]; 94 | int left = range.start, right = range.end - 1; 95 | while (left < right) { 96 | while (arr[left] < mid && left < right) left++; 97 | while (arr[right] >= mid && left < right) right--; 98 | std::swap(arr[left], arr[right]); 99 | } 100 | if (arr[left] >= arr[range.end]) 101 | std::swap(arr[left], arr[range.end]); 102 | else 103 | left++; 104 | r[p++] = Range(range.start, left - 1); 105 | r[p++] = Range(left + 1, range.end); 106 | } 107 | } -------------------------------------------------------------------------------- /Algorithm/RadixSort.h: -------------------------------------------------------------------------------- 1 | // 基数排序:一种多关键字的排序算法,可用桶排序实现。 2 | 3 | int maxbit(int data[], int n) //辅助函数,求数据的最大位数 4 | { 5 | int maxData = data[0]; ///< 最大数 6 | /// 先求出最大数,再求其位数,这样有原先依次每个数判断其位数,稍微优化点。 7 | for (int i = 1; i < n; ++i) 8 | { 9 | if (maxData < data[i]) 10 | maxData = data[i]; 11 | } 12 | int d = 1; 13 | int p = 10; 14 | while (maxData >= p) 15 | { 16 | //p *= 10; // Maybe overflow 17 | maxData /= 10; 18 | ++d; 19 | } 20 | return d; 21 | /* int d = 1; //保存最大的位数 22 | int p = 10; 23 | for(int i = 0; i < n; ++i) 24 | { 25 | while(data[i] >= p) 26 | { 27 | p *= 10; 28 | ++d; 29 | } 30 | } 31 | return d;*/ 32 | } 33 | void radixsort(int data[], int n) //基数排序 34 | { 35 | int d = maxbit(data, n); 36 | int *tmp = new int[n]; 37 | int *count = new int[10]; //计数器 38 | int i, j, k; 39 | int radix = 1; 40 | for(i = 1; i <= d; i++) //进行d次排序 41 | { 42 | for(j = 0; j < 10; j++) 43 | count[j] = 0; //每次分配前清空计数器 44 | for(j = 0; j < n; j++) 45 | { 46 | k = (data[j] / radix) % 10; //统计每个桶中的记录数 47 | count[k]++; 48 | } 49 | for(j = 1; j < 10; j++) 50 | count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶 51 | for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中 52 | { 53 | k = (data[j] / radix) % 10; 54 | tmp[count[k] - 1] = data[j]; 55 | count[k]--; 56 | } 57 | for(j = 0; j < n; j++) //将临时数组的内容复制到data中 58 | data[j] = tmp[j]; 59 | radix = radix * 10; 60 | } 61 | delete []tmp; 62 | delete []count; 63 | } -------------------------------------------------------------------------------- /Algorithm/SelectionSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | (有序区,无序区)。在无序区里找一个最小的元素跟在有序区的后面。对数组:比较得多,换得少。 4 | 5 | 选择排序思路: 6 | 1. 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置 7 | 2. 从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾 8 | 3. 以此类推,直到所有元素均排序完毕 9 | 10 | */ 11 | 12 | // 选择排序 13 | void SelectionSort(vector& v) { 14 | int min, len = v.size(); 15 | for (int i = 0; i < len - 1; ++i) { 16 | min = i; 17 | for (int j = i + 1; j < len; ++j) { 18 | if (v[j] < v[min]) { // 标记最小的 19 | min = j; 20 | } 21 | } 22 | if (i != min) // 交换到前面 23 | swap(v[i], v[min]); 24 | } 25 | } 26 | 27 | // 模板实现 28 | template 29 | void Selection_Sort(std::vector& arr) { 30 | int len = arr.size(); 31 | for (int i = 0; i < len - 1; i++) { 32 | int min = i; 33 | for (int j = i + 1; j < len; j++) 34 | if (arr[j] < arr[min]) 35 | min = j; 36 | if(i != min) 37 | std::swap(arr[i], arr[min]); 38 | } 39 | } -------------------------------------------------------------------------------- /Algorithm/SequentialSearch.h: -------------------------------------------------------------------------------- 1 | // 顺序查找 2 | int SequentialSearch(vector& v, int k) { 3 | for (int i = 0; i < v.size(); ++i) 4 | if (v[i] == k) 5 | return i; 6 | return -1; 7 | } 8 | 9 | 10 | /* The following is a Sentinel Search Algorithm which only performs 11 | just one test in each loop iteration thereby reducing time complexity */ 12 | 13 | int BetterSequentialSearch(vector& v, int k) { 14 | int last = v[v.size()-1]; 15 | v[v.size()-1] = k; 16 | int i = 0; 17 | while (v[i]!= k) 18 | i++; 19 | v[v.size()-1] = last; 20 | if(i < v.size()-1 || v[v.size()-1] == k) 21 | return i; 22 | return -1; 23 | } -------------------------------------------------------------------------------- /Algorithm/ShellSort.h: -------------------------------------------------------------------------------- 1 | // 希尔排序:每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1。 2 | template 3 | void shell_sort(T array[], int length) { 4 | int h = 1; 5 | while (h < length / 3) { 6 | h = 3 * h + 1; 7 | } 8 | while (h >= 1) { 9 | for (int i = h; i < length; i++) { 10 | for (int j = i; j >= h && array[j] < array[j - h]; j -= h) { 11 | std::swap(array[j], array[j - h]); 12 | } 13 | } 14 | h = h / 3; 15 | } 16 | } -------------------------------------------------------------------------------- /DataStructure/BinaryTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define TRUE 1 5 | #define FALSE 0 6 | #define OK 1 7 | #define ERROR 0 8 | #define OVERFLOW -1 9 | #define SUCCESS 1 10 | #define UNSUCCESS 0 11 | #define dataNum 5 12 | int i = 0; 13 | int dep = 0; 14 | char data[dataNum] = { 'A', 'B', 'C', 'D', 'E' }; 15 | 16 | typedef int Status; 17 | typedef char TElemType; 18 | 19 | // 二叉树结构 20 | typedef struct BiTNode 21 | { 22 | TElemType data; 23 | struct BiTNode *lchild, *rchild; 24 | }BiTNode, *BiTree; 25 | 26 | // 初始化一个空树 27 | void InitBiTree(BiTree &T) 28 | { 29 | T = NULL; 30 | } 31 | 32 | // 构建二叉树 33 | BiTree MakeBiTree(TElemType e, BiTree L, BiTree R) 34 | { 35 | BiTree t; 36 | t = (BiTree)malloc(sizeof(BiTNode)); 37 | if (NULL == t) return NULL; 38 | t->data = e; 39 | t->lchild = L; 40 | t->rchild = R; 41 | return t; 42 | } 43 | 44 | // 访问结点 45 | Status visit(TElemType e) 46 | { 47 | printf("%c", e); 48 | return OK; 49 | } 50 | 51 | // 对二叉树T求叶子结点数目 52 | int Leaves(BiTree T) 53 | { 54 | int l = 0, r = 0; 55 | if (NULL == T) return 0; 56 | if (NULL == T->lchild && NULL == T->rchild) return 1; 57 | 58 | // 求左子树叶子数目 59 | l = Leaves(T->lchild); 60 | // 求右子树叶子数目 61 | r = Leaves(T->rchild); 62 | // 组合 63 | return r + l; 64 | } 65 | 66 | // 层次遍历:dep是个全局变量,高度 67 | int depTraverse(BiTree T) 68 | { 69 | if (NULL == T) return ERROR; 70 | 71 | dep = (depTraverse(T->lchild) > depTraverse(T->rchild)) ? depTraverse(T->lchild) : depTraverse(T->rchild); 72 | 73 | return dep + 1; 74 | } 75 | 76 | // 高度遍历:lev是局部变量,层次 77 | void levTraverse(BiTree T, Status(*visit)(TElemType e), int lev) 78 | { 79 | if (NULL == T) return; 80 | visit(T->data); 81 | printf("的层次是%d\n", lev); 82 | 83 | levTraverse(T->lchild, visit, ++lev); 84 | levTraverse(T->rchild, visit, lev); 85 | } 86 | 87 | // num是个全局变量 88 | void InOrderTraverse(BiTree T, Status(*visit)(TElemType e), int &num) 89 | { 90 | if (NULL == T) return; 91 | visit(T->data); 92 | if (NULL == T->lchild && NULL == T->rchild) { printf("是叶子结点"); num++; } 93 | else printf("不是叶子结点"); 94 | printf("\n"); 95 | InOrderTraverse(T->lchild, visit, num); 96 | InOrderTraverse(T->rchild, visit, num); 97 | } 98 | 99 | // 二叉树判空 100 | Status BiTreeEmpty(BiTree T) 101 | { 102 | if (NULL == T) return TRUE; 103 | return FALSE; 104 | } 105 | 106 | // 打断二叉树:置空二叉树的左右子树 107 | Status BreakBiTree(BiTree &T, BiTree &L, BiTree &R) 108 | { 109 | if (NULL == T) return ERROR; 110 | L = T->lchild; 111 | R = T->rchild; 112 | T->lchild = NULL; 113 | T->rchild = NULL; 114 | return OK; 115 | } 116 | 117 | // 替换左子树 118 | Status ReplaceLeft(BiTree &T, BiTree <) 119 | { 120 | BiTree temp; 121 | if (NULL == T) return ERROR; 122 | temp = T->lchild; 123 | T->lchild = LT; 124 | LT = temp; 125 | return OK; 126 | } 127 | 128 | // 替换右子树 129 | Status ReplaceRight(BiTree &T, BiTree &RT) 130 | { 131 | BiTree temp; 132 | if (NULL == T) return ERROR; 133 | temp = T->rchild; 134 | T->rchild = RT; 135 | RT = temp; 136 | return OK; 137 | } 138 | 139 | // 合并二叉树 140 | void UnionBiTree(BiTree &Ttemp) 141 | { 142 | BiTree L = NULL, R = NULL; 143 | L = MakeBiTree(data[i++], NULL, NULL); 144 | R = MakeBiTree(data[i++], NULL, NULL); 145 | ReplaceLeft(Ttemp, L); 146 | ReplaceRight(Ttemp, R); 147 | } 148 | 149 | int main() 150 | { 151 | BiTree T = NULL, Ttemp = NULL; 152 | 153 | InitBiTree(T); 154 | if (TRUE == BiTreeEmpty(T)) printf("初始化T为空\n"); 155 | else printf("初始化T不为空\n"); 156 | 157 | T = MakeBiTree(data[i++], NULL, NULL); 158 | 159 | Ttemp = T; 160 | UnionBiTree(Ttemp); 161 | 162 | Ttemp = T->lchild; 163 | UnionBiTree(Ttemp); 164 | 165 | Status(*visit1)(TElemType); 166 | visit1 = visit; 167 | int num = 0; 168 | InOrderTraverse(T, visit1, num); 169 | printf("叶子结点是 %d\n", num); 170 | 171 | printf("叶子结点是 %d\n", Leaves(T)); 172 | 173 | int lev = 1; 174 | levTraverse(T, visit1, lev); 175 | 176 | printf("高度是 %d\n", depTraverse(T)); 177 | 178 | getchar(); 179 | return 0; 180 | } -------------------------------------------------------------------------------- /DataStructure/HashTable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SUCCESS 1 5 | #define UNSUCCESS 0 6 | #define OVERFLOW -1 7 | #define OK 1 8 | #define ERROR -1 9 | #define MAXNUM 9999 // 用于初始化哈希表的记录 key 10 | 11 | typedef int Status; 12 | typedef int KeyType; 13 | 14 | // 哈希表中的记录类型 15 | typedef struct { 16 | KeyType key; 17 | }RcdType; 18 | 19 | // 哈希表类型 20 | typedef struct { 21 | RcdType *rcd; 22 | int size; 23 | int count; 24 | int *tag; 25 | }HashTable; 26 | 27 | // 哈希表每次重建增长后的大小 28 | int hashsize[] = { 11, 31, 61, 127, 251, 503 }; 29 | int index = 0; 30 | 31 | // 初始哈希表 32 | Status InitHashTable(HashTable &H, int size) { 33 | int i; 34 | H.rcd = (RcdType *)malloc(sizeof(RcdType)*size); 35 | H.tag = (int *)malloc(sizeof(int)*size); 36 | if (NULL == H.rcd || NULL == H.tag) return OVERFLOW; 37 | KeyType maxNum = MAXNUM; 38 | for (i = 0; i < size; i++) { 39 | H.tag[i] = 0; 40 | H.rcd[i].key = maxNum; 41 | } 42 | H.size = size; 43 | H.count = 0; 44 | return OK; 45 | } 46 | 47 | // 哈希函数:除留余数法 48 | int Hash(KeyType key, int m) { 49 | return (3 * key) % m; 50 | } 51 | 52 | // 处理哈希冲突:线性探测 53 | void collision(int &p, int m) { 54 | p = (p + 1) % m; 55 | } 56 | 57 | // 在哈希表中查询 58 | Status SearchHash(HashTable H, KeyType key, int &p, int &c) { 59 | p = Hash(key, H.size); 60 | int h = p; 61 | c = 0; 62 | while ((1 == H.tag[p] && H.rcd[p].key != key) || -1 == H.tag[p]) { 63 | collision(p, H.size); c++; 64 | } 65 | 66 | if (1 == H.tag[p] && key == H.rcd[p].key) return SUCCESS; 67 | else return UNSUCCESS; 68 | } 69 | 70 | //打印哈希表 71 | void printHash(HashTable H) 72 | { 73 | int i; 74 | printf("key : "); 75 | for (i = 0; i < H.size; i++) 76 | printf("%3d ", H.rcd[i].key); 77 | printf("\n"); 78 | printf("tag : "); 79 | for (i = 0; i < H.size; i++) 80 | printf("%3d ", H.tag[i]); 81 | printf("\n\n"); 82 | } 83 | 84 | // 函数声明:插入哈希表 85 | Status InsertHash(HashTable &H, KeyType key); 86 | 87 | // 重建哈希表 88 | Status recreateHash(HashTable &H) { 89 | RcdType *orcd; 90 | int *otag, osize, i; 91 | orcd = H.rcd; 92 | otag = H.tag; 93 | osize = H.size; 94 | 95 | InitHashTable(H, hashsize[index++]); 96 | //把所有元素,按照新哈希函数放到新表中 97 | for (i = 0; i < osize; i++) { 98 | if (1 == otag[i]) { 99 | InsertHash(H, orcd[i].key); 100 | } 101 | } 102 | return OK; 103 | } 104 | 105 | // 插入哈希表 106 | Status InsertHash(HashTable &H, KeyType key) { 107 | int p, c; 108 | if (UNSUCCESS == SearchHash(H, key, p, c)) { //没有相同key 109 | if (c*1.0 / H.size < 0.5) { //冲突次数未达到上线 110 | //插入代码 111 | H.rcd[p].key = key; 112 | H.tag[p] = 1; 113 | H.count++; 114 | return SUCCESS; 115 | } 116 | else recreateHash(H); //重构哈希表 117 | } 118 | return UNSUCCESS; 119 | } 120 | 121 | // 删除哈希表 122 | Status DeleteHash(HashTable &H, KeyType key) { 123 | int p, c; 124 | if (SUCCESS == SearchHash(H, key, p, c)) { 125 | //删除代码 126 | H.tag[p] = -1; 127 | H.count--; 128 | return SUCCESS; 129 | } 130 | else return UNSUCCESS; 131 | } 132 | 133 | int main() 134 | { 135 | printf("-----哈希表-----\n"); 136 | HashTable H; 137 | int i; 138 | int size = 11; 139 | KeyType array[8] = { 22, 41, 53, 46, 30, 13, 12, 67 }; 140 | KeyType key; 141 | 142 | //初始化哈希表 143 | printf("初始化哈希表\n"); 144 | if (SUCCESS == InitHashTable(H, hashsize[index++])) printf("初始化成功\n"); 145 | 146 | //插入哈希表 147 | printf("插入哈希表\n"); 148 | for (i = 0; i <= 7; i++) { 149 | key = array[i]; 150 | InsertHash(H, key); 151 | printHash(H); 152 | } 153 | 154 | //删除哈希表 155 | printf("删除哈希表中key为12的元素\n"); 156 | int p, c; 157 | if (SUCCESS == DeleteHash(H, 12)) { 158 | printf("删除成功,此时哈希表为:\n"); 159 | printHash(H); 160 | } 161 | 162 | //查询哈希表 163 | printf("查询哈希表中key为67的元素\n"); 164 | if (SUCCESS == SearchHash(H, 67, p, c)) printf("查询成功\n"); 165 | 166 | //再次插入,测试哈希表的重建 167 | printf("再次插入,测试哈希表的重建:\n"); 168 | KeyType array1[8] = { 27, 47, 57, 47, 37, 17, 93, 67 }; 169 | for (i = 0; i <= 7; i++) { 170 | key = array1[i]; 171 | InsertHash(H, key); 172 | printHash(H); 173 | } 174 | 175 | getchar(); 176 | return 0; 177 | } -------------------------------------------------------------------------------- /DataStructure/LinkList.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @author huihut 3 | * @E-mail:huihut@outlook.com 4 | * @version 创建时间:2016年9月18日 5 | * 说明:本程序实现了一个单链表。 6 | */ 7 | 8 | #include "stdio.h" 9 | #include "stdlib.h" 10 | #include "malloc.h" 11 | 12 | //5个常量定义 13 | #define TRUE 1 14 | #define FALSE 0 15 | #define OK 1 16 | #define ERROR 0 17 | #define OVERFLOW -1 18 | 19 | //类型定义 20 | typedef int Status; 21 | typedef int ElemType; 22 | 23 | //测试程序长度定义 24 | #define LONGTH 5 25 | 26 | //链表的类型 27 | typedef struct LNode { 28 | ElemType data; 29 | struct LNode *next; 30 | } LNode, *LinkList; 31 | 32 | //创建包含n个元素的链表L,元素值存储在data数组中 33 | Status create(LinkList &L, ElemType *data, int n) { 34 | LNode *p, *q; 35 | int i; 36 | if (n < 0) return ERROR; 37 | L = NULL; 38 | p = L; 39 | for (i = 0; i < n; i++) 40 | { 41 | q = (LNode *)malloc(sizeof(LNode)); 42 | if (NULL == q) return OVERFLOW; 43 | q->data = data[i]; 44 | q->next = NULL; 45 | if (NULL == p) L = q; 46 | else p->next = q; 47 | p = q; 48 | } 49 | return OK; 50 | } 51 | 52 | //e从链表末尾入链表 53 | Status EnQueue_LQ(LinkList &L, ElemType &e) { 54 | LinkList p, q; 55 | 56 | if (NULL == (q = (LNode *)malloc(sizeof(LNode)))) return OVERFLOW; 57 | q->data = e; 58 | q->next = NULL; 59 | if (NULL == L) L = q; 60 | else 61 | { 62 | p = L; 63 | while (p->next != NULL) 64 | { 65 | p = p->next; 66 | } 67 | p->next = q; 68 | } 69 | return OK; 70 | } 71 | 72 | 73 | //从链表头节点出链表到e 74 | Status DeQueue_LQ(LinkList &L, ElemType &e) { 75 | if (NULL == L) return ERROR; 76 | LinkList p; 77 | p = L; 78 | e = p->data; 79 | L = L->next; 80 | free(p); 81 | return OK; 82 | } 83 | 84 | //遍历调用 85 | Status visit(ElemType e) { 86 | printf("%d\t", e); 87 | return OK; 88 | } 89 | 90 | //遍历单链表 91 | void ListTraverse_L(LinkList L, Status(*visit)(ElemType e)) 92 | { 93 | if (NULL == L) return; 94 | for (LinkList p = L; NULL != p; p = p->next) { 95 | visit(p->data); 96 | } 97 | } 98 | 99 | int main() { 100 | int i; 101 | ElemType e, data[LONGTH] = { 1, 2, 3, 4, 5 }; 102 | LinkList L; 103 | 104 | //显示测试值 105 | printf("---【单链表】---\n"); 106 | printf("待测试元素为:\n"); 107 | for (i = 0; i < LONGTH; i++) printf("%d\t", data[i]); 108 | printf("\n"); 109 | 110 | //创建链表L 111 | printf("创建链表L\n"); 112 | if (ERROR == create(L, data, LONGTH)) 113 | { 114 | printf("创建链表L失败\n"); 115 | return -1; 116 | } 117 | printf("成功创建包含%d个元素的链表L\n元素值存储在data数组中\n", LONGTH); 118 | 119 | //遍历单链表 120 | printf("此时链表中元素为:\n"); 121 | ListTraverse_L(L, visit); 122 | 123 | //从链表头节点出链表到e 124 | printf("\n出链表到e\n"); 125 | DeQueue_LQ(L, e); 126 | printf("出链表的元素为:%d\n", e); 127 | printf("此时链表中元素为:\n"); 128 | 129 | //遍历单链表 130 | ListTraverse_L(L, visit); 131 | 132 | //e从链表末尾入链表 133 | printf("\ne入链表\n"); 134 | EnQueue_LQ(L, e); 135 | printf("入链表的元素为:%d\n", e); 136 | printf("此时链表中元素为:\n"); 137 | 138 | //遍历单链表 139 | ListTraverse_L(L, visit); 140 | printf("\n"); 141 | 142 | getchar(); 143 | return 0; 144 | } -------------------------------------------------------------------------------- /DataStructure/LinkList_with_head.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @author huihut 3 | * @E-mail:huihut@outlook.com 4 | * @version 创建时间:2016年9月23日 5 | * 说明:本程序实现了一个具有头结点的单链表。 6 | */ 7 | 8 | #include "stdio.h" 9 | #include "stdlib.h" 10 | #include "malloc.h" 11 | 12 | //5个常量定义 13 | #define TRUE 1 14 | #define FALSE 0 15 | #define OK 1 16 | #define ERROR 0 17 | #define OVERFLOW -1 18 | 19 | //类型定义 20 | typedef int Status; 21 | typedef int ElemType; 22 | 23 | //测试程序长度定义 24 | #define LONGTH 5 25 | 26 | //链表的类型 27 | typedef struct LNode { 28 | ElemType data; 29 | struct LNode *next; 30 | } LNode, *LinkList; 31 | 32 | //创建包含n个元素的链表L,元素值存储在data数组中 33 | Status create(LinkList &L, ElemType *data, int n) { 34 | LNode *p, *q; 35 | int i; 36 | if (n < 0) return ERROR; 37 | p = L = NULL; 38 | 39 | q = (LNode *)malloc(sizeof(LNode)); 40 | if (NULL == q) return OVERFLOW; 41 | q->next = NULL; 42 | p = L = q; 43 | 44 | for (i = 0; i < n; i++) 45 | { 46 | q = (LNode *)malloc(sizeof(LNode)); 47 | if (NULL == q) return OVERFLOW; 48 | q->data = data[i]; 49 | q->next = NULL; 50 | p->next = q; 51 | p = q; 52 | } 53 | return OK; 54 | } 55 | 56 | //e从链表末尾入链表 57 | Status EnQueue_LQ(LinkList &L, ElemType &e) { 58 | LinkList p, q; 59 | 60 | if (NULL == (q = (LNode *)malloc(sizeof(LNode)))) return OVERFLOW; 61 | q->data = e; 62 | q->next = NULL; 63 | if (NULL == L) 64 | { 65 | L = (LNode *)malloc(sizeof(LNode)); 66 | if (NULL == L) return OVERFLOW; 67 | L->next = q; 68 | } 69 | else if (NULL == L->next) 70 | { 71 | L->next = q; 72 | } 73 | else 74 | { 75 | p = L; 76 | while (p->next != NULL) 77 | { 78 | p = p->next; 79 | } 80 | p->next = q; 81 | } 82 | return OK; 83 | } 84 | 85 | 86 | //从链表头节点出链表到e 87 | Status DeQueue_LQ(LinkList &L, ElemType &e) { 88 | if (NULL == L || NULL == L->next) return ERROR; 89 | LinkList p; 90 | p = L->next; 91 | e = p->data; 92 | L->next = p->next; 93 | free(p); 94 | return OK; 95 | } 96 | 97 | //遍历调用 98 | Status visit(ElemType e) { 99 | printf("%d\t", e); 100 | return OK; 101 | } 102 | 103 | //遍历单链表 104 | void ListTraverse_L(LinkList L, Status(*visit)(ElemType e)) 105 | { 106 | if (NULL == L || NULL == L->next) return; 107 | for (LinkList p = L->next; NULL != p; p = p->next) { 108 | visit(p->data); 109 | } 110 | } 111 | 112 | int main() { 113 | int i; 114 | ElemType e, data[LONGTH] = { 1, 2, 3, 4, 5 }; 115 | LinkList L; 116 | 117 | //显示测试值 118 | printf("---【有头结点的单链表】---\n"); 119 | printf("待测试元素为:\n"); 120 | for (i = 0; i < LONGTH; i++) printf("%d\t", data[i]); 121 | printf("\n"); 122 | 123 | //创建链表L 124 | printf("创建链表L\n"); 125 | if (ERROR == create(L, data, LONGTH)) 126 | { 127 | printf("创建链表L失败\n"); 128 | return -1; 129 | } 130 | printf("成功创建包含1个头结点、%d个元素的链表L\n元素值存储在data数组中\n", LONGTH); 131 | 132 | //遍历单链表 133 | printf("此时链表中元素为:\n"); 134 | ListTraverse_L(L, visit); 135 | 136 | //从链表头节点出链表到e 137 | printf("\n出链表到e\n"); 138 | DeQueue_LQ(L, e); 139 | printf("出链表的元素为:%d\n", e); 140 | printf("此时链表中元素为:\n"); 141 | 142 | //遍历单链表 143 | ListTraverse_L(L, visit); 144 | 145 | //e从链表末尾入链表 146 | printf("\ne入链表\n"); 147 | EnQueue_LQ(L, e); 148 | printf("入链表的元素为:%d\n", e); 149 | printf("此时链表中元素为:\n"); 150 | 151 | //遍历单链表 152 | ListTraverse_L(L, visit); 153 | printf("\n"); 154 | 155 | getchar(); 156 | return 0; 157 | } -------------------------------------------------------------------------------- /DataStructure/RedBlackTree.cpp: -------------------------------------------------------------------------------- 1 | #define BLACK 1 2 | #define RED 0 3 | #include 4 | 5 | using namespace std; 6 | 7 | class bst { 8 | private: 9 | 10 | struct Node { 11 | int value; 12 | bool color; 13 | Node *leftTree, *rightTree, *parent; 14 | 15 | Node() : value(0), color(RED), leftTree(NULL), rightTree(NULL), parent(NULL) { } 16 | 17 | Node* grandparent() { 18 | if (parent == NULL) { 19 | return NULL; 20 | } 21 | return parent->parent; 22 | } 23 | 24 | Node* uncle() { 25 | if (grandparent() == NULL) { 26 | return NULL; 27 | } 28 | if (parent == grandparent()->rightTree) 29 | return grandparent()->leftTree; 30 | else 31 | return grandparent()->rightTree; 32 | } 33 | 34 | Node* sibling() { 35 | if (parent->leftTree == this) 36 | return parent->rightTree; 37 | else 38 | return parent->leftTree; 39 | } 40 | }; 41 | 42 | void rotate_right(Node *p) { 43 | Node *gp = p->grandparent(); 44 | Node *fa = p->parent; 45 | Node *y = p->rightTree; 46 | 47 | fa->leftTree = y; 48 | 49 | if (y != NIL) 50 | y->parent = fa; 51 | p->rightTree = fa; 52 | fa->parent = p; 53 | 54 | if (root == fa) 55 | root = p; 56 | p->parent = gp; 57 | 58 | if (gp != NULL) { 59 | if (gp->leftTree == fa) 60 | gp->leftTree = p; 61 | else 62 | gp->rightTree = p; 63 | } 64 | 65 | } 66 | 67 | void rotate_left(Node *p) { 68 | if (p->parent == NULL) { 69 | root = p; 70 | return; 71 | } 72 | Node *gp = p->grandparent(); 73 | Node *fa = p->parent; 74 | Node *y = p->leftTree; 75 | 76 | fa->rightTree = y; 77 | 78 | if (y != NIL) 79 | y->parent = fa; 80 | p->leftTree = fa; 81 | fa->parent = p; 82 | 83 | if (root == fa) 84 | root = p; 85 | p->parent = gp; 86 | 87 | if (gp != NULL) { 88 | if (gp->leftTree == fa) 89 | gp->leftTree = p; 90 | else 91 | gp->rightTree = p; 92 | } 93 | } 94 | 95 | void inorder(Node *p) { 96 | if (p == NIL) 97 | return; 98 | 99 | if (p->leftTree) 100 | inorder(p->leftTree); 101 | 102 | cout << p->value << " "; 103 | 104 | if (p->rightTree) 105 | inorder(p->rightTree); 106 | } 107 | 108 | string outputColor(bool color) { 109 | return color ? "BLACK" : "RED"; 110 | } 111 | 112 | Node* getSmallestChild(Node *p) { 113 | if (p->leftTree == NIL) 114 | return p; 115 | return getSmallestChild(p->leftTree); 116 | } 117 | 118 | bool delete_child(Node *p, int data) { 119 | if (p->value > data) { 120 | if (p->leftTree == NIL) { 121 | return false; 122 | } 123 | return delete_child(p->leftTree, data); 124 | } 125 | else if (p->value < data) { 126 | if (p->rightTree == NIL) { 127 | return false; 128 | } 129 | return delete_child(p->rightTree, data); 130 | } 131 | else if (p->value == data) { 132 | if (p->rightTree == NIL) { 133 | delete_one_child(p); 134 | return true; 135 | } 136 | Node *smallest = getSmallestChild(p->rightTree); 137 | swap(p->value, smallest->value); 138 | delete_one_child(smallest); 139 | 140 | return true; 141 | } 142 | else { 143 | return false; 144 | } 145 | } 146 | 147 | void delete_one_child(Node *p) { 148 | Node *child = p->leftTree == NIL ? p->rightTree : p->leftTree; 149 | if (p->parent == NULL && p->leftTree == NIL && p->rightTree == NIL) { 150 | p = NULL; 151 | root = p; 152 | return; 153 | } 154 | 155 | if (p->parent == NULL) { 156 | delete p; 157 | child->parent = NULL; 158 | root = child; 159 | root->color = BLACK; 160 | return; 161 | } 162 | 163 | if (p->parent->leftTree == p) { 164 | p->parent->leftTree = child; 165 | } 166 | else { 167 | p->parent->rightTree = child; 168 | } 169 | child->parent = p->parent; 170 | 171 | if (p->color == BLACK) { 172 | if (child->color == RED) { 173 | child->color = BLACK; 174 | } 175 | else 176 | delete_case(child); 177 | } 178 | 179 | delete p; 180 | } 181 | 182 | void delete_case(Node *p) { 183 | if (p->parent == NULL) { 184 | p->color = BLACK; 185 | return; 186 | } 187 | if (p->sibling()->color == RED) { 188 | p->parent->color = RED; 189 | p->sibling()->color = BLACK; 190 | if (p == p->parent->leftTree) 191 | rotate_left(p->sibling()); 192 | else 193 | rotate_right(p->sibling()); 194 | } 195 | if (p->parent->color == BLACK && p->sibling()->color == BLACK 196 | && p->sibling()->leftTree->color == BLACK && p->sibling()->rightTree->color == BLACK) { 197 | p->sibling()->color = RED; 198 | delete_case(p->parent); 199 | } 200 | else if (p->parent->color == RED && p->sibling()->color == BLACK 201 | && p->sibling()->leftTree->color == BLACK && p->sibling()->rightTree->color == BLACK) { 202 | p->sibling()->color = RED; 203 | p->parent->color = BLACK; 204 | } 205 | else { 206 | if (p->sibling()->color == BLACK) { 207 | if (p == p->parent->leftTree && p->sibling()->leftTree->color == RED 208 | && p->sibling()->rightTree->color == BLACK) { 209 | p->sibling()->color = RED; 210 | p->sibling()->leftTree->color = BLACK; 211 | rotate_right(p->sibling()->leftTree); 212 | } 213 | else if (p == p->parent->rightTree && p->sibling()->leftTree->color == BLACK 214 | && p->sibling()->rightTree->color == RED) { 215 | p->sibling()->color = RED; 216 | p->sibling()->rightTree->color = BLACK; 217 | rotate_left(p->sibling()->rightTree); 218 | } 219 | } 220 | p->sibling()->color = p->parent->color; 221 | p->parent->color = BLACK; 222 | if (p == p->parent->leftTree) { 223 | p->sibling()->rightTree->color = BLACK; 224 | rotate_left(p->sibling()); 225 | } 226 | else { 227 | p->sibling()->leftTree->color = BLACK; 228 | rotate_right(p->sibling()); 229 | } 230 | } 231 | } 232 | 233 | void insert(Node *p, int data) { 234 | if (p->value >= data) { 235 | if (p->leftTree != NIL) 236 | insert(p->leftTree, data); 237 | else { 238 | Node *tmp = new Node(); 239 | tmp->value = data; 240 | tmp->leftTree = tmp->rightTree = NIL; 241 | tmp->parent = p; 242 | p->leftTree = tmp; 243 | insert_case(tmp); 244 | } 245 | } 246 | else { 247 | if (p->rightTree != NIL) 248 | insert(p->rightTree, data); 249 | else { 250 | Node *tmp = new Node(); 251 | tmp->value = data; 252 | tmp->leftTree = tmp->rightTree = NIL; 253 | tmp->parent = p; 254 | p->rightTree = tmp; 255 | insert_case(tmp); 256 | } 257 | } 258 | } 259 | 260 | void insert_case(Node *p) { 261 | if (p->parent == NULL) { 262 | root = p; 263 | p->color = BLACK; 264 | return; 265 | } 266 | if (p->parent->color == RED) { 267 | if (p->uncle()->color == RED) { 268 | p->parent->color = p->uncle()->color = BLACK; 269 | p->grandparent()->color = RED; 270 | insert_case(p->grandparent()); 271 | } 272 | else { 273 | if (p->parent->rightTree == p && p->grandparent()->leftTree == p->parent) { 274 | rotate_left(p); 275 | rotate_right(p); 276 | p->color = BLACK; 277 | p->leftTree->color = p->rightTree->color = RED; 278 | } 279 | else if (p->parent->leftTree == p && p->grandparent()->rightTree == p->parent) { 280 | rotate_right(p); 281 | rotate_left(p); 282 | p->color = BLACK; 283 | p->leftTree->color = p->rightTree->color = RED; 284 | } 285 | else if (p->parent->leftTree == p && p->grandparent()->leftTree == p->parent) { 286 | p->parent->color = BLACK; 287 | p->grandparent()->color = RED; 288 | rotate_right(p->parent); 289 | } 290 | else if (p->parent->rightTree == p && p->grandparent()->rightTree == p->parent) { 291 | p->parent->color = BLACK; 292 | p->grandparent()->color = RED; 293 | rotate_left(p->parent); 294 | } 295 | } 296 | } 297 | } 298 | 299 | void DeleteTree(Node *p) { 300 | if (!p || p == NIL) { 301 | return; 302 | } 303 | DeleteTree(p->leftTree); 304 | DeleteTree(p->rightTree); 305 | delete p; 306 | } 307 | public: 308 | 309 | bst() { 310 | NIL = new Node(); 311 | NIL->color = BLACK; 312 | root = NULL; 313 | } 314 | 315 | ~bst() { 316 | if (root) 317 | DeleteTree(root); 318 | delete NIL; 319 | } 320 | 321 | void inorder() { 322 | if (root == NULL) 323 | return; 324 | inorder(root); 325 | cout << endl; 326 | } 327 | 328 | void insert(int x) { 329 | if (root == NULL) { 330 | root = new Node(); 331 | root->color = BLACK; 332 | root->leftTree = root->rightTree = NIL; 333 | root->value = x; 334 | } 335 | else { 336 | insert(root, x); 337 | } 338 | } 339 | 340 | bool delete_value(int data) { 341 | return delete_child(root, data); 342 | } 343 | private: 344 | Node *root, *NIL; 345 | }; 346 | 347 | int main() 348 | { 349 | cout << "---【红黑树】---" << endl; 350 | // 创建红黑树 351 | bst tree; 352 | 353 | // 插入元素 354 | tree.insert(2); 355 | tree.insert(9); 356 | tree.insert(-10); 357 | tree.insert(0); 358 | tree.insert(33); 359 | tree.insert(-19); 360 | 361 | // 顺序打印红黑树 362 | cout << "插入元素后的红黑树:" << endl; 363 | tree.inorder(); 364 | 365 | // 删除元素 366 | tree.delete_value(2); 367 | 368 | // 顺序打印红黑树 369 | cout << "删除元素 2 后的红黑树:" << endl; 370 | tree.inorder(); 371 | 372 | // 析构 373 | tree.~bst(); 374 | 375 | getchar(); 376 | return 0; 377 | } -------------------------------------------------------------------------------- /DataStructure/SqList.cpp: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @author huihut 4 | * @E-mail:huihut@outlook.com 5 | * @version 创建时间:2016年9月9日 6 | * 说明:本程序实现了一个顺序表。 7 | */ 8 | 9 | #include "stdio.h" 10 | #include "stdlib.h" 11 | #include "malloc.h" 12 | 13 | //5个常量定义 14 | #define TRUE 1 15 | #define FALSE 0 16 | #define OK 1 17 | #define ERROR 0 18 | #define OVERFLOW -1 19 | 20 | //测试程序长度定义 21 | #define LONGTH 5 22 | 23 | //类型定义 24 | typedef int Status; 25 | typedef int ElemType; 26 | 27 | //顺序栈的类型 28 | typedef struct { 29 | ElemType *elem; 30 | int length; 31 | int size; 32 | int increment; 33 | } SqList; 34 | 35 | //初始化顺序表L 36 | Status InitList_Sq(SqList &L, int size, int inc) { 37 | L.elem = (ElemType *)malloc(size * sizeof(ElemType)); 38 | if (NULL == L.elem) return OVERFLOW; 39 | L.length = 0; 40 | L.size = size; 41 | L.increment = inc; 42 | return OK; 43 | } 44 | 45 | //销毁顺序表L 46 | Status DestroyList_Sq(SqList &L) { 47 | free(L.elem); 48 | L.elem = NULL; 49 | return OK; 50 | } 51 | 52 | //将顺序表L清空 53 | Status ClearList_Sq(SqList &L) { 54 | if (0 != L.length) L.length = 0; 55 | return OK; 56 | } 57 | 58 | //若顺序表L为空表,则返回TRUE,否则FALSE 59 | Status ListEmpty_Sq(SqList L) { 60 | if (0 == L.length) return TRUE; 61 | return FALSE; 62 | } 63 | 64 | //返回顺序表L中元素个数 65 | int ListLength_Sq(SqList L) { 66 | return L.length; 67 | } 68 | 69 | // 用e返回顺序表L中第i个元素的值 70 | Status GetElem_Sq(SqList L, int i, ElemType &e) { 71 | e = L.elem[--i]; 72 | return OK; 73 | } 74 | 75 | 76 | // 在顺序表L顺序查找元素e,成功时返回该元素在表中第一次出现的位置,否则返回 - 1 77 | int Search_Sq(SqList L, ElemType e) { 78 | int i = 0; 79 | while (i < L.length && L.elem[i] != e) i++; 80 | if (i < L.length) return i; 81 | else return -1; 82 | } 83 | 84 | //遍历调用 85 | Status visit(ElemType e) { 86 | printf("%d\t", e); 87 | return OK; 88 | } 89 | 90 | //遍历顺序表L,依次对每个元素调用函数visit() 91 | Status ListTraverse_Sq(SqList L, Status(*visit)(ElemType e)) { 92 | if (0 == L.length) return ERROR; 93 | for (int i = 0; i < L.length; i++) { 94 | visit(L.elem[i]); 95 | } 96 | return OK; 97 | } 98 | 99 | //将顺序表L中第i个元素赋值为e 100 | Status PutElem_Sq(SqList &L, int i, ElemType e) { 101 | if (i > L.length) return ERROR; 102 | e = L.elem[--i]; 103 | return OK; 104 | 105 | } 106 | 107 | //在顺序表L表尾添加元素e 108 | Status Append_Sq(SqList &L, ElemType e) { 109 | if (L.length >= L.size) return ERROR; 110 | L.elem[L.length] = e; 111 | L.length++; 112 | return OK; 113 | } 114 | 115 | //删除顺序表L的表尾元素,并用参数e返回其值 116 | Status DeleteLast_Sq(SqList &L, ElemType &e) { 117 | if (0 == L.length) return ERROR; 118 | e = L.elem[L.length - 1]; 119 | L.length--; 120 | return OK; 121 | } 122 | 123 | int main() { 124 | //定义表L 125 | SqList L; 126 | 127 | //定义测量值 128 | int size, increment, i; 129 | 130 | //初始化测试值 131 | size = LONGTH; 132 | increment = LONGTH; 133 | ElemType e, eArray[LONGTH] = { 1, 2, 3, 4, 5 }; 134 | 135 | //显示测试值 136 | printf("---【顺序栈】---\n"); 137 | printf("表L的size为:%d\n表L的increment为:%d\n", size, increment); 138 | printf("待测试元素为:\n"); 139 | for (i = 0; i < LONGTH; i++) { 140 | printf("%d\t", eArray[i]); 141 | } 142 | printf("\n"); 143 | 144 | //初始化顺序表 145 | if (!InitList_Sq(L, size, increment)) { 146 | printf("初始化顺序表失败\n"); 147 | exit(0); 148 | } 149 | printf("已初始化顺序表\n"); 150 | 151 | //判空 152 | if (TRUE == ListEmpty_Sq(L)) printf("此表为空表\n"); 153 | else printf("此表不是空表\n"); 154 | 155 | //入表 156 | printf("将待测元素入表:\n"); 157 | for (i = 0; i < LONGTH; i++) { 158 | if (ERROR == Append_Sq(L, eArray[i])) printf("入表失败\n");; 159 | } 160 | printf("入表成功\n"); 161 | 162 | //遍历顺序表L 163 | printf("此时表内元素为:\n"); 164 | ListTraverse_Sq(L, visit); 165 | 166 | //出表 167 | printf("\n将表尾元素入表到e:\n"); 168 | if (ERROR == DeleteLast_Sq(L, e)) printf("出表失败\n"); 169 | printf("出表成功\n出表元素为%d\n", e); 170 | 171 | //遍历顺序表L 172 | printf("此时表内元素为:\n"); 173 | ListTraverse_Sq(L, visit); 174 | 175 | //销毁顺序表 176 | printf("\n销毁顺序表\n"); 177 | if (OK == DestroyList_Sq(L)) printf("销毁成功\n"); 178 | else printf("销毁失败\n"); 179 | 180 | getchar(); 181 | return 0; 182 | } -------------------------------------------------------------------------------- /DataStructure/SqStack.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @author huihut 3 | * @E-mail:huihut@outlook.com 4 | * @version 创建时间:2016年9月9日 5 | * 说明:本程序实现了一个顺序栈。 6 | * 功能:有初始化、销毁、判断空、清空、入栈、出栈、取元素的操作。 7 | */ 8 | 9 | #include "stdio.h" 10 | #include "stdlib.h" 11 | #include "malloc.h" 12 | 13 | //5个常量定义 14 | #define TRUE 1 15 | #define FALSE 0 16 | #define OK 1 17 | #define ERROR 0 18 | #define OVERFLOW -1 19 | 20 | //测试程序长度定义 21 | #define LONGTH 5 22 | 23 | //类型定义 24 | typedef int Status; 25 | typedef int ElemType; 26 | 27 | //顺序栈的类型 28 | typedef struct { 29 | ElemType *elem; 30 | int top; 31 | int size; 32 | int increment; 33 | } SqSrack; 34 | 35 | //初始化顺序栈 36 | Status InitStack_Sq(SqSrack &S, int size, int inc) { 37 | S.elem = (ElemType *)malloc(size * sizeof(ElemType)); 38 | if (NULL == S.elem) return OVERFLOW; 39 | S.top = 0; 40 | S.size = size; 41 | S.increment = inc; 42 | return OK; 43 | } 44 | 45 | //销毁顺序栈 46 | Status DestroyStack_Sq(SqSrack &S) { 47 | free(S.elem); 48 | S.elem = NULL; 49 | return OK; 50 | } 51 | 52 | //判断S是否空,若空则返回TRUE,否则返回FALSE 53 | Status StackEmpty_Sq(SqSrack S) { 54 | if (0 == S.top) return TRUE; 55 | return FALSE; 56 | } 57 | 58 | //清空栈S 59 | void ClearStack_Sq(SqSrack &S) { 60 | if (0 == S.top) return; 61 | S.size = 0; 62 | S.top = 0; 63 | } 64 | 65 | //元素e压入栈S 66 | Status Push_Sq(SqSrack &S, ElemType e) { 67 | ElemType *newbase; 68 | if (S.top >= S.size) { 69 | newbase = (ElemType *)realloc(S.elem, (S.size + S.increment) * sizeof(ElemType)); 70 | if (NULL == newbase) return OVERFLOW; 71 | S.elem = newbase; 72 | S.size += S.increment; 73 | } 74 | S.elem[S.top++] = e; 75 | return OK; 76 | } 77 | 78 | //取栈S的栈顶元素,并用e返回 79 | Status GetTop_Sq(SqSrack S, ElemType &e) { 80 | if (0 == S.top) return ERROR; 81 | e = S.elem[S.top - 1]; 82 | return e; 83 | } 84 | 85 | //栈S的栈顶元素出栈,并用e返回 86 | Status Pop_Sq(SqSrack &S, ElemType &e) { 87 | if (0 == S.top) return ERROR; 88 | e = S.elem[S.top - 1]; 89 | S.top--; 90 | return e; 91 | } 92 | 93 | int main() { 94 | //定义栈S 95 | SqSrack S; 96 | 97 | //定义测量值 98 | int size, increment, i; 99 | 100 | //初始化测试值 101 | size = LONGTH; 102 | increment = LONGTH; 103 | ElemType e, eArray[LONGTH] = { 1, 2, 3, 4, 5 }; 104 | 105 | //显示测试值 106 | printf("---【顺序栈】---\n"); 107 | printf("栈S的size为:%d\n栈S的increment为:%d\n", size, increment); 108 | printf("待测试元素为:\n"); 109 | for (i = 0; i < LONGTH; i++) { 110 | printf("%d\t", eArray[i]); 111 | } 112 | printf("\n"); 113 | 114 | //初始化顺序栈 115 | if (!InitStack_Sq(S, size, increment)) { 116 | printf("初始化顺序栈失败\n"); 117 | exit(0); 118 | } 119 | printf("已初始化顺序栈\n"); 120 | 121 | //入栈 122 | for (i = 0; i < S.size; i++) { 123 | if (!Push_Sq(S, eArray[i])) { 124 | printf("%d入栈失败\n", eArray[i]); 125 | exit(0); 126 | } 127 | } 128 | printf("已入栈\n"); 129 | 130 | //判断非空 131 | if (StackEmpty_Sq(S)) printf("S栈为空\n"); 132 | else printf("S栈非空\n"); 133 | 134 | //取栈S的栈顶元素 135 | printf("栈S的栈顶元素为:\n"); 136 | printf("%d\n", GetTop_Sq(S, e)); 137 | 138 | //栈S元素出栈 139 | printf("栈S元素出栈为:\n"); 140 | for (i = 0, e = 0; i < S.size; i++) { 141 | printf("%d\t", Pop_Sq(S, e)); 142 | } 143 | printf("\n"); 144 | 145 | //清空栈S 146 | ClearStack_Sq(S); 147 | printf("已清空栈S\n"); 148 | 149 | getchar(); 150 | return 0; 151 | } -------------------------------------------------------------------------------- /DesignPattern/AbstractFactoryPattern/Factory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #include "Factory.h" 6 | #include "concrete_factory.h" 7 | 8 | Factory* Factory::CreateFactory(FACTORY_TYPE factory) 9 | { 10 | Factory *pFactory = nullptr; 11 | switch (factory) { 12 | case FACTORY_TYPE::BENZ_FACTORY: // Benz factory 13 | pFactory = new BenzFactory(); 14 | break; 15 | case FACTORY_TYPE::BMW_FACTORY: // BMW factory 16 | pFactory = new BmwFactory(); 17 | break; 18 | case FACTORY_TYPE::AUDI_FACTORY: // Audi factory 19 | pFactory = new AudiFactory(); 20 | break; 21 | default: 22 | break; 23 | } 24 | return pFactory; 25 | } -------------------------------------------------------------------------------- /DesignPattern/AbstractFactoryPattern/Factory.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_FACTORY_H 6 | #define DESIGNPATTERN_FACTORY_H 7 | 8 | #include "product.h" 9 | 10 | // Abstract factory pattern 11 | class Factory { 12 | public: 13 | enum FACTORY_TYPE { 14 | BENZ_FACTORY, // Benz factory 15 | BMW_FACTORY, // BMW factory 16 | AUDI_FACTORY // Audi factory 17 | }; 18 | 19 | virtual ICar* CreateCar() = 0; // Production car 20 | virtual IBike* CreateBike() = 0; // Production bicycle 21 | static Factory * CreateFactory(FACTORY_TYPE factory); // Create factory 22 | }; 23 | 24 | #endif //DESIGNPATTERN_FACTORY_H 25 | -------------------------------------------------------------------------------- /DesignPattern/AbstractFactoryPattern/FactoryMain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #include "Factory.h" 6 | #include "product.h" 7 | #include "FactoryMain.h" 8 | #include 9 | using namespace std; 10 | 11 | void FactoryMain() 12 | { 13 | // Benz 14 | Factory * pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::BENZ_FACTORY); 15 | ICar * pCar = pFactory->CreateCar(); 16 | IBike * pBike = pFactory->CreateBike(); 17 | 18 | cout << "Benz factory - Car: " << pCar->Name() << endl; 19 | cout << "Benz factory - Bike: " << pBike->Name() << endl; 20 | 21 | SAFE_DELETE(pCar); 22 | SAFE_DELETE(pBike); 23 | SAFE_DELETE(pFactory); 24 | 25 | // BMW 26 | pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::BMW_FACTORY); 27 | pCar = pFactory->CreateCar(); 28 | pBike = pFactory->CreateBike(); 29 | cout << "Bmw factory - Car: " << pCar->Name() << endl; 30 | cout << "Bmw factory - Bike: " << pBike->Name() << endl; 31 | 32 | SAFE_DELETE(pCar); 33 | SAFE_DELETE(pBike); 34 | SAFE_DELETE(pFactory); 35 | 36 | // Audi 37 | pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::AUDI_FACTORY); 38 | pCar = pFactory->CreateCar(); 39 | pBike = pFactory->CreateBike(); 40 | cout << "Audi factory - Car: " << pCar->Name() << endl; 41 | cout << "Audi factory - Bike: " << pBike->Name() << endl; 42 | 43 | SAFE_DELETE(pCar); 44 | SAFE_DELETE(pBike); 45 | SAFE_DELETE(pFactory); 46 | } -------------------------------------------------------------------------------- /DesignPattern/AbstractFactoryPattern/FactoryMain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_FACTORYMAIN_H 6 | #define DESIGNPATTERN_FACTORYMAIN_H 7 | 8 | #ifndef SAFE_DELETE 9 | #define SAFE_DELETE(p) { if(p) {delete(p); (p)=nullptr;}} 10 | #endif 11 | 12 | void FactoryMain(); 13 | 14 | #endif //DESIGNPATTERN_FACTORYMAIN_H 15 | -------------------------------------------------------------------------------- /DesignPattern/AbstractFactoryPattern/concrete_factory.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_CONCRETE_FACTORY_H 6 | #define DESIGNPATTERN_CONCRETE_FACTORY_H 7 | 8 | #include "Factory.h" 9 | #include "concrete_product.h" 10 | 11 | // Benz factory 12 | class BenzFactory : public Factory 13 | { 14 | public: 15 | ICar* CreateCar() 16 | { 17 | return new BenzCar(); 18 | } 19 | IBike* CreateBike() 20 | { 21 | return new BenzBike(); 22 | } 23 | }; 24 | 25 | // BMW factory 26 | class BmwFactory : public Factory 27 | { 28 | public: 29 | ICar* CreateCar() { 30 | return new BmwCar(); 31 | } 32 | 33 | IBike* CreateBike() { 34 | return new BmwBike(); 35 | } 36 | }; 37 | 38 | // Audi factory 39 | class AudiFactory : public Factory 40 | { 41 | public: 42 | ICar* CreateCar() { 43 | return new AudiCar(); 44 | } 45 | 46 | IBike* CreateBike() { 47 | return new AudiBike(); 48 | } 49 | }; 50 | 51 | #endif //DESIGNPATTERN_CONCRETE_FACTORY_H 52 | -------------------------------------------------------------------------------- /DesignPattern/AbstractFactoryPattern/concrete_product.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_CONCRETE_PRODUCT_H 6 | #define DESIGNPATTERN_CONCRETE_PRODUCT_H 7 | 8 | #include "product.h" 9 | 10 | /********** Car **********/ 11 | // Benz 12 | class BenzCar : public ICar 13 | { 14 | public: 15 | string Name() 16 | { 17 | return "Benz Car"; 18 | } 19 | }; 20 | 21 | // BMW 22 | class BmwCar : public ICar 23 | { 24 | public: 25 | string Name() 26 | { 27 | return "Bmw Car"; 28 | } 29 | }; 30 | 31 | // Audi 32 | class AudiCar : public ICar 33 | { 34 | public: 35 | string Name() 36 | { 37 | return "Audi Car"; 38 | } 39 | }; 40 | 41 | /********** Bicycle **********/ 42 | // Benz 43 | class BenzBike : public IBike 44 | { 45 | public: 46 | string Name() 47 | { 48 | return "Benz Bike"; 49 | } 50 | }; 51 | 52 | // BMW 53 | class BmwBike : public IBike 54 | { 55 | public: 56 | string Name() 57 | { 58 | return "Bmw Bike"; 59 | } 60 | }; 61 | 62 | // Audi 63 | class AudiBike : public IBike 64 | { 65 | public: 66 | string Name() 67 | { 68 | return "Audi Bike"; 69 | } 70 | }; 71 | 72 | #endif //DESIGNPATTERN_CONCRETE_PRODUCT_H 73 | -------------------------------------------------------------------------------- /DesignPattern/AbstractFactoryPattern/product.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_PRODUCT_H 6 | #define DESIGNPATTERN_PRODUCT_H 7 | 8 | #include 9 | using std::string; 10 | 11 | // Car Interface 12 | class ICar 13 | { 14 | public: 15 | virtual string Name() = 0; 16 | }; 17 | 18 | // Bike Interface 19 | class IBike 20 | { 21 | public: 22 | virtual string Name() = 0; 23 | }; 24 | 25 | #endif //DESIGNPATTERN_PRODUCT_H 26 | -------------------------------------------------------------------------------- /DesignPattern/AdapterPattern/AdapterMain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_ADAPTERMAIN_H 6 | #define DESIGNPATTERN_ADAPTERMAIN_H 7 | 8 | #include "adapter.h" 9 | 10 | void AdapterMain() 11 | { 12 | // Create a power adapter 13 | IRussiaSocket * pAdapter = new PowerAdapter(); 14 | 15 | // Recharge 16 | pAdapter->Charge(); 17 | 18 | SAFE_DELETE(pAdapter); 19 | } 20 | 21 | #endif //DESIGNPATTERN_ADAPTERMAIN_H 22 | -------------------------------------------------------------------------------- /DesignPattern/AdapterPattern/adaptee.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_ADAPTEE_H 6 | #define DESIGNPATTERN_ADAPTEE_H 7 | 8 | #include 9 | 10 | // Built-in charger (two-leg flat type) 11 | class OwnCharger 12 | { 13 | public: 14 | void ChargeWithFeetFlat() 15 | { 16 | std::cout << "OwnCharger::ChargeWithFeetFlat\n"; 17 | } 18 | }; 19 | 20 | #endif //DESIGNPATTERN_ADAPTEE_H 21 | -------------------------------------------------------------------------------- /DesignPattern/AdapterPattern/adapter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_ADAPTER_H 6 | #define DESIGNPATTERN_ADAPTER_H 7 | 8 | #include "target.h" 9 | #include "adaptee.h" 10 | 11 | #ifndef SAFE_DELETE 12 | #define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} } 13 | #endif 14 | 15 | // Power Adapter 16 | class PowerAdapter : public IRussiaSocket 17 | { 18 | public: 19 | PowerAdapter() : m_pCharger(new OwnCharger()){} 20 | ~PowerAdapter() 21 | { 22 | SAFE_DELETE(m_pCharger); 23 | } 24 | void Charge() 25 | { 26 | // Use the built-in charger (two-pin flat) to charge 27 | m_pCharger->ChargeWithFeetFlat(); 28 | } 29 | private: 30 | // Hold the interface object that needs to be adapted (the built-in charger) 31 | OwnCharger* m_pCharger; 32 | }; 33 | 34 | #endif //DESIGNPATTERN_ADAPTER_H 35 | -------------------------------------------------------------------------------- /DesignPattern/AdapterPattern/target.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_TARGET_H 6 | #define DESIGNPATTERN_TARGET_H 7 | 8 | // Sockets provided by Russia 9 | class IRussiaSocket 10 | { 11 | public: 12 | // Use both feet to charge in a round shape (not implemented yet) 13 | virtual void Charge() = 0; 14 | }; 15 | 16 | #endif //DESIGNPATTERN_TARGET_H 17 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/BridgeMain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #include "BridgeMain.h" 6 | 7 | void BridgeMain() 8 | { 9 | // Create electrical appliances (electric lights, electric fans) 10 | IElectricalEquipment * light = new Light(); 11 | IElectricalEquipment * fan = new Fan(); 12 | 13 | // Create switch (pull chain switch, two-position switch) 14 | // Associating a pull chain switch with a light and a two-position switch with a fan 15 | ISwitch * pullChain = new PullChainSwitch(light); 16 | ISwitch * twoPosition = new TwoPositionSwitch(fan); 17 | 18 | // Lights on, lights off 19 | pullChain->On(); 20 | pullChain->Off(); 21 | 22 | // Turn on the fan, turn off the fan 23 | twoPosition->On(); 24 | twoPosition->Off(); 25 | 26 | SAFE_DELETE(twoPosition); 27 | SAFE_DELETE(pullChain); 28 | SAFE_DELETE(fan); 29 | SAFE_DELETE(light); 30 | } -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/BridgeMain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_BRIDGEMAIN_H 6 | #define DESIGNPATTERN_BRIDGEMAIN_H 7 | 8 | #include "refined_abstraction.h" 9 | #include "concrete_implementor.h" 10 | 11 | #ifndef SAFE_DELETE 12 | #define SAFE_DELETE(p) { if(p){delete(p); (p)=nullptr;} } 13 | #endif 14 | 15 | void BridgeMain(); 16 | 17 | #endif //DESIGNPATTERN_BRIDGEMAIN_H 18 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/abstraction.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_ABSTRACTION_H 6 | #define DESIGNPATTERN_ABSTRACTION_H 7 | 8 | #include "implementor.h" 9 | 10 | // Switch 11 | class ISwitch 12 | { 13 | public: 14 | ISwitch(IElectricalEquipment *ee){ m_pEe = ee; } 15 | virtual ~ISwitch(){} 16 | virtual void On() = 0; // Turn on the appliance 17 | virtual void Off() = 0; // Turn off the appliance 18 | 19 | protected: 20 | IElectricalEquipment * m_pEe; 21 | }; 22 | 23 | #endif //DESIGNPATTERN_ABSTRACTION_H 24 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/concrete_implementor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H 6 | #define DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H 7 | 8 | #include "implementor.h" 9 | #include 10 | 11 | // Electric lights 12 | class Light : public IElectricalEquipment 13 | { 14 | public: 15 | // Turn on the lights 16 | virtual void PowerOn() override 17 | { 18 | std::cout << "Light is on." << std::endl; 19 | } 20 | // Turn off the lights 21 | virtual void PowerOff() override 22 | { 23 | std::cout << "Light is off." << std::endl; 24 | } 25 | }; 26 | 27 | // Electric Fan 28 | class Fan : public IElectricalEquipment 29 | { 30 | public: 31 | // Turn on the fan 32 | virtual void PowerOn() override 33 | { 34 | std::cout << "Fan is on." << std::endl; 35 | } 36 | // Turn off the fan 37 | virtual void PowerOff() override 38 | { 39 | std::cout << "Fan is off." << std::endl; 40 | } 41 | }; 42 | 43 | 44 | #endif //DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H 45 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/implementor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_IMPLEMENTOR_H 6 | #define DESIGNPATTERN_IMPLEMENTOR_H 7 | 8 | // Electric equipment 9 | class IElectricalEquipment 10 | { 11 | public: 12 | virtual ~IElectricalEquipment(){} 13 | virtual void PowerOn() = 0; 14 | virtual void PowerOff() = 0; 15 | }; 16 | 17 | #endif //DESIGNPATTERN_IMPLEMENTOR_H 18 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/refined_abstraction.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_REFINED_ABSTRACTION_H 6 | #define DESIGNPATTERN_REFINED_ABSTRACTION_H 7 | 8 | #include "abstraction.h" 9 | #include 10 | 11 | // Zipper switch 12 | class PullChainSwitch : public ISwitch 13 | { 14 | public: 15 | PullChainSwitch(IElectricalEquipment *ee) : ISwitch(ee) {} 16 | 17 | // Turn on the equipment with a zipper switch 18 | virtual void On() override 19 | { 20 | std::cout << "Turn on the equipment with a zipper switch." << std::endl; 21 | m_pEe->PowerOn(); 22 | } 23 | 24 | // Turn off the equipment with a zipper switch 25 | virtual void Off() override 26 | { 27 | std::cout << "Turn off the equipment with a zipper switch." << std::endl; 28 | m_pEe->PowerOff(); 29 | } 30 | }; 31 | 32 | // Two-position switch 33 | class TwoPositionSwitch : public ISwitch 34 | { 35 | public: 36 | TwoPositionSwitch(IElectricalEquipment *ee) : ISwitch(ee) {} 37 | 38 | // Turn on the equipment with a two-position switch 39 | virtual void On() override 40 | { 41 | std::cout << "Turn on the equipment with a two-position switch." << std::endl; 42 | m_pEe->PowerOn(); 43 | } 44 | 45 | // Turn off the equipment with a two-position switch 46 | virtual void Off() override { 47 | std::cout << "Turn off the equipment with a two-position switch." << std::endl; 48 | m_pEe->PowerOff(); 49 | } 50 | }; 51 | 52 | 53 | #endif //DESIGNPATTERN_REFINED_ABSTRACTION_H 54 | -------------------------------------------------------------------------------- /DesignPattern/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(DesignPattern) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | add_executable(DesignPattern main.cpp AbstractFactoryPattern/product.h AbstractFactoryPattern/concrete_product.h AbstractFactoryPattern/Factory.cpp AbstractFactoryPattern/Factory.h AbstractFactoryPattern/concrete_factory.h AbstractFactoryPattern/FactoryMain.cpp AbstractFactoryPattern/FactoryMain.h SingletonPattern/Singleton.cpp SingletonPattern/Singleton.h SingletonPattern/SingletonMain.h AdapterPattern/target.h AdapterPattern/adaptee.h AdapterPattern/adapter.h AdapterPattern/AdapterMain.h BridgePattern/implementor.h BridgePattern/concrete_implementor.h BridgePattern/abstraction.h BridgePattern/refined_abstraction.h BridgePattern/BridgeMain.h BridgePattern/BridgeMain.cpp ObserverPattern/subject.h ObserverPattern/observer.h ObserverPattern/concrete_subject.h ObserverPattern/concrete_observer.h ObserverPattern/ObserverMain.cpp ObserverPattern/ObserverMain.h) -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/ObserverMain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #include "ObserverMain.h" 6 | 7 | void ObserverMain() 8 | { 9 | // Create Subject 10 | ConcreteSubject * pSubject = new ConcreteSubject(); 11 | 12 | // Create Observer 13 | IObserver * pObserver1 = new ConcreteObserver("Jack Ma"); 14 | IObserver * pObserver2 = new ConcreteObserver("Pony"); 15 | 16 | // Attach Observers 17 | pSubject->Attach(pObserver1); 18 | pSubject->Attach(pObserver2); 19 | 20 | // Change the price and notify the observer 21 | pSubject->SetPrice(12.5); 22 | pSubject->Notify(); 23 | 24 | // Detach Observers 25 | pSubject->Detach(pObserver2); 26 | 27 | // Change the state again and notify the observer 28 | pSubject->SetPrice(15.0); 29 | pSubject->Notify(); 30 | 31 | SAFE_DELETE(pObserver1); 32 | SAFE_DELETE(pObserver2); 33 | SAFE_DELETE(pSubject); 34 | } -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/ObserverMain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_OBSERVERMAIN_H 6 | #define DESIGNPATTERN_OBSERVERMAIN_H 7 | 8 | #include "concrete_subject.h" 9 | #include "concrete_observer.h" 10 | 11 | #ifndef SAFE_DELETE 12 | #define SAFE_DELETE(p) { if(p){delete(p); (p)=nullptr;} } 13 | #endif 14 | 15 | void ObserverMain(); 16 | 17 | #endif //DESIGNPATTERN_OBSERVERMAIN_H 18 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/concrete_observer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_CONCRETE_OBSERVER_H 6 | #define DESIGNPATTERN_CONCRETE_OBSERVER_H 7 | 8 | #include "observer.h" 9 | #include 10 | #include 11 | 12 | class ConcreteObserver : public IObserver 13 | { 14 | public: 15 | ConcreteObserver(std::string name) { m_strName = name; } 16 | void Update(float price) 17 | { 18 | std::cout << m_strName << " - price" << price << "\n"; 19 | } 20 | 21 | private: 22 | std::string m_strName; // name 23 | }; 24 | 25 | #endif //DESIGNPATTERN_CONCRETE_OBSERVER_H 26 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/concrete_subject.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_CONCRETE_SUBJECT_H 6 | #define DESIGNPATTERN_CONCRETE_SUBJECT_H 7 | 8 | #include "subject.h" 9 | #include "observer.h" 10 | #include 11 | #include 12 | 13 | // Specific Subject 14 | class ConcreteSubject : public ISubject 15 | { 16 | public: 17 | ConcreteSubject(){ m_fPrice = 10.0; } 18 | void SetPrice(float price) 19 | { 20 | m_fPrice = price; 21 | } 22 | void Attach(IObserver * observer) 23 | { 24 | m_observers.push_back(observer); 25 | } 26 | void Detach(IObserver * observer) 27 | { 28 | m_observers.remove(observer); 29 | } 30 | // Notify all observers 31 | void Notify() 32 | { 33 | std::list::iterator it = m_observers.begin(); 34 | while (it != m_observers.end()) 35 | { 36 | (*it)->Update(m_fPrice); 37 | ++it; 38 | } 39 | } 40 | private: 41 | std::list m_observers; // Observer list 42 | float m_fPrice; // Price 43 | }; 44 | 45 | #endif //DESIGNPATTERN_CONCRETE_SUBJECT_H 46 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/observer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_OBSERVER_H 6 | #define DESIGNPATTERN_OBSERVER_H 7 | 8 | // Abstract observer 9 | class IObserver 10 | { 11 | public: 12 | virtual void Update(float price) = 0; // Update price 13 | }; 14 | 15 | #endif //DESIGNPATTERN_OBSERVER_H 16 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/subject.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/21. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_SUBJECT_H 6 | #define DESIGNPATTERN_SUBJECT_H 7 | 8 | class IObserver; 9 | 10 | class ISubject 11 | { 12 | public: 13 | virtual void Attach(IObserver *) = 0; // Attach observer 14 | virtual void Detach(IObserver *) = 0; // Detach observer 15 | virtual void Notify() = 0; // Notify observer 16 | }; 17 | 18 | #endif //DESIGNPATTERN_SUBJECT_H 19 | -------------------------------------------------------------------------------- /DesignPattern/README.md: -------------------------------------------------------------------------------- 1 | # 设计模式 2 | 3 | > 各大设计模式例子参考:[CSDN专栏 . C++ 设计模式](https://blog.csdn.net/liang19890820/article/details/66974516) 系列博文 4 | 5 | 此文件夹为一个 CLion 工程,由 CMake 构建,各个文件夹为各个设计模式的具体实现。文件中可能会有中文乱码问题,请以 `GB2312`(中文) 编码打开。 6 | 7 | * [单例模式例子](SingletonPattern) 8 | * [抽象工厂模式例子](AbstractFactoryPattern) 9 | * [适配器模式例子](AdapterPattern) 10 | * [桥接模式例子](BridgePattern) 11 | * [观察者模式例子](ObserverPattern) -------------------------------------------------------------------------------- /DesignPattern/SingletonPattern/README.md: -------------------------------------------------------------------------------- 1 | # 单例模式 2 | 3 | ```cpp 4 | // 懒汉式单例模式 5 | class Singleton 6 | { 7 | private: 8 | Singleton() { } 9 | static Singleton * pInstance; 10 | public: 11 | static Singleton * GetInstance() 12 | { 13 | if (pInstance == nullptr) 14 | pInstance = new Singleton(); 15 | return pInstance; 16 | } 17 | }; 18 | 19 | // 线程安全的单例模式 20 | class Singleton 21 | { 22 | private: 23 | Singleton() { } 24 | ~Singleton() { } 25 | Singleton(const Singleton &); 26 | Singleton & operator = (const Singleton &); 27 | public: 28 | static Singleton & GetInstance() 29 | { 30 | static Singleton instance; 31 | return instance; 32 | } 33 | }; 34 | ``` -------------------------------------------------------------------------------- /DesignPattern/SingletonPattern/Singleton.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #include 6 | #include "Singleton.h" 7 | 8 | void Singleton::DoSomething() 9 | { 10 | std::cout << "Singleton do something\n"; 11 | } -------------------------------------------------------------------------------- /DesignPattern/SingletonPattern/Singleton.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_SINGLETON_H 6 | #define DESIGNPATTERN_SINGLETON_H 7 | 8 | // Singleton mode 9 | class Singleton { 10 | private: 11 | Singleton(){} 12 | ~Singleton(){} 13 | Singleton(const Singleton &); 14 | Singleton & operator= (const Singleton &); 15 | 16 | public: 17 | static Singleton & GetInstance() 18 | { 19 | static Singleton instance; 20 | return instance; 21 | } 22 | void DoSomething(); 23 | }; 24 | 25 | #endif //DESIGNPATTERN_SINGLETON_H 26 | -------------------------------------------------------------------------------- /DesignPattern/SingletonPattern/SingletonMain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #ifndef DESIGNPATTERN_SINGLETONMAIN_H 6 | #define DESIGNPATTERN_SINGLETONMAIN_H 7 | 8 | #include "Singleton.h" 9 | 10 | void SingletonMain() 11 | { 12 | Singleton::GetInstance().DoSomething(); 13 | } 14 | 15 | #endif //DESIGNPATTERN_SINGLETONMAIN_H 16 | -------------------------------------------------------------------------------- /DesignPattern/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xiemenghui on 2018/7/20. 3 | // 4 | 5 | #include 6 | #include "SingletonPattern/SingletonMain.h" 7 | #include "AbstractFactoryPattern/FactoryMain.h" 8 | #include "AdapterPattern/AdapterMain.h" 9 | #include "BridgePattern/BridgeMain.h" 10 | #include "ObserverPattern/ObserverMain.h" 11 | 12 | int main() { 13 | std::cout << "*******************" << std::endl; 14 | std::cout << "** Design pattern example **" << std::endl; 15 | std::cout << "*******************" << std::endl; 16 | 17 | std::cout << "*******************" << std::endl; 18 | std::cout << "** Singleton mode **" << std::endl; 19 | std::cout << "*******************" << std::endl; 20 | SingletonMain(); 21 | 22 | std::cout << "*******************" << std::endl; 23 | std::cout << "** Abstract factory pattern **" << std::endl; 24 | std::cout << "*******************" << std::endl; 25 | FactoryMain(); 26 | 27 | std::cout << "*******************" << std::endl; 28 | std::cout << "** Adapter mode **" << std::endl; 29 | std::cout << "*******************" << std::endl; 30 | AdapterMain(); 31 | 32 | std::cout << "*******************" << std::endl; 33 | std::cout << "** Bridge mode **" << std::endl; 34 | std::cout << "*******************" << std::endl; 35 | BridgeMain(); 36 | 37 | std::cout << "*******************" << std::endl; 38 | std::cout << "** Observer mode **" << std::endl; 39 | std::cout << "*******************" << std::endl; 40 | ObserverMain(); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International 2 | Public License 3 | 4 | By exercising the Licensed Rights (defined below), You accept and agree 5 | to be bound by the terms and conditions of this Creative Commons 6 | Attribution-NonCommercial-ShareAlike 4.0 International Public License 7 | ("Public License"). To the extent this Public License may be 8 | interpreted as a contract, You are granted the Licensed Rights in 9 | consideration of Your acceptance of these terms and conditions, and the 10 | Licensor grants You such rights in consideration of benefits the 11 | Licensor receives from making the Licensed Material available under 12 | these terms and conditions. 13 | 14 | 15 | Section 1 -- Definitions. 16 | 17 | a. Adapted Material means material subject to Copyright and Similar 18 | Rights that is derived from or based upon the Licensed Material 19 | and in which the Licensed Material is translated, altered, 20 | arranged, transformed, or otherwise modified in a manner requiring 21 | permission under the Copyright and Similar Rights held by the 22 | Licensor. For purposes of this Public License, where the Licensed 23 | Material is a musical work, performance, or sound recording, 24 | Adapted Material is always produced where the Licensed Material is 25 | synched in timed relation with a moving image. 26 | 27 | b. Adapter's License means the license You apply to Your Copyright 28 | and Similar Rights in Your contributions to Adapted Material in 29 | accordance with the terms and conditions of this Public License. 30 | 31 | c. BY-NC-SA Compatible License means a license listed at 32 | creativecommons.org/compatiblelicenses, approved by Creative 33 | Commons as essentially the equivalent of this Public License. 34 | 35 | d. Copyright and Similar Rights means copyright and/or similar rights 36 | closely related to copyright including, without limitation, 37 | performance, broadcast, sound recording, and Sui Generis Database 38 | Rights, without regard to how the rights are labeled or 39 | categorized. For purposes of this Public License, the rights 40 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 41 | Rights. 42 | 43 | e. Effective Technological Measures means those measures that, in the 44 | absence of proper authority, may not be circumvented under laws 45 | fulfilling obligations under Article 11 of the WIPO Copyright 46 | Treaty adopted on December 20, 1996, and/or similar international 47 | agreements. 48 | 49 | f. Exceptions and Limitations means fair use, fair dealing, and/or 50 | any other exception or limitation to Copyright and Similar Rights 51 | that applies to Your use of the Licensed Material. 52 | 53 | g. License Elements means the license attributes listed in the name 54 | of a Creative Commons Public License. The License Elements of this 55 | Public License are Attribution, NonCommercial, and ShareAlike. 56 | 57 | h. Licensed Material means the artistic or literary work, database, 58 | or other material to which the Licensor applied this Public 59 | License. 60 | 61 | i. Licensed Rights means the rights granted to You subject to the 62 | terms and conditions of this Public License, which are limited to 63 | all Copyright and Similar Rights that apply to Your use of the 64 | Licensed Material and that the Licensor has authority to license. 65 | 66 | j. Licensor means the individual(s) or entity(ies) granting rights 67 | under this Public License. 68 | 69 | k. NonCommercial means not primarily intended for or directed towards 70 | commercial advantage or monetary compensation. For purposes of 71 | this Public License, the exchange of the Licensed Material for 72 | other material subject to Copyright and Similar Rights by digital 73 | file-sharing or similar means is NonCommercial provided there is 74 | no payment of monetary compensation in connection with the 75 | exchange. 76 | 77 | l. Share means to provide material to the public by any means or 78 | process that requires permission under the Licensed Rights, such 79 | as reproduction, public display, public performance, distribution, 80 | dissemination, communication, or importation, and to make material 81 | available to the public including in ways that members of the 82 | public may access the material from a place and at a time 83 | individually chosen by them. 84 | 85 | m. Sui Generis Database Rights means rights other than copyright 86 | resulting from Directive 96/9/EC of the European Parliament and of 87 | the Council of 11 March 1996 on the legal protection of databases, 88 | as amended and/or succeeded, as well as other essentially 89 | equivalent rights anywhere in the world. 90 | 91 | n. You means the individual or entity exercising the Licensed Rights 92 | under this Public License. Your has a corresponding meaning. 93 | 94 | 95 | Section 2 -- Scope. 96 | 97 | a. License grant. 98 | 99 | 1. Subject to the terms and conditions of this Public License, 100 | the Licensor hereby grants You a worldwide, royalty-free, 101 | non-sublicensable, non-exclusive, irrevocable license to 102 | exercise the Licensed Rights in the Licensed Material to: 103 | 104 | a. reproduce and Share the Licensed Material, in whole or 105 | in part, for NonCommercial purposes only; and 106 | 107 | b. produce, reproduce, and Share Adapted Material for 108 | NonCommercial purposes only. 109 | 110 | 2. Exceptions and Limitations. For the avoidance of doubt, where 111 | Exceptions and Limitations apply to Your use, this Public 112 | License does not apply, and You do not need to comply with 113 | its terms and conditions. 114 | 115 | 3. Term. The term of this Public License is specified in Section 116 | 6(a). 117 | 118 | 4. Media and formats; technical modifications allowed. The 119 | Licensor authorizes You to exercise the Licensed Rights in 120 | all media and formats whether now known or hereafter created, 121 | and to make technical modifications necessary to do so. The 122 | Licensor waives and/or agrees not to assert any right or 123 | authority to forbid You from making technical modifications 124 | necessary to exercise the Licensed Rights, including 125 | technical modifications necessary to circumvent Effective 126 | Technological Measures. For purposes of this Public License, 127 | simply making modifications authorized by this Section 2(a) 128 | (4) never produces Adapted Material. 129 | 130 | 5. Downstream recipients. 131 | 132 | a. Offer from the Licensor -- Licensed Material. Every 133 | recipient of the Licensed Material automatically 134 | receives an offer from the Licensor to exercise the 135 | Licensed Rights under the terms and conditions of this 136 | Public License. 137 | 138 | b. Additional offer from the Licensor -- Adapted Material. 139 | Every recipient of Adapted Material from You 140 | automatically receives an offer from the Licensor to 141 | exercise the Licensed Rights in the Adapted Material 142 | under the conditions of the Adapter's License You apply. 143 | 144 | c. No downstream restrictions. You may not offer or impose 145 | any additional or different terms or conditions on, or 146 | apply any Effective Technological Measures to, the 147 | Licensed Material if doing so restricts exercise of the 148 | Licensed Rights by any recipient of the Licensed 149 | Material. 150 | 151 | 6. No endorsement. Nothing in this Public License constitutes or 152 | may be construed as permission to assert or imply that You 153 | are, or that Your use of the Licensed Material is, connected 154 | with, or sponsored, endorsed, or granted official status by, 155 | the Licensor or others designated to receive attribution as 156 | provided in Section 3(a)(1)(A)(i). 157 | 158 | b. Other rights. 159 | 160 | 1. Moral rights, such as the right of integrity, are not 161 | licensed under this Public License, nor are publicity, 162 | privacy, and/or other similar personality rights; however, to 163 | the extent possible, the Licensor waives and/or agrees not to 164 | assert any such rights held by the Licensor to the limited 165 | extent necessary to allow You to exercise the Licensed 166 | Rights, but not otherwise. 167 | 168 | 2. Patent and trademark rights are not licensed under this 169 | Public License. 170 | 171 | 3. To the extent possible, the Licensor waives any right to 172 | collect royalties from You for the exercise of the Licensed 173 | Rights, whether directly or through a collecting society 174 | under any voluntary or waivable statutory or compulsory 175 | licensing scheme. In all other cases the Licensor expressly 176 | reserves any right to collect such royalties, including when 177 | the Licensed Material is used other than for NonCommercial 178 | purposes. 179 | 180 | 181 | Section 3 -- License Conditions. 182 | 183 | Your exercise of the Licensed Rights is expressly made subject to the 184 | following conditions. 185 | 186 | a. Attribution. 187 | 188 | 1. If You Share the Licensed Material (including in modified 189 | form), You must: 190 | 191 | a. retain the following if it is supplied by the Licensor 192 | with the Licensed Material: 193 | 194 | i. identification of the creator(s) of the Licensed 195 | Material and any others designated to receive 196 | attribution, in any reasonable manner requested by 197 | the Licensor (including by pseudonym if 198 | designated); 199 | 200 | ii. a copyright notice; 201 | 202 | iii. a notice that refers to this Public License; 203 | 204 | iv. a notice that refers to the disclaimer of 205 | warranties; 206 | 207 | v. a URI or hyperlink to the Licensed Material to the 208 | extent reasonably practicable; 209 | 210 | b. indicate if You modified the Licensed Material and 211 | retain an indication of any previous modifications; and 212 | 213 | c. indicate the Licensed Material is licensed under this 214 | Public License, and include the text of, or the URI or 215 | hyperlink to, this Public License. 216 | 217 | 2. You may satisfy the conditions in Section 3(a)(1) in any 218 | reasonable manner based on the medium, means, and context in 219 | which You Share the Licensed Material. For example, it may be 220 | reasonable to satisfy the conditions by providing a URI or 221 | hyperlink to a resource that includes the required 222 | information. 223 | 3. If requested by the Licensor, You must remove any of the 224 | information required by Section 3(a)(1)(A) to the extent 225 | reasonably practicable. 226 | 227 | b. ShareAlike. 228 | 229 | In addition to the conditions in Section 3(a), if You Share 230 | Adapted Material You produce, the following conditions also apply. 231 | 232 | 1. The Adapter's License You apply must be a Creative Commons 233 | license with the same License Elements, this version or 234 | later, or a BY-NC-SA Compatible License. 235 | 236 | 2. You must include the text of, or the URI or hyperlink to, the 237 | Adapter's License You apply. You may satisfy this condition 238 | in any reasonable manner based on the medium, means, and 239 | context in which You Share Adapted Material. 240 | 241 | 3. You may not offer or impose any additional or different terms 242 | or conditions on, or apply any Effective Technological 243 | Measures to, Adapted Material that restrict exercise of the 244 | rights granted under the Adapter's License You apply. 245 | 246 | 247 | Section 4 -- Sui Generis Database Rights. 248 | 249 | Where the Licensed Rights include Sui Generis Database Rights that 250 | apply to Your use of the Licensed Material: 251 | 252 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 253 | to extract, reuse, reproduce, and Share all or a substantial 254 | portion of the contents of the database for NonCommercial purposes 255 | only; 256 | 257 | b. if You include all or a substantial portion of the database 258 | contents in a database in which You have Sui Generis Database 259 | Rights, then the database in which You have Sui Generis Database 260 | Rights (but not its individual contents) is Adapted Material, 261 | including for purposes of Section 3(b); and 262 | 263 | c. You must comply with the conditions in Section 3(a) if You Share 264 | all or a substantial portion of the contents of the database. 265 | 266 | For the avoidance of doubt, this Section 4 supplements and does not 267 | replace Your obligations under this Public License where the Licensed 268 | Rights include other Copyright and Similar Rights. 269 | 270 | 271 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 272 | 273 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 274 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 275 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 276 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 277 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 278 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 279 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 280 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 281 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 282 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 283 | 284 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 285 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 286 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 287 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 288 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 289 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 290 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 291 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 292 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 293 | 294 | c. The disclaimer of warranties and limitation of liability provided 295 | above shall be interpreted in a manner that, to the extent 296 | possible, most closely approximates an absolute disclaimer and 297 | waiver of all liability. 298 | 299 | 300 | Section 6 -- Term and Termination. 301 | 302 | a. This Public License applies for the term of the Copyright and 303 | Similar Rights licensed here. However, if You fail to comply with 304 | this Public License, then Your rights under this Public License 305 | terminate automatically. 306 | 307 | b. Where Your right to use the Licensed Material has terminated under 308 | Section 6(a), it reinstates: 309 | 310 | 1. automatically as of the date the violation is cured, provided 311 | it is cured within 30 days of Your discovery of the 312 | violation; or 313 | 314 | 2. upon express reinstatement by the Licensor. 315 | 316 | For the avoidance of doubt, this Section 6(b) does not affect any 317 | right the Licensor may have to seek remedies for Your violations 318 | of this Public License. 319 | 320 | c. For the avoidance of doubt, the Licensor may also offer the 321 | Licensed Material under separate terms or conditions or stop 322 | distributing the Licensed Material at any time; however, doing so 323 | will not terminate this Public License. 324 | 325 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 326 | License. 327 | 328 | 329 | Section 7 -- Other Terms and Conditions. 330 | 331 | a. The Licensor shall not be bound by any additional or different 332 | terms or conditions communicated by You unless expressly agreed. 333 | 334 | b. Any arrangements, understandings, or agreements regarding the 335 | Licensed Material not stated herein are separate from and 336 | independent of the terms and conditions of this Public License. 337 | 338 | 339 | Section 8 -- Interpretation. 340 | 341 | a. For the avoidance of doubt, this Public License does not, and 342 | shall not be interpreted to, reduce, limit, restrict, or impose 343 | conditions on any use of the Licensed Material that could lawfully 344 | be made without permission under this Public License. 345 | 346 | b. To the extent possible, if any provision of this Public License is 347 | deemed unenforceable, it shall be automatically reformed to the 348 | minimum extent necessary to make it enforceable. If the provision 349 | cannot be reformed, it shall be severed from this Public License 350 | without affecting the enforceability of the remaining terms and 351 | conditions. 352 | 353 | c. No term or condition of this Public License will be waived and no 354 | failure to comply consented to unless expressly agreed to by the 355 | Licensor. 356 | 357 | d. Nothing in this Public License constitutes or may be interpreted 358 | as a limitation upon, or waiver of, any privileges and immunities 359 | that apply to the Licensor or You, including from the legal 360 | processes of any jurisdiction or authority. -------------------------------------------------------------------------------- /Problems/ChessboardCoverageProblem/ChessboardCoverage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int num_Now = 0; // 记录L型骨牌编号 8 | int **board = NULL; // 棋盘指针 9 | 10 | // 函数声明 11 | void ChessBoard(int num_BoardTopLeftRow, int num_BoardTopLeftColumn, int num_SpecialRow, int num_SpecialColumn, int boardSize); 12 | 13 | int main() { 14 | 15 | int num_BoardTopLeftRow = 0, // 棋盘左上角的行号 16 | num_BoardTopLeftColumn = 0, // 棋盘左上角的列号 17 | num_SpecialRow = 0, // 特殊方格所在的行号 18 | num_SpecialColumn = 0, // 特殊方格所在的列号 19 | boardSize = 0, // 棋盘大小 20 | k = 0; // 构成的(2^k)*(2^k)个方格的棋盘 21 | 22 | // 用户界面 23 | cout << "---------------- 棋盘覆盖问题 ----------------" << endl; 24 | cout << "请输入k(k>=0),构成(2^k)*(2^k)个方格的棋盘" << endl; 25 | 26 | // 输入k值 27 | cin >> k; 28 | 29 | // 判断输入数据合法性,包括检查输入是否为数字,k值是否大于0 30 | if (cin.fail() || k < 0) 31 | { 32 | cout << "输入k错误!" << endl; 33 | system("pause"); 34 | return 0; 35 | } 36 | 37 | // 计算棋盘大小 38 | boardSize = pow(2, k); 39 | 40 | cout << "请输入特殊方格所在的行号和列号(从0开始,用空格隔开)" << endl; 41 | 42 | // 输入特殊方格所在的行号和列号 43 | cin >> num_SpecialRow >> num_SpecialColumn; 44 | 45 | // 判断输入数据合法性,包括检查输入是否为数字,特殊方格行号列号是否大于0,特殊方格行号列号是否不大于棋盘大小 46 | if (cin.fail() || num_SpecialRow < 0 || num_SpecialColumn < 0 || num_SpecialRow >= boardSize || num_SpecialColumn >= boardSize) 47 | { 48 | cout << "输入行号或列号错误!" << endl; 49 | system("pause"); 50 | return 0; 51 | } 52 | 53 | // 分配棋盘空间 54 | board = new int *[boardSize]; 55 | for (auto i = 0; i < boardSize; i++) 56 | { 57 | board[i] = new int[boardSize]; 58 | } 59 | 60 | // 为特殊方格赋初值0 61 | board[num_SpecialRow][num_SpecialColumn] = 0; 62 | 63 | //执行棋盘覆盖函数 64 | ChessBoard(num_BoardTopLeftRow, num_BoardTopLeftColumn, num_SpecialRow, num_SpecialColumn, boardSize); 65 | 66 | // 显示输出 67 | cout << "------------------------------------------------" << endl; 68 | for (auto i = 0; i < boardSize; i++) 69 | { 70 | for (auto j = 0; j < boardSize; j++) 71 | { 72 | cout << board[i][j] << "\t"; 73 | } 74 | cout << endl; 75 | } 76 | cout << "------------------------------------------------" << endl; 77 | 78 | // 暂停查看结果 79 | system("pause"); 80 | 81 | // 释放内存 82 | for (int i = 0; i <= boardSize; i++) 83 | delete[] board[i]; 84 | delete[] board; 85 | 86 | // 指针置空 87 | board = NULL; 88 | 89 | return 0; 90 | } 91 | 92 | // 棋盘覆盖函数 93 | void ChessBoard(int num_BoardTopLeftRow, int num_BoardTopLeftColumn, int num_SpecialRow, int num_SpecialColumn, int boardSize) 94 | { 95 | // 棋盘大小为1则直接返回 96 | if (boardSize == 1) return; 97 | 98 | int num = ++num_Now, // L型骨牌编号 99 | size = boardSize / 2; // 分割棋盘,行列各一分为二 100 | 101 | // 覆盖左上角子棋盘 102 | if (num_SpecialRow < num_BoardTopLeftRow + size && num_SpecialColumn < num_BoardTopLeftColumn + size) 103 | { 104 | // 递归覆盖含有特殊方格的子棋盘 105 | ChessBoard(num_BoardTopLeftRow, num_BoardTopLeftColumn, num_SpecialRow, num_SpecialColumn, size); 106 | } 107 | else 108 | { 109 | // 用编号为num的L型骨牌覆盖右下角 110 | board[num_BoardTopLeftRow + size - 1][num_BoardTopLeftColumn + size - 1] = num; 111 | 112 | // 递归覆盖其余棋盘 113 | ChessBoard(num_BoardTopLeftRow, num_BoardTopLeftColumn, num_BoardTopLeftRow + size - 1, num_BoardTopLeftColumn + size - 1, size); 114 | } 115 | 116 | // 覆盖右上角子棋盘 117 | if (num_SpecialRow < num_BoardTopLeftRow + size && num_SpecialColumn >= num_BoardTopLeftColumn + size) 118 | { 119 | // 递归覆盖含有特殊方格的子棋盘 120 | ChessBoard(num_BoardTopLeftRow, num_BoardTopLeftColumn + size, num_SpecialRow, num_SpecialColumn, size); 121 | } 122 | else 123 | { 124 | // 用编号为num的L型骨牌覆盖左下角 125 | board[num_BoardTopLeftRow + size - 1][num_BoardTopLeftColumn + size] = num; 126 | 127 | // 递归覆盖其余棋盘 128 | ChessBoard(num_BoardTopLeftRow, num_BoardTopLeftColumn + size, num_BoardTopLeftRow + size - 1, num_BoardTopLeftColumn + size, size); 129 | } 130 | 131 | // 覆盖左下角子棋盘 132 | if (num_SpecialRow >= num_BoardTopLeftRow + size && num_SpecialColumn < num_BoardTopLeftColumn + size) 133 | { 134 | // 递归覆盖含有特殊方格的子棋盘 135 | ChessBoard(num_BoardTopLeftRow + size, num_BoardTopLeftColumn, num_SpecialRow, num_SpecialColumn, size); 136 | } 137 | else 138 | { 139 | // 用编号为num的L型骨牌覆盖右上角 140 | board[num_BoardTopLeftRow + size][num_BoardTopLeftColumn + size - 1] = num; 141 | 142 | // 递归覆盖其余棋盘 143 | ChessBoard(num_BoardTopLeftRow + size, num_BoardTopLeftColumn, num_BoardTopLeftRow + size, num_BoardTopLeftColumn + size - 1, size); 144 | } 145 | 146 | // 覆盖右下角子棋盘 147 | if (num_SpecialRow >= num_BoardTopLeftRow + size && num_SpecialColumn >= num_BoardTopLeftColumn + size) 148 | { 149 | // 递归覆盖含有特殊方格的子棋盘 150 | ChessBoard(num_BoardTopLeftRow + size, num_BoardTopLeftColumn + size, num_SpecialRow, num_SpecialColumn, size); 151 | } 152 | else 153 | { 154 | // 用编号为num的L型骨牌覆盖左上角 155 | board[num_BoardTopLeftRow + size][num_BoardTopLeftColumn + size] = num; 156 | 157 | // 递归覆盖其余棋盘 158 | ChessBoard(num_BoardTopLeftRow + size, num_BoardTopLeftColumn + size, num_BoardTopLeftRow + size, num_BoardTopLeftColumn + size, size); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Problems/ChessboardCoverageProblem/ChessboardCoverage.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/Problems/ChessboardCoverageProblem/ChessboardCoverage.exe -------------------------------------------------------------------------------- /Problems/ChessboardCoverageProblem/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 棋盘覆盖问题 3 | 4 | ### 代码 5 | 6 | [棋盘覆盖问题代码](ChessboardCoverage.cpp) 7 | 8 | ### 问题说明 9 | 10 | 在一个2^k * 2^k个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格。 11 | 12 | 棋盘覆盖问题就是要用图示的4种不同形态的L型骨牌覆盖给定棋盘上除特殊方格之外的所有方格,且任何2个L型骨牌不得重叠覆盖。 13 | 14 | ![](http://blog.chinaunix.net/attachment/201303/1/26548237_1362125215RWwI.png) 15 | 16 | ### 功能说明 17 | 18 | 本程序用分治法的思想解决了棋盘覆盖问题,显示输出 19 | 20 | ### 代码简述 21 | 22 | 用户输入数据,程序输入检测,动态分配空间,调用棋盘覆盖函数,把计算结果存储到board(二维数组指针),显示输出。 23 | 24 | 其中棋盘覆盖函数用分治的思想把棋盘分成四份,递归求解。 -------------------------------------------------------------------------------- /Problems/KnapsackProblem/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 背包问题 3 | 4 | ### 代码 5 | 6 | [背包问题代码](pack.cpp) 7 | 8 | ### 问题说明 9 | 10 | 有N件物品和一个容量为V的背包。 11 | 12 | 第i件物品的重量是w[i],价值是v[i]。 13 | 14 | 求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量, 15 | 16 | 且价值总和最大。 17 | 18 | ### 功能说明 19 | 20 | 本程序用动态规划的思想解决了背包问题,并用了两种算法: 21 | 迭代法、递归法。在迭代法中实现了打印背包问题的表格。 22 | 23 | ### 代码简述 24 | 25 | 通过用户输入数据,程序输入检测,动态分配空间,选择算法, 26 | 用动态规划的思想求解背包问题。 27 | 28 | #### 迭代法: 29 | 通过遍历n行W列,迭代每行每列的值,并把最优解放到 30 | n行(在数组中为第n+1行)W列(在数组中为第W+1列)中。 31 | 32 | #### 递归法: 33 | 通过每次返回前i个物品和承重为j的最优解, 34 | 递归计算总背包问题的最优解。 35 | -------------------------------------------------------------------------------- /Problems/KnapsackProblem/pack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int **T = NULL; // 存储背包问题表格的数组指针 6 | 7 | // 返回两个值的最大值 8 | int max(int a, int b) { 9 | return (a > b) ? a : b; 10 | } 11 | 12 | // 迭代法,能显示背包问题的表格 13 | int packIterative(int n, int W, int *w, int *v) { 14 | 15 | // 循环遍历n行 16 | for (int i = 1; i <= n; ++i) 17 | { 18 | // 循环遍历W列 19 | for (int j = 1; j <= W; ++j) 20 | { 21 | //第i个物品能装下,则比较包括第i个物品和不包括第i个物品,取其最大值 22 | if (w[i] <= j) 23 | T[i][j] = max(v[i] + T[i - 1][j - w[i]], T[i - 1][j]); 24 | 25 | // 第i个物品不能装下,则递归装i-1个 26 | else 27 | T[i][j] = T[i - 1][j]; 28 | } 29 | } 30 | return T[n][W]; 31 | } 32 | 33 | // 递归法,不支持显示背包问题的表格 34 | int packRecursive(int n, int W, int *w, int *v) { 35 | // 结束条件(初始条件),i或者j为0时最大总价值为0 36 | if (n == 0 || W == 0) { 37 | return 0; 38 | } 39 | // 第i个物品不能装下,则递归装i-1个 40 | if (w[n] > W) { 41 | return packRecursive(n - 1, W, w, v); 42 | } 43 | //第i个物品能装下,则比较包括第i个物品和不包括第i个物品,取其最大值 44 | else { 45 | return max(v[n] + packRecursive(n - 1, W - w[n], w, v), packRecursive(n - 1, W, w, v)); 46 | } 47 | } 48 | 49 | // 打印背包问题的表格 50 | void printT(int n, int W) 51 | { 52 | // 打印n行 53 | for (auto i = 0; i <= n; i++) 54 | { 55 | // 打印行数 56 | cout << i << ":\t"; 57 | 58 | // 打印W列 59 | for (int w = 0; w <= W; w++) 60 | { 61 | cout << T[i][w] << "\t"; 62 | } 63 | 64 | // 换行 65 | cout << endl; 66 | } 67 | } 68 | 69 | int main() { 70 | int *w = NULL; // 存储每件物品重量的数组指针 71 | int *v = NULL; // 存储每件物品价值的数组指针 72 | int n; // 物品个数n 73 | int W; // 背包总承重W 74 | 75 | cout << "---------------- 背包问题 ----------------" << endl; 76 | cout << "请输入物品数 n (n>=0) " << endl; 77 | 78 | // 输入背包数 79 | cin >> n; 80 | 81 | if (cin.fail() || n < 0) 82 | { 83 | cout << "输入n错误!" << endl; 84 | system("pause"); 85 | return 0; 86 | } 87 | 88 | cout << "请输入背包承重量 W (W>=0) " << endl; 89 | 90 | // 输入背包承重量 91 | cin >> W; 92 | 93 | if (cin.fail() || W < 0) 94 | { 95 | cout << "输入W错误!" << endl; 96 | system("pause"); 97 | return 0; 98 | } 99 | 100 | // 分配空间 101 | // 对w和v分配n+1大小 102 | w = new int[n + 1]; 103 | v = new int[n + 1]; 104 | 105 | // 对T分配n+1行,并初始化为0 106 | T = new int *[n + 1](); 107 | // 对T分配W+1列,并初始化为0 108 | for (auto i = 0; i <= n; i++) 109 | { 110 | T[i] = new int[W + 1](); 111 | } 112 | 113 | // 输入背包的重量和价值 114 | for (auto i = 1; i <= n; i++) 115 | { 116 | cout << "请输入第 " << i << " 个物品的重量和价值(用空格隔开)" << endl; 117 | cin >> w[i] >> v[i]; 118 | if (cin.fail() || w[i] < 0 || v[i] < 0) 119 | { 120 | cout << "输入错误!" << endl; 121 | system("pause"); 122 | return 0; 123 | } 124 | } 125 | 126 | cout << "------------------------------------------------" << endl; 127 | cout << "请选择算法:" << endl; 128 | cout << "【1】迭代法" << endl; 129 | cout << "【2】递归法" << endl; 130 | cout << "------------------------------------------------" << endl; 131 | 132 | int choose; 133 | 134 | // 输入算法的选择 135 | cin >> choose; 136 | switch (choose) 137 | { 138 | case 1: 139 | { 140 | // 迭代法,能显示背包问题的表格 141 | cout << "能装下物品的最大价值为 " << packIterative(n, W, w, v) << endl; 142 | cout << "------------------------------------------------" << endl; 143 | printT(n, W); 144 | break; 145 | } 146 | case 2: 147 | { 148 | // 递归法,不支持显示背包问题的表格 149 | cout << "能装下物品的最大价值为 " << packRecursive(n, W, w, v) << endl; 150 | break; 151 | } 152 | default: 153 | { 154 | cout << "输入错误!" << endl; 155 | break; 156 | } 157 | } 158 | 159 | cout << "------------------------------------------------" << endl; 160 | 161 | delete w; 162 | delete v; 163 | for (int i = 0; i <= n; ++i) { 164 | delete[] T[i]; 165 | } 166 | delete[] T; 167 | 168 | system("pause"); 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /Problems/KnapsackProblem/pack.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/Problems/KnapsackProblem/pack.exe -------------------------------------------------------------------------------- /Problems/NeumannNeighborProblem/Formula/Neumann2_3_12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //通项法 4 | int Neumann2_3_12(int n) { 5 | 6 | //通项公式的求解请查看说明文档 7 | return 2 * n*n + 2 * n + 1; 8 | } 9 | 10 | int main() { 11 | int n = 0, a = 0; 12 | 13 | printf("------冯诺依曼邻居问题------\n"); 14 | printf("已知:\n"); 15 | printf(" 0 阶冯诺依曼邻居的元胞数为 1 \n"); 16 | printf(" 1 阶冯诺依曼邻居的元胞数为 5 \n"); 17 | printf(" 2 阶冯诺依曼邻居的元胞数为 13 \n"); 18 | printf("求:\n"); 19 | printf(" n 阶冯诺依曼邻居的元胞数\n"); 20 | printf("----------------------------\n"); 21 | printf("请输入n\n"); 22 | scanf("%d", &n); 23 | 24 | //用通项公式求解 25 | a = Neumann2_3_12(n); 26 | 27 | printf("------------通项法-------------\n"); 28 | printf(" %d 阶冯诺依曼邻居的元胞数为 %d\n", n, a); 29 | 30 | getchar(); 31 | getchar(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /Problems/NeumannNeighborProblem/Formula/Neumann2_3_12.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/Problems/NeumannNeighborProblem/Formula/Neumann2_3_12.exe -------------------------------------------------------------------------------- /Problems/NeumannNeighborProblem/Formula/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 冯诺依曼邻居问题(通项公式) 3 | 4 | ### 代码 5 | 6 | [冯诺依曼邻居问题(通项公式)代码](Neumann2_3_12.cpp) 7 | 8 | ### 问题说明 9 | 10 | 某算法从一个1×1的方格开始,每次都会在上次图形的周围再加上一圈方格,在第n次的时候要生成多少个方格?下图给出了n = 0,1,2是的结果。 11 | 12 | ![](https://huihut-img.oss-cn-shenzhen.aliyuncs.com/NeumannNeighborProblem.jpg) 13 | 14 | ### 功能说明 15 | 16 | 本程序使用通项公式求解。 17 | 18 | ### 代码简述 19 | 20 | 若设第n次生成的方格数是a(n),则: 21 | 22 | a(1) = a(0) + 4 * 1 23 | a(2) = a(1) + 4 * 2 24 | a(3) = a(2) + 4 * 3 25 | ... 26 | a(n) = a(n-1) + 4 * n 27 | 28 | 化简可得: 29 | 30 | a(n) - a(1) = 4 * (n + (n-1) + ... + 2 ) 31 | 32 | 即: 33 | 34 | a(n) = 2 * n*n + 2 * n + 1 35 | 36 | 则可得出a(n)的通项公式,即可用通项公式直接求解。 37 | 38 | 在程序中用Neumann2_3_12函数返回a(n)的值。 -------------------------------------------------------------------------------- /Problems/NeumannNeighborProblem/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 冯诺依曼邻居问题 3 | 4 | ### 问题说明 5 | 6 | 某算法从一个1×1的方格开始,每次都会在上次图形的周围再加上一圈方格,在第n次的时候要生成多少个方格?下图给出了n = 0,1,2是的结果。 7 | 8 | ![](https://huihut-img.oss-cn-shenzhen.aliyuncs.com/NeumannNeighborProblem.jpg) 9 | 10 | ### 解法 11 | 12 | * [通项公式解法](Formula) 13 | * [递推关系解法](Recursive) -------------------------------------------------------------------------------- /Problems/NeumannNeighborProblem/Recursive/Neumann2_4_12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //递归法 4 | int Neumann2_4_12(int n) { 5 | 6 | //由图可知第0次有1个方格 7 | if (n == 0) return 1; 8 | 9 | //递推关系的求解请查看说明文档 10 | return Neumann2_4_12(n - 1) + 4 * n; 11 | } 12 | 13 | int main() { 14 | int n = 0, a = 0; 15 | 16 | printf("------冯诺依曼邻居问题------\n"); 17 | printf("已知:\n"); 18 | printf(" 0 阶冯诺依曼邻居的元胞数为 1 \n"); 19 | printf(" 1 阶冯诺依曼邻居的元胞数为 5 \n"); 20 | printf(" 2 阶冯诺依曼邻居的元胞数为 13 \n"); 21 | printf("求:\n"); 22 | printf(" n 阶冯诺依曼邻居的元胞数\n"); 23 | printf("----------------------------\n"); 24 | printf("请输入n\n"); 25 | scanf("%d", &n); 26 | 27 | //建立递推关系,使用递归求解 28 | a = Neumann2_4_12(n); 29 | 30 | printf("------------通项法-------------\n"); 31 | printf(" %d 阶冯诺依曼邻居的元胞数为 %d\3n", n, a); 32 | 33 | getchar(); 34 | getchar(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /Problems/NeumannNeighborProblem/Recursive/Neumann2_4_12.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/Problems/NeumannNeighborProblem/Recursive/Neumann2_4_12.exe -------------------------------------------------------------------------------- /Problems/NeumannNeighborProblem/Recursive/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 冯诺依曼邻居问题(递推关系) 3 | 4 | ### 代码 5 | 6 | [冯诺依曼邻居问题(递推关系)代码](Neumann2_4_12.cpp) 7 | 8 | ### 问题说明 9 | 10 | 某算法从一个1×1的方格开始,每次都会在上次图形的周围再加上一圈方格,在第n次的时候要生成多少个方格?下图给出了n = 0,1,2是的结果。 11 | 12 | ![](https://huihut-img.oss-cn-shenzhen.aliyuncs.com/NeumannNeighborProblem.jpg) 13 | 14 | ### 功能说明 15 | 16 | 本程序使用递推关系求解。 17 | 18 | ### 代码简述 19 | 20 | 若设第n次生成的方格数是a(n),则: 21 | 22 | a(1) = a(0) + 4 * 1 23 | a(2) = a(1) + 4 * 2 24 | a(3) = a(2) + 4 * 3 25 | ... 26 | a(n) = a(n-1) + 4 * n 27 | 28 | 则可得: 29 | 30 | a(n) = a(n - 1) + 4 * n 31 | 32 | 然后在代码中使用递归法,递归结束条件为n = 0,即 33 | 34 | if (n == 0) return 1; 35 | 36 | 则可写出递归法的代码。 37 | 38 | 在程序中用Neumann2_4_12函数进行递归求解。 -------------------------------------------------------------------------------- /Problems/RoundRobinProblem/MatchTable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 循环赛日程安排函数声明 7 | void MatchTable(int k, int n, int **table); 8 | 9 | int main() 10 | { 11 | int n = 0, k = 0; 12 | 13 | // 用户界面 14 | cout << "---------------- 循环赛日程安排问题 ----------------" << endl; 15 | cout << "请输入k(k>=0),构成 n=(2^k) 个选手的循环赛" << endl; 16 | 17 | // 输入k值 18 | cin >> k; 19 | 20 | // 判断输入数据合法性,包括检查输入是否为数字,k值是否大于0 21 | if (cin.fail() || k < 0) 22 | { 23 | cout << "输入k错误!" << endl; 24 | system("pause"); 25 | return 0; 26 | } 27 | 28 | // 计算比赛日程表大小 29 | n = pow(2, k); 30 | 31 | // 分配日程表空间 32 | int **table = new int *[n + 1]; 33 | for (int i = 0; i <= n; i++) 34 | { 35 | table[i] = new int[n + 1]; 36 | } 37 | 38 | // 进行循环赛日程安排,生成日程表 39 | MatchTable(k, n, table); 40 | 41 | // 显示输出 42 | cout << "------------------------------------------------" << endl; 43 | for (int i = 1; i <= n; i++) 44 | { 45 | for (int j = 1; j <= n; j++) 46 | { 47 | cout << table[i][j] << "\t"; 48 | } 49 | cout << endl; 50 | } 51 | cout << "------------------------------------------------" << endl; 52 | 53 | // 暂停查看结果 54 | system("pause"); 55 | 56 | // 释放内存 57 | for (int i = 0; i <= n; i++) 58 | delete[] table[i]; 59 | delete[] table; 60 | 61 | // 指针置空 62 | table = NULL; 63 | 64 | return 0; 65 | } 66 | 67 | // 进行循环赛日程安排,生成日程表 68 | void MatchTable(int k, int n, int **table) 69 | { 70 | // 设置日程表第一行的值 71 | for (int i = 1; i <= n; i++) 72 | table[1][i] = i; 73 | 74 | // 每次填充的起始填充位置 75 | int begin = 1; 76 | 77 | // 用分治法分separate份,循环求解 78 | for (int separate = 1; separate <= k; separate++) 79 | { 80 | // 日程表进行划分 81 | n /= 2; 82 | 83 | // flag为每一小份的列的标记 84 | for (int flag = 1; flag <= n; flag++) 85 | { 86 | // 操作行 87 | for (int i = begin + 1; i <= 2 * begin; i++) 88 | { 89 | // 操作列 90 | for (int j = begin + 1; j <= 2 * begin; j++) 91 | { 92 | // 把左上角的值赋给右下角 93 | table[i][j + (flag - 1) * begin * 2] = table[i - begin][j + (flag - 1) * begin * 2 - begin]; 94 | // 把右上角的值赋给左下角 95 | table[i][j + (flag - 1) * begin * 2 - begin] = table[i - begin][j + (flag - 1) * begin * 2]; 96 | } 97 | } 98 | } 99 | // 进入日程表的下一个划分进行填充 100 | begin *= 2; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Problems/RoundRobinProblem/MatchTable.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/Problems/RoundRobinProblem/MatchTable.exe -------------------------------------------------------------------------------- /Problems/RoundRobinProblem/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 循环赛日程安排问题 3 | 4 | ### 代码 5 | 6 | [循环赛日程安排问题代码](MatchTable.cpp) 7 | 8 | ### 问题说明 9 | 10 | 设有n=2k个选手要进行网球循环赛, 11 | 要求设计一个满足以下要求的比赛日程表: 12 | 13 | (1)每个选手必须与其他n-1个选手各赛一次; 14 | (2)每个选手一天只能赛一次。 15 | 16 | 按此要求,可将比赛日程表设计成一个 n 行n-1列的二维表, 17 | 其中,第 i 行第 j 列表示和第 i 个选手在第 j 天比赛的选手。 18 | 19 | ### 功能说明 20 | 21 | 本程序运用分治的思想,实现了循环赛日程安排问题的求解, 22 | 生成日程表,输出。 23 | 24 | ### 代码简述 25 | 26 | 通过用户输入数据,程序输入检测,动态分配空间, 27 | 调用生成日程表函数,显示输出。 28 | 29 | 其中,生成日程表函数运用分治的思想,分成separate份, 30 | 先安排第一行(第一份),然后每一份填充,最终求解完毕, 31 | 生成日程表。 -------------------------------------------------------------------------------- /Problems/TubingProblem/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 输油管道问题 3 | 4 | ### 代码 5 | 6 | [输油管道问题代码](Tubing.cpp) 7 | 8 | ### 问题说明 9 | 10 | 某石油公司计划建造一条由东向西的主输油管道。 11 | 该管道要穿过一个有n 口油井的油田。 12 | 从每口油井都要有一条输油管道沿最短路经(或南或北)与主管道相连。 13 | 如果给定n口油井的位置,即它们的x 坐标(东西向)和y 坐标(南北向), 14 | 应如何确定主管道的最优位置, 15 | 即使各油井到主管道之间的输油管道长度总和最小的位置? 16 | 17 | ### 功能说明 18 | 19 | 本程序用排序求中值的方法求解输油管道问题。 20 | 21 | ### 代码简述 22 | 23 | 通过用户输入数据(只输入油井数n、每个油井的y坐标), 24 | 程序输入检测,动态分配空间,排序(使用快速排序), 25 | 求出中间值,输出。 26 | 27 | 输出有以下两种情况: 28 | 29 | 1. 当n为奇数,则最优位置为y数组的第n/2个油井的y坐标 30 | 31 | 2. 当n为偶数,则最优位置为y数组的中间两个油井的y坐标的区间 -------------------------------------------------------------------------------- /Problems/TubingProblem/Tubing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 油井y坐标指针 5 | float * y = NULL; 6 | 7 | // 快速排序 8 | void quick_sort(int low, int high) 9 | { 10 | if (low >= high) // 结束标志 11 | return; 12 | int first = low; // 低位下标 13 | int last = high; // 高位下标 14 | float key = y[first]; // 设第一个为基准 15 | 16 | while (first < last) 17 | { 18 | // 将比第一个小的移到前面 19 | while (first < last && y[last] >= key) 20 | last--; 21 | if (first < last) 22 | y[first++] = y[last]; 23 | 24 | // 将比第一个大的移到后面 25 | while (first < last && y[first] <= key) 26 | first++; 27 | if (first < last) 28 | y[last--] = y[first]; 29 | } 30 | // 基准置位 31 | y[first] = key; 32 | // 前半递归 33 | quick_sort(low, first - 1); 34 | // 后半递归 35 | quick_sort(first + 1, high); 36 | } 37 | 38 | int main() 39 | { 40 | int n; // 油井数 41 | float mid; // y数组的中间位置的数 42 | float minDistance = 0; // 各油井到主管道之间的管道长度总和最小位置 43 | 44 | cout << "---------------- 输油管问题 ----------------" << endl; 45 | cout << "请输入油井数 n (n>=0) " << endl; 46 | 47 | // 输入油井数 48 | cin >> n; 49 | 50 | // 判断输入数据合法性,包括检查输入是否为数字,k值是否大于0 51 | if (cin.fail() || n < 0) 52 | { 53 | cout << "输入n错误!" << endl; 54 | system("pause"); 55 | return 0; 56 | } 57 | 58 | // 分配n个y坐标存储空间 59 | y = new float[n]; 60 | 61 | cout << "请输入 " << n << " 个油井的 y 坐标(用空格隔开)" << endl; 62 | 63 | // 输入油井的 y 坐标 64 | for (auto i = 0; i < n; i++) 65 | { 66 | cin >> y[i]; 67 | } 68 | 69 | // 判断输入数据合法性 70 | if (cin.fail()) 71 | { 72 | cout << "输入y坐标错误!" << endl; 73 | system("pause"); 74 | return 0; 75 | } 76 | 77 | // 运用快速排序对y坐标数组进行排序 78 | quick_sort(0, n - 1); 79 | 80 | // 计算y数组的中间位置的数 81 | mid = y[n / 2]; 82 | 83 | // 计算各个油井到主输油管的长度之和 84 | for (auto i = 0; i < n; i++) 85 | { 86 | minDistance += abs(y[i] - mid); 87 | } 88 | 89 | // 显示输出 90 | cout << "------------------------------------------------" << endl; 91 | // 判断油井奇偶,做不同的输出 92 | if (n & 1) 93 | { 94 | // n为奇数,则最优位置为y数组的第n/2个油井的y坐标 95 | cout << "主管道的最优位置为:y = " << mid << endl; 96 | } 97 | else 98 | { 99 | // n为偶数,则最优位置为y数组的中间两个油井的y坐标的区间 100 | cout << "主管道的最优位置为:y = [" << y[n / 2 - 1] << "," << mid << "]" << endl; 101 | } 102 | // 输出各油井到主管道之间的管道总长度 103 | cout << "各油井到主管道之间的管道总长度为:" << minDistance << endl; 104 | cout << "------------------------------------------------" << endl; 105 | 106 | // 暂停查看结果 107 | system("pause"); 108 | 109 | // 释放内存 110 | delete[] y; 111 | 112 | // 指针置空 113 | y = NULL; 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /Problems/TubingProblem/Tubing.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/Problems/TubingProblem/Tubing.exe -------------------------------------------------------------------------------- /STL/README.md: -------------------------------------------------------------------------------- 1 | [STL 详细文档](https://github.com/huihut/interview/blob/master/STL/STL.md) 2 | 3 | # 容器(containers) 4 | 5 | ## array 6 | 7 | array 是固定大小的顺序容器,它们保存了一个以严格的线性顺序排列的特定数量的元素。 8 | 9 | 方法|含义 10 | ---|--- 11 | begin|返回指向数组容器中第一个元素的迭代器 12 | end|返回指向数组容器中最后一个元素之后的理论元素的迭代器 13 | rbegin|返回指向数组容器中最后一个元素的反向迭代器 14 | rend|返回一个反向迭代器,指向数组中第一个元素之前的理论元素 15 | cbegin|返回指向数组容器中第一个元素的常量迭代器(const_iterator) 16 | cend|返回指向数组容器中最后一个元素之后的理论元素的常量迭代器(const_iterator) 17 | crbegin|返回指向数组容器中最后一个元素的常量反向迭代器(const_reverse_iterator) 18 | crend|返回指向数组中第一个元素之前的理论元素的常量反向迭代器(const_reverse_iterator) 19 | size|返回数组容器中元素的数量 20 | max_size|返回数组容器可容纳的最大元素数 21 | empty|返回一个布尔值,指示数组容器是否为空 22 | operator[]|返回容器中第 n(参数)个位置的元素的引用 23 | at|返回容器中第 n(参数)个位置的元素的引用 24 | front|返回对容器中第一个元素的引用 25 | back|返回对容器中最后一个元素的引用 26 | data|返回指向容器中第一个元素的指针 27 | fill|用 val(参数)填充数组所有元素 28 | swap|通过 x(参数)的内容交换数组的内容 29 | get(array)|形如 `std::get<0>(myarray)`;传入一个数组容器,返回指定位置元素的引用 30 | relational operators (array)|形如 `arrayA > arrayB`;依此比较数组每个元素的大小关系 31 | 32 | ## vector 33 | 34 | vector 是表示可以改变大小的数组的序列容器。 35 | 36 | 方法|含义 37 | ---|--- 38 | vector|构造函数 39 | ~vector|析构函数,销毁容器对象 40 | operator=|将新内容分配给容器,替换其当前内容,并相应地修改其大小 41 | begin|返回指向容器中第一个元素的迭代器 42 | end|返回指向容器中最后一个元素之后的理论元素的迭代器 43 | rbegin|返回指向容器中最后一个元素的反向迭代器 44 | rend|返回一个反向迭代器,指向中第一个元素之前的理论元素 45 | cbegin|返回指向容器中第一个元素的常量迭代器(const_iterator) 46 | cend|返回指向容器中最后一个元素之后的理论元素的常量迭代器(const_iterator) 47 | crbegin|返回指向容器中最后一个元素的常量反向迭代器(const_reverse_iterator) 48 | crend|返回指向容器中第一个元素之前的理论元素的常量反向迭代器(const_reverse_iterator) 49 | size|返回容器中元素的数量 50 | max_size|返回容器可容纳的最大元素数 51 | resize|调整容器的大小,使其包含 n(参数)个元素 52 | capacity|返回当前为 vector 分配的存储空间(容量)的大小 53 | empty|返回 vector 是否为空 54 | reserve|请求 vector 容量至少足以包含 n(参数)个元素 55 | shrink_to_fit|要求容器减小其 capacity(容量)以适应其 size(元素数量) 56 | operator[]|返回容器中第 n(参数)个位置的元素的引用 57 | at|返回容器中第 n(参数)个位置的元素的引用 58 | front|返回对容器中第一个元素的引用 59 | back|返回对容器中最后一个元素的引用 60 | data|返回指向容器中第一个元素的指针 61 | assign|将新内容分配给 vector,替换其当前内容,并相应地修改其 size 62 | push_back|在容器的最后一个元素之后添加一个新元素 63 | pop_back|删除容器中的最后一个元素,有效地将容器 size 减少一个 64 | insert|通过在指定位置的元素之前插入新元素来扩展该容器,通过插入元素的数量有效地增加容器大小 65 | erase|从 vector 中删除单个元素(`position`)或一系列元素(`[first,last)`),这有效地减少了被去除的元素的数量,从而破坏了容器的大小 66 | swap|通过 x(参数)的内容交换容器的内容,x 是另一个类型相同、size 可能不同的 vector 对象 67 | clear|从 vector 中删除所有的元素(被销毁),留下 size 为 0 的容器 68 | emplace|通过在 position(参数)位置处插入新元素 args(参数)来扩展容器 69 | emplace_back|在 vector 的末尾插入一个新的元素,紧跟在当前的最后一个元素之后 70 | get_allocator|返回与vector关联的构造器对象的副本 71 | swap(vector)|容器 x(参数)的内容与容器 y(参数)的内容交换。两个容器对象都必须是相同的类型(相同的模板参数),尽管大小可能不同 72 | relational operators (vector)|形如 `vectorA > vectorB`;依此比较每个元素的大小关系 73 | 74 | ## deque 75 | 76 | deque(['dek])(双端队列)是double-ended queue 的一个不规则缩写。deque是具有动态大小的序列容器,可以在两端(前端或后端)扩展或收缩。 77 | 78 | 方法|含义 79 | ---|--- 80 | deque|构造函数 81 | push_back|在当前的最后一个元素之后 ,在 deque 容器的末尾添加一个新元素 82 | push_front|在 deque 容器的开始位置插入一个新的元素,位于当前的第一个元素之前 83 | pop_back|删除 deque 容器中的最后一个元素,有效地将容器大小减少一个 84 | pop_front|删除 deque 容器中的第一个元素,有效地减小其大小 85 | emplace_front|在 deque 的开头插入一个新的元素,就在其当前的第一个元素之前 86 | emplace_back|在 deque 的末尾插入一个新的元素,紧跟在当前的最后一个元素之后 87 | 88 | ## forward\_list 89 | 90 | forward_list(单向链表)是序列容器,允许在序列中的任何地方进行恒定的时间插入和擦除操作。 91 | 92 | 方法|含义 93 | ---|--- 94 | forward\_list|返回指向容器中第一个元素之前的位置的迭代器 95 | cbefore\_begin|返回指向容器中第一个元素之前的位置的 const_iterator 96 | 97 | ## list 98 | 99 | list,双向链表,是序列容器,允许在序列中的任何地方进行常数时间插入和擦除操作,并在两个方向上进行迭代。 100 | 101 | ## stack 102 | 103 | stack 是一种容器适配器,用于在LIFO(后进先出)的操作,其中元素仅从容器的一端插入和提取。 104 | 105 | ## queue 106 | 107 | queue 是一种容器适配器,用于在FIFO(先入先出)的操作,其中元素插入到容器的一端并从另一端提取。 108 | 109 | ## priority_queue 110 | 111 | ## set 112 | 113 | set 是按照特定顺序存储唯一元素的容器。 114 | 115 | ## multiset 116 | 117 | ## map 118 | 119 | map 是关联容器,按照特定顺序存储由 key value (键值) 和 mapped value (映射值) 组合形成的元素。 120 | 121 | 方法|含义 122 | ---|--- 123 | map|构造函数 124 | begin|返回引用容器中第一个元素的迭代器 125 | key_comp|返回容器用于比较键的比较对象的副本 126 | value_comp|返回可用于比较两个元素的比较对象,以获取第一个元素的键是否在第二个元素之前 127 | find|在容器中搜索具有等于 k(参数)的键的元素,如果找到则返回一个迭代器,否则返回 map::end 的迭代器 128 | count|在容器中搜索具有等于 k(参数)的键的元素,并返回匹配的数量 129 | lower_bound|返回一个非递减序列 `[first, last)`(参数)中的第一个大于等于值 val(参数)的位置的迭代器 130 | upper_bound|返回一个非递减序列 `[first, last)`(参数)中第一个大于 val(参数)的位置的迭代器 131 | equal_range|获取相同元素的范围,返回包含容器中所有具有与 k(参数)等价的键的元素的范围边界(`pair< map::iterator, map::iterator >`) 132 | 133 | ## multimap 134 | 135 | ## unordered\_set 136 | 137 | ## unordered\_multiset 138 | 139 | ## unordered\_map 140 | 141 | ## unordered\_multimap 142 | 143 | ## tuple 144 | 145 | 元组是一个能够容纳元素集合的对象。每个元素可以是不同的类型。 146 | 147 | ## pair 148 | 149 | 这个类把一对值(values)结合在一起,这些值可能是不同的类型(T1 和 T2)。每个值可以被公有的成员变量first、second访问。 150 | 151 | # 算法(algorithms) 152 | 153 | ```cpp 154 | // 简单查找算法,要求输入迭代器(input iterator) 155 | find(beg, end, val); // 返回一个迭代器,指向输入序列中第一个等于 val 的元素,未找到返回 end 156 | find_if(beg, end, unaryPred); // 返回一个迭代器,指向第一个满足 unaryPred 的元素,未找到返回 end 157 | find_if_not(beg, end, unaryPred); // 返回一个迭代器,指向第一个令 unaryPred 为 false 的元素,未找到返回 end 158 | count(beg, end, val); // 返回一个计数器,指出 val 出现了多少次 159 | count_if(beg, end, unaryPred); // 统计有多少个元素满足 unaryPred 160 | all_of(beg, end, unaryPred); // 返回一个 bool 值,判断是否所有元素都满足 unaryPred 161 | any_of(beg, end, unaryPred); // 返回一个 bool 值,判断是否任意(存在)一个元素满足 unaryPred 162 | none_of(beg, end, unaryPred); // 返回一个 bool 值,判断是否所有元素都不满足 unaryPred 163 | 164 | // 查找重复值的算法,传入向前迭代器(forward iterator) 165 | adjacent_find(beg, end); // 返回指向第一对相邻重复元素的迭代器,无相邻元素则返回 end 166 | adjacent_find(beg, end, binaryPred); // 返回指向第一对相邻重复元素的迭代器,无相邻元素则返回 end 167 | search_n(beg, end, count, val); // 返回一个迭代器,从此位置开始有 count 个相等元素,不存在则返回 end 168 | search_n(beg, end, count, val, binaryPred); // 返回一个迭代器,从此位置开始有 count 个相等元素,不存在则返回 end 169 | 170 | // 查找子序列算法,除 find_first_of(前两个输入迭代器,后两个前向迭代器) 外,都要求两个前向迭代器 171 | search(beg1, end1, beg2, end2); // 返回第二个输入范围(子序列)在爹一个输入范围中第一次出现的位置,未找到则返回 end1 172 | search(beg1, end1, beg2, end2, binaryPred); // 返回第二个输入范围(子序列)在爹一个输入范围中第一次出现的位置,未找到则返回 end1 173 | find_first_of(beg1, end1, beg2, end2); // 返回一个迭代器,指向第二个输入范围中任意元素在第一个范围中首次出现的位置,未找到则返回end1 174 | find_first_of(beg1, end1, beg2, end2, binaryPred); // 返回一个迭代器,指向第二个输入范围中任意元素在第一个范围中首次出现的位置,未找到则返回end1 175 | find_end(beg1, end1, beg2, end2); // 类似 search,但返回的最后一次出现的位置。如果第二个输入范围为空,或者在第一个输入范围为空,或者在第一个输入范围中未找到它,则返回 end1 176 | find_end(beg1, end1, beg2, end2, binaryPred); // 类似 search,但返回的最后一次出现的位置。如果第二个输入范围为空,或者在第一个输入范围为空,或者在第一个输入范围中未找到它,则返回 end1 177 | 178 | // 其他只读算法,传入输入迭代器 179 | for_each(beg, end, unaryOp); // 对输入序列中的每个元素应用可调用对象 unaryOp,unaryOp 的返回值被忽略 180 | mismatch(beg1, end1, beg2); // 比较两个序列中的元素。返回一个迭代器的 pair,表示两个序列中第一个不匹配的元素 181 | mismatch(beg1, end1, beg2, binaryPred); // 比较两个序列中的元素。返回一个迭代器的 pair,表示两个序列中第一个不匹配的元素 182 | equal(beg1, end1, beg2); // 比较每个元素,确定两个序列是否相等。 183 | equal(beg1, end1, beg2, binaryPred); // 比较每个元素,确定两个序列是否相等。 184 | 185 | // 二分搜索算法,传入前向迭代器或随机访问迭代器(random-access iterator),要求序列中的元素已经是有序的。通过小于运算符(<)或 comp 比较操作实现比较。 186 | lower_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end 187 | lower_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end 188 | upper_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end 189 | upper_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end 190 | equal_range(beg, end, val); // 返回一个 pair,其 first 成员是 lower_bound 返回的迭代器,其 second 成员是 upper_bound 返回的迭代器 191 | binary_search(beg, end, val); // 返回一个 bool 值,指出序列中是否包含等于 val 的元素。对于两个值 x 和 y,当 x 不小于 y 且 y 也不小于 x 时,认为它们相等。 192 | 193 | // 只写不读算法,要求输出迭代器(output iterator) 194 | fill(beg, end, val); // 将 val 赋予每个元素,返回 void 195 | fill_n(beg, cnt, val); // 将 val 赋予 cnt 个元素,返回指向写入到输出序列最有一个元素之后位置的迭代器 196 | genetate(beg, end, Gen); // 每次调用 Gen() 生成不同的值赋予每个序列,返回 void 197 | genetate_n(beg, cnt, Gen); // 每次调用 Gen() 生成不同的值赋予 cnt 个序列,返回指向写入到输出序列最有一个元素之后位置的迭代器 198 | 199 | // 使用输入迭代器的写算法,读取一个输入序列,将值写入到一个输出序列(dest)中 200 | copy(beg, end, dest); // 从输入范围将元素拷贝所有元素到 dest 指定定的目的序列 201 | copy_if(beg, end, dest, unaryPred); // 从输入范围将元素拷贝满足 unaryPred 的元素到 dest 指定定的目的序列 202 | copy_n(beg, n, dest); // 从输入范围将元素拷贝前 n 个元素到 dest 指定定的目的序列 203 | move(beg, end, dest); // 对输入序列中的每个元素调用 std::move,将其移动到迭代器 dest 开始始的序列中 204 | transform(beg, end, dest, unaryOp); // 调用给定操作(一元操作),并将结果写到dest中 205 | transform(beg, end, beg2, dest, binaryOp); // 调用给定操作(二元操作),并将结果写到dest中 206 | replace_copy(beg, end, dest, old_val, new_val); // 将每个元素拷贝到 dest,将等于 old_val 的的元素替换为 new_val 207 | replace_copy_if(beg, end, dest, unaryPred, new_val); // 将每个元素拷贝到 dest,将满足 unaryPred 的的元素替换为 new_val 208 | merge(beg1, end1, beg2, end2, dest); // 两个输入序列必须都是有序的,用 < 运算符将合并后的序列写入到 dest 中 209 | merge(beg1, end1, beg2, end2, dest, comp); // 两个输入序列必须都是有序的,使用给定的比较操作(comp)将合并后的序列写入到 dest 中 210 | 211 | // 使用前向迭代器的写算法,要求前向迭代器 212 | iter_swap(iter1, iter2); // 交换 iter1 和 iter2 所表示的元素,返回 void 213 | swap_ranges(beg1, end1, beg2); // 将输入范围中所有元素与 beg2 开始的第二个序列中所有元素进行交换。返回递增后的的 beg2,指向最后一个交换元素之后的位置。 214 | replace(beg, end, old_val, new_val); // 用 new_val 替换等于 old_val 的每个匹配元素 215 | replace_if(beg, end, unaryPred, new_val); // 用 new_val 替换满足 unaryPred 的每个匹配元素 216 | 217 | // 使用双向迭代器的写算法,要求双向选代器(bidirectional iterator) 218 | copy_backward(beg, end, dest); // 从输入范围中拷贝元素到指定目的位置。如果范围为空,则返回值为 dest;否则,返回值表示从 *beg 中拷贝或移动的元素。 219 | move_backward(beg, end, dest); // 从输入范围中移动元素到指定目的位置。如果范围为空,则返回值为 dest;否则,返回值表示从 *beg 中拷贝或移动的元素。 220 | inplace_merge(beg, mid, end); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用 < 比较元素。 221 | inplace_merge(beg, mid, end, comp); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用给定的 comp 操作。 222 | 223 | // 划分算法,要求双向选代器(bidirectional iterator) 224 | is_partitioned(beg, end, unaryPred); // 如果所有满足谓词 unaryPred 的元素都在不满足 unarypred 的元素之前,则返回 true。若序列为空,也返回 true 225 | partition_copy(beg, end, dest1, dest2, unaryPred); // 将满足 unaryPred 的元素拷贝到到 dest1,并将不满足 unaryPred 的元素拷贝到到 dest2。返回一个迭代器 pair,其 first 成员表示拷贝到 dest1 的的元素的末尾,second 表示拷贝到 dest2 的元素的末尾。 226 | partitioned_point(beg, end, unaryPred); // 输入序列必须是已经用 unaryPred 划分过的。返回满足 unaryPred 的范围的尾后迭代器。如果返回的迭代器不是 end,则它指向的元素及其后的元素必须都不满足 unaryPred 227 | stable_partition(beg, end, unaryPred); // 使用 unaryPred 划分输入序列。满足 unaryPred 的元素放置在序列开始,不满足的元素放在序列尾部。返回一个迭代器,指向最后一个满足 unaryPred 的元素之后的位置如果所有元素都不满足 unaryPred,则返回 beg 228 | partition(beg, end, unaryPred); // 使用 unaryPred 划分输入序列。满足 unaryPred 的元素放置在序列开始,不满足的元素放在序列尾部。返回一个迭代器,指向最后一个满足 unaryPred 的元素之后的位置如果所有元素都不满足 unaryPred,则返回 beg 229 | 230 | // 排序算法,要求随机访问迭代器(random-access iterator) 231 | sort(beg, end); // 排序整个范围 232 | stable_sort(beg, end); // 排序整个范围(稳定排序) 233 | sort(beg, end, comp); // 排序整个范围 234 | stable_sort(beg, end, comp); // 排序整个范围(稳定排序) 235 | is_sorted(beg, end); // 返回一个 bool 值,指出整个输入序列是否有序 236 | is_sorted(beg, end, comp); // 返回一个 bool 值,指出整个输入序列是否有序 237 | is_sorted_until(beg, end); // 在输入序列中査找最长初始有序子序列,并返回子序列的尾后迭代器 238 | is_sorted_until(beg, end, comp); // 在输入序列中査找最长初始有序子序列,并返回子序列的尾后迭代器 239 | partial_sort(beg, mid, end); // 排序 mid-beg 个元素。即,如果 mid-beg 等于 42,则此函数将值最小的 42 个元素有序放在序列前 42 个位置 240 | partial_sort(beg, mid, end, comp); // 排序 mid-beg 个元素。即,如果 mid-beg 等于 42,则此函数将值最小的 42 个元素有序放在序列前 42 个位置 241 | partial_sort_copy(beg, end, destBeg, destEnd); // 排序输入范围中的元素,并将足够多的已排序元素放到 destBeg 和 destEnd 所指示的序列中 242 | partial_sort_copy(beg, end, destBeg, destEnd, comp); // 排序输入范围中的元素,并将足够多的已排序元素放到 destBeg 和 destEnd 所指示的序列中 243 | nth_element(beg, nth, end); // nth 是一个迭代器,指向输入序列中第 n 大的元素。nth 之前的元素都小于等于它,而之后的元素都大于等于它 244 | nth_element(beg, nth, end, comp); // nth 是一个迭代器,指向输入序列中第 n 大的元素。nth 之前的元素都小于等于它,而之后的元素都大于等于它 245 | 246 | // 使用前向迭代器的重排算法。普通版本在输入序列自身内部重拍元素,_copy 版本完成重拍后写入到指定目的序列中,而不改变输入序列 247 | remove(beg, end, val); // 通过用保留的元素覆盖要删除的元素实现删除 ==val 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器 248 | remove_if(beg, end, unaryPred); // 通过用保留的元素覆盖要删除的元素实现删除满足 unaryPred 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器 249 | remove_copy(beg, end, dest, val); // 通过用保留的元素覆盖要删除的元素实现删除 ==val 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器 250 | remove_copy_if(beg, end, dest, unaryPred); // 通过用保留的元素覆盖要删除的元素实现删除满足 unaryPred 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器 251 | unique(beg, end); // 通过对覆盖相邻的重复元素(用 == 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置 252 | unique (beg, end, binaryPred); // 通过对覆盖相邻的重复元素(用 binaryPred 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置 253 | unique_copy(beg, end, dest); // 通过对覆盖相邻的重复元素(用 == 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置 254 | unique_copy_if(beg, end, dest, binaryPred); // 通过对覆盖相邻的重复元素(用 binaryPred 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置 255 | rotate(beg, mid, end); // 围绕 mid 指向的元素进行元素转动。元素 mid 成为为首元素,随后是 mid+1 到到 end 之前的元素,再接着是 beg 到 mid 之前的元素。返回一个迭代器,指向原来在 beg 位置的元素 256 | rotate_copy(beg, mid, end, dest); // 围绕 mid 指向的元素进行元素转动。元素 mid 成为为首元素,随后是 mid+1 到到 end 之前的元素,再接着是 beg 到 mid 之前的元素。返回一个迭代器,指向原来在 beg 位置的元素 257 | 258 | // 使用双向迭代器的重排算法 259 | reverse(beg, end); // 翻转序列中的元素,返回 void 260 | reverse_copy(beg, end, dest);; // 翻转序列中的元素,返回一个迭代器,指向拷贝到目的序列的元素的尾后位置 261 | 262 | // 使用随机访问迭代器的重排算法 263 | random_shuffle(beg, end); // 混洗输入序列中的元素,返回 void 264 | random_shuffle(beg, end, rand); // 混洗输入序列中的元素,rand 接受一个正整数的随机对象,返回 void 265 | shuffle(beg, end, Uniform_rand); // 混洗输入序列中的元素,Uniform_rand 必须满足均匀分布随机数生成器的要求,返回 void 266 | 267 | // 最小值和最大值,使用 < 运算符或给定的比较操作 comp 进行比较 268 | min(val1, va12); // 返回 val1 和 val2 中的最小值,两个实参的类型必须完全一致。参数和返回类型都是 const的引引用,意味着对象不会被拷贝。下略 269 | min(val1, val2, comp); 270 | min(init_list); 271 | min(init_list, comp); 272 | max(val1, val2); 273 | max(val1, val2, comp); 274 | max(init_list); 275 | max(init_list, comp); 276 | minmax(val1, val2); // 返回一个 pair,其 first 成员为提供的值中的较小者,second 成员为较大者。下略 277 | minmax(vall, val2, comp); 278 | minmax(init_list); 279 | minmax(init_list, comp); 280 | min_element(beg, end); // 返回指向输入序列中最小元素的迭代器 281 | min_element(beg, end, comp); // 返回指向输入序列中最小元素的迭代器 282 | max_element(beg, end); // 返回指向输入序列中最大元素的迭代器 283 | max_element(beg, end, comp); // 返回指向输入序列中最大元素的迭代器 284 | minmax_element(beg, end); // 返回一个 pair,其中 first 成员为最小元素,second 成员为最大元素 285 | minmax_element(beg, end, comp); // 返回一个 pair,其中 first 成员为最小元素,second 成员为最大元素 286 | 287 | // 字典序比较,根据第一对不相等的元素的相对大小来返回结果。如果第一个序列在字典序中小于第二个序列,则返回 true。否则,返回 fa1se。如果个序列比另一个短,且所有元素都与较长序列的对应元素相等,则较短序列在字典序中更小。如果序列长度相等,且对应元素都相等,则在字典序中任何一个都不大于另外一个。 288 | lexicographical_compare(beg1, end1, beg2, end2); 289 | lexicographical_compare(beg1, end1, beg2, end2, comp); 290 | ``` -------------------------------------------------------------------------------- /STL/STL.md: -------------------------------------------------------------------------------- 1 | # STL 2 | 3 | ## 网站 4 | 5 | * [github . huihut/note/STL.md](https://github.com/huihut/note/blob/master/STL.md) 6 | * [cplusplus . stl](http://www.cplusplus.com/reference/stl/) 7 | * [cppreference . C++ 参考手册](http://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5) 8 | * [CSDN专栏:STL学习笔记](http://blog.csdn.net/column/details/geek-stl.html) 9 | 10 | ## 组成 11 | 12 | * 容器(containers) 13 | * 算法(algorithms) 14 | * 迭代器(iterators) 15 | * 仿函数(functors) 16 | * 配接器(adapters) 17 | * 空间配置器(allocator) 18 | 19 | ## 容器(containers) 20 | 21 | * 序列式容器(sequence containers):元素都是可序(ordered),但未必是有序(sorted) 22 | * 关联式容器(associattive containers) 23 | 24 | ### array 25 | 26 | array是固定大小的顺序容器,它们保存了一个以严格的线性顺序排列的特定数量的元素。 27 | 28 | 在内部,一个数组除了它所包含的元素(甚至不是它的大小,它是一个模板参数,在编译时是固定的)以外不保存任何数据。存储大小与用语言括号语法([])声明的普通数组一样高效。这个类只是增加了一层成员函数和全局函数,所以数组可以作为标准容器使用。 29 | 30 | 与其他标准容器不同,数组具有固定的大小,并且不通过分配器管理其元素的分配:它们是封装固定大小数组元素的聚合类型。因此,他们不能动态地扩大或缩小。 31 | 32 | 零大小的数组是有效的,但是它们不应该被解除引用(成员的前面,后面和数据)。 33 | 34 | 与标准库中的其他容器不同,交换两个数组容器是一种线性操作,它涉及单独交换范围内的所有元素,这通常是相当低效的操作。另一方面,这允许迭代器在两个容器中的元素保持其原始容器关联。 35 | 36 | 数组容器的另一个独特特性是它们可以被当作元组对象来处理:array头部重载get函数来访问数组元素,就像它是一个元组,以及专门的tuple_size和tuple_element类型。 37 | 38 | ```cpp 39 | template < class T, size_t N > class array; 40 | ``` 41 | 42 | ![](http://img.blog.csdn.net/20160405225541788) 43 | 44 | #### array::begin 45 | 46 | 返回指向数组容器中第一个元素的迭代器。 47 | 48 | ![](https://i.stack.imgur.com/oa3EQ.png) 49 | 50 | ```cpp 51 | iterator begin() noexcept; 52 | const_iterator begin() const noexcept; 53 | ``` 54 | 55 | Example 56 | 57 | ```cpp 58 | #include 59 | #include 60 | 61 | int main() 62 | { 63 | std::array myarray = {2, 16, 77,34, 50}; 64 | std::cout << "myarray contains:"; 65 | for(auto it = myarray.begin(); it != myarray.end(); ++it) 66 | std::cout << ' ' << *it; 67 | std::cout << '\n'; 68 | 69 | return 0; 70 | } 71 | ``` 72 | Output 73 | ``` 74 | myarray contains: 2 16 77 34 50 75 | ``` 76 | 77 | #### array::end 78 | 79 | 返回指向数组容器中最后一个元素之后的理论元素的迭代器。 80 | 81 | ```cpp 82 | iterator end() noexcept; 83 | const_iterator end() const noexcept; 84 | ``` 85 | 86 | Example 87 | 88 | ```cpp 89 | #include 90 | #include 91 | 92 | int main () 93 | { 94 | std::array myarray = { 5, 19, 77, 34, 99 }; 95 | 96 | std::cout << "myarray contains:"; 97 | for ( auto it = myarray.begin(); it != myarray.end(); ++it ) 98 | std::cout << ' ' << *it; 99 | 100 | std::cout << '\n'; 101 | 102 | return 0; 103 | } 104 | ``` 105 | Output 106 | ``` 107 | myarray contains: 5 19 77 34 99 108 | ``` 109 | 110 | #### array::rbegin 111 | 112 | 返回指向数组容器中最后一个元素的反向迭代器。 113 | 114 | ```cpp 115 | reverse_iterator rbegin()noexcept; 116 | const_reverse_iterator rbegin()const noexcept; 117 | ``` 118 | Example 119 | ```cpp 120 | #include 121 | #include 122 | 123 | int main () 124 | { 125 | std::array myarray = {4, 26, 80, 14} ; 126 | for(auto rit = myarray.rbegin(); rit < myarray.rend(); ++rit) 127 | std::cout << ' ' << *rit; 128 | 129 | std::cout << '\n'; 130 | 131 | return 0; 132 | } 133 | ``` 134 | Output 135 | ``` 136 | myarray contains: 14 80 26 4 137 | ``` 138 | 139 | #### array::rend 140 | 141 | 返回一个反向迭代器,指向数组中第一个元素之前的理论元素(这被认为是它的反向结束)。 142 | 143 | ```cpp 144 | reverse_iterator rend() noexcept; 145 | const_reverse_iterator rend() const noexcept; 146 | ``` 147 | 148 | Example 149 | ```cpp 150 | #include 151 | #include 152 | 153 | int main () 154 | { 155 | std::array myarray = {4, 26, 80, 14}; 156 | std::cout << "myarray contains"; 157 | for(auto rit = myarray.rbegin(); rit < myarray.rend(); ++rit) 158 | std::cout << ' ' << *rit; 159 | 160 | std::cout << '\n'; 161 | 162 | return 0; 163 | } 164 | ``` 165 | Output 166 | ``` 167 | myarray contains: 14 80 26 4 168 | ``` 169 | 170 | #### array::cbegin 171 | 172 | 返回指向数组容器中第一个元素的常量迭代器(const_iterator);这个迭代器可以增加和减少,但是不能用来修改它指向的内容。 173 | ```cpp 174 | const_iterator cbegin()const noexcept; 175 | ``` 176 | Example 177 | ```cpp 178 | #include 179 | #include 180 | 181 | int main () 182 | { 183 | std::array myarray = {2, 16, 77, 34, 50}; 184 | 185 | std::cout << "myarray contains:"; 186 | 187 | for ( auto it = myarray.cbegin(); it != myarray.cend(); ++it ) 188 | std::cout << ' ' << *it; // cannot modify *it 189 | 190 | std::cout << '\n'; 191 | 192 | return 0; 193 | } 194 | ``` 195 | Output 196 | ``` 197 | myarray contains: 2 16 77 34 50 198 | ``` 199 | 200 | #### array::cend 201 | 返回指向数组容器中最后一个元素之后的理论元素的常量迭代器(const_iterator)。这个迭代器可以增加和减少,但是不能用来修改它指向的内容。 202 | ```cpp 203 | const_iterator cend() const noexcept; 204 | ``` 205 | Example 206 | ```cpp 207 | #include 208 | #include 209 | 210 | int main () 211 | { 212 | std::array myarray = { 15, 720, 801, 1002, 3502 }; 213 | 214 | std::cout << "myarray contains:"; 215 | for ( auto it = myarray.cbegin(); it != myarray.cend(); ++it ) 216 | std::cout << ' ' << *it; // cannot modify *it 217 | 218 | std::cout << '\n'; 219 | 220 | return 0; 221 | } 222 | ``` 223 | Output 224 | ``` 225 | myarray contains: 2 16 77 34 50 226 | ``` 227 | 228 | #### array::crbegin 229 | 返回指向数组容器中最后一个元素的常量反向迭代器(const_reverse_iterator) 230 | ```cpp 231 | const_reverse_iterator crbegin()const noexcept; 232 | ``` 233 | Example 234 | ```cpp 235 | #include 236 | #include 237 | 238 | int main () 239 | { 240 | std::array myarray = {10, 20, 30, 40, 50, 60} ; 241 | 242 | std::cout << "myarray backwards:"; 243 | for ( auto rit=myarray.crbegin() ; rit < myarray.crend(); ++rit ) 244 | std::cout << ' ' << *rit; // cannot modify *rit 245 | 246 | std::cout << '\n'; 247 | 248 | return 0; 249 | } 250 | ``` 251 | Output 252 | ``` 253 | myarray backwards: 60 50 40 30 20 10 254 | ``` 255 | #### array::crend 256 | 257 | 返回指向数组中第一个元素之前的理论元素的常量反向迭代器(const_reverse_iterator),它被认为是其反向结束。 258 | 259 | ```cpp 260 | const_reverse_iterator crend() const noexcept; 261 | ``` 262 | Example 263 | ```cpp 264 | #include 265 | #include 266 | 267 | int main () 268 | { 269 | std::array myarray = {10, 20, 30, 40, 50, 60} ; 270 | 271 | std::cout << "myarray backwards:"; 272 | for ( auto rit=myarray.crbegin() ; rit < myarray.crend(); ++rit ) 273 | std::cout << ' ' << *rit; // cannot modify *rit 274 | 275 | std::cout << '\n'; 276 | 277 | return 0; 278 | } 279 | ``` 280 | Output 281 | ``` 282 | myarray backwards: 60 50 40 30 20 10 283 | ``` 284 | 285 | #### array::size 286 | 287 | 返回数组容器中元素的数量。 288 | 289 | ```cpp 290 | constexpr size_type size()noexcept; 291 | ``` 292 | Example 293 | ```cpp 294 | #include 295 | #include 296 | 297 | int main () 298 | { 299 | std::array myints; 300 | std::cout << "size of myints:" << myints.size() << std::endl; 301 | std::cout << "sizeof(myints):" << sizeof(myints) << std::endl; 302 | 303 | return 0; 304 | } 305 | ``` 306 | Possible Output 307 | ``` 308 | size of myints: 5 309 | sizeof(myints): 20 310 | ``` 311 | #### array::max_size 312 | 返回数组容器可容纳的最大元素数。数组对象的max_size与其size一样,始终等于用于实例化数组模板类的第二个模板参数。 313 | ```cpp 314 | constexpr size_type max_size() noexcept; 315 | ``` 316 | Example 317 | ```cpp 318 | #include 319 | #include 320 | 321 | int main () 322 | { 323 | std::array myints; 324 | std::cout << "size of myints: " << myints.size() << '\n'; 325 | std::cout << "max_size of myints: " << myints.max_size() << '\n'; 326 | 327 | return 0; 328 | } 329 | ``` 330 | Output 331 | ``` 332 | size of myints: 10 333 | max_size of myints: 10 334 | ``` 335 | 336 | #### array::empty 337 | 返回一个布尔值,指示数组容器是否为空,即它的size()是否为0。 338 | ```cpp 339 | constexpr bool empty() noexcept; 340 | ``` 341 | Example 342 | ```cpp 343 | #include 344 | #include 345 | 346 | int main () 347 | { 348 | std::array first; 349 | std::array second; 350 | std::cout << "first " << (first.empty() ? "is empty" : "is not empty") << '\n'; 351 | std::cout << "second " << (second.empty() ? "is empty" : "is not empty") << '\n'; 352 | return 0; 353 | } 354 | ``` 355 | Output: 356 | ``` 357 | first is empty 358 | second is not empt 359 | ``` 360 | #### array::operator[] 361 | 返回数组中第n个位置的元素的引用。与array::at相似,但array::at会检查数组边界并通过抛出一个out_of_range异常来判断n是否超出范围,而array::operator[]不检查边界。 362 | ```cpp 363 | reference operator[] (size_type n); 364 | const_reference operator[] (size_type n) const; 365 | ``` 366 | Example 367 | ```cpp 368 | #include 369 | #include 370 | 371 | int main () 372 | { 373 | std::array myarray; 374 | unsigned int i; 375 | 376 | // assign some values: 377 | for(i=0; i<10; i++) 378 | myarray[i] = i; 379 | 380 | // print content 381 | std::cout << "myarray contains:"; 382 | for(i=0; i<10; i++) 383 | std::cout << ' ' << myarray[i]; 384 | std::cout << '\n'; 385 | 386 | return 0; 387 | } 388 | ``` 389 | Output 390 | ``` 391 | myarray contains: 0 1 2 3 4 5 6 7 8 9 392 | ``` 393 | #### array::at 394 | 返回数组中第n个位置的元素的引用。与array::operator[]相似,但array::at会检查数组边界并通过抛出一个out_of_range异常来判断n是否超出范围,而array::operator[]不检查边界。 395 | ```cpp 396 | reference at ( size_type n ); 397 | const_reference at ( size_type n ) const; 398 | ``` 399 | Example 400 | ```cpp 401 | #include 402 | #include 403 | 404 | int main() 405 | { 406 | std::array myarray; 407 | unsigned int i; 408 | 409 | // assign some values: 410 | for (i = 0; i<10; i++) 411 | myarray[i] = i; 412 | 413 | // print content 414 | std::cout << "myarray contains:"; 415 | for (i = 0; i<10; i++) 416 | std::cout << ' ' << myarray.at(i); 417 | std::cout << '\n'; 418 | 419 | return 0; 420 | } 421 | ``` 422 | Output 423 | ``` 424 | myarray contains: 0 1 2 3 4 5 6 7 8 9 425 | ``` 426 | #### array::front 427 | 返回对数组容器中第一个元素的引用。array::begin返回的是迭代器,array::front返回的是直接引用。 428 | 在空容器上调用此函数会导致未定义的行为。 429 | ```cpp 430 | reference front(); 431 | const_reference front() const; 432 | ``` 433 | Example 434 | ```cpp 435 | #include 436 | #include 437 | 438 | int main () 439 | { 440 | std::array myarray = {2, 16, 77}; 441 | 442 | std::cout << "front is: " << myarray.front() << std::endl; // 2 443 | std::cout << "back is: " << myarray.back() << std::endl; // 77 444 | 445 | myarray.front() = 100; 446 | 447 | std::cout << "myarray now contains:"; 448 | for ( int& x : myarray ) std::cout << ' ' << x; 449 | 450 | std::cout << '\n'; 451 | 452 | return 0; 453 | } 454 | ``` 455 | Output 456 | ``` 457 | front is: 2 458 | back is: 77 459 | myarray now contains: 100 16 77 460 | ``` 461 | #### array::back 462 | 返回对数组容器中最后一个元素的引用。array::end返回的是迭代器,array::back返回的是直接引用。 463 | 在空容器上调用此函数会导致未定义的行为。 464 | ```cpp 465 | reference back(); 466 | const_reference back() const; 467 | ``` 468 | Example 469 | ```cpp 470 | #include 471 | #include 472 | 473 | int main () 474 | { 475 | std::array myarray = {5, 19, 77}; 476 | 477 | std::cout << "front is: " << myarray.front() << std::endl; // 5 478 | std::cout << "back is: " << myarray.back() << std::endl; // 77 479 | 480 | myarray.back() = 50; 481 | 482 | std::cout << "myarray now contains:"; 483 | for ( int& x : myarray ) std::cout << ' ' << x; 484 | std::cout << '\n'; 485 | 486 | return 0; 487 | } 488 | ``` 489 | Output 490 | ``` 491 | front is: 5 492 | back is: 77 493 | myarray now contains: 5 19 50 494 | ``` 495 | #### array::data 496 | 返回指向数组对象中第一个元素的指针。 497 | 498 | 由于数组中的元素存储在连续的存储位置,所以检索到的指针可以偏移以访问数组中的任何元素。 499 | ```cpp 500 | value_type* data() noexcept; 501 | const value_type* data() const noexcept; 502 | ``` 503 | Example 504 | ```cpp 505 | #include 506 | #include 507 | #include 508 | 509 | int main () 510 | { 511 | const char* cstr = "Test string"; 512 | std::array charray; 513 | 514 | std::memcpy (charray.data(),cstr,12); 515 | 516 | std::cout << charray.data() << '\n'; 517 | 518 | return 0; 519 | } 520 | ``` 521 | Output 522 | ``` 523 | Test string 524 | ``` 525 | #### array::fill 526 | 用val填充数组所有元素,将val设置为数组对象中所有元素的值。 527 | ```cpp 528 | void fill (const value_type& val); 529 | ``` 530 | Example 531 | ```cpp 532 | #include 533 | #include 534 | 535 | int main () { 536 | std::array myarray; 537 | 538 | myarray.fill(5); 539 | 540 | std::cout << "myarray contains:"; 541 | for ( int& x : myarray) { std::cout << ' ' << x; } 542 | 543 | std::cout << '\n'; 544 | 545 | return 0; 546 | } 547 | ``` 548 | Output 549 | ``` 550 | myarray contains: 5 5 5 5 5 5 551 | ``` 552 | #### array::swap 553 | 通过x的内容交换数组的内容,这是另一个相同类型的数组对象(包括相同的大小)。 554 | 555 | 与其他容器的交换成员函数不同,此成员函数通过在各个元素之间执行与其大小相同的单独交换操作,以线性时间运行。 556 | ```cpp 557 | void swap (array& x) noexcept(noexcept(swap(declval(),declval()))); 558 | ``` 559 | Example 560 | ```cpp 561 | #include 562 | #include 563 | 564 | int main () 565 | { 566 | std::array first = {10, 20, 30, 40, 50}; 567 | std::array second = {11, 22, 33, 44, 55}; 568 | 569 | first.swap (second); 570 | 571 | std::cout << "first:"; 572 | for (int& x : first) std::cout << ' ' << x; 573 | std::cout << '\n'; 574 | 575 | std::cout << "second:"; 576 | for (int& x : second) std::cout << ' ' << x; 577 | std::cout << '\n'; 578 | 579 | return 0; 580 | } 581 | ``` 582 | Output 583 | ``` 584 | first: 11 22 33 44 55 585 | second: 10 20 30 40 50 586 | ``` 587 | #### get(array) 588 | 形如:std::get<0>(myarray);传入一个数组容器,返回指定位置元素的引用。 589 | ```cpp 590 | template T&get(array &arr)noexcept; 591 | template T && get(array && arr)noexcept; 592 | template const T&get(const array &arr)noexcept; 593 | ``` 594 | Example 595 | ```cpp 596 | #include 597 | #include 598 | #include 599 | 600 | int main () 601 | { 602 | std::array myarray = {10, 20, 30}; 603 | std::tuple mytuple (10, 20, 30); 604 | 605 | std::tuple_element<0,decltype(myarray)>::type myelement; // int myelement 606 | 607 | myelement = std::get<2>(myarray); 608 | std::get<2>(myarray) = std::get<0>(myarray); 609 | std::get<0>(myarray) = myelement; 610 | 611 | std::cout << "first element in myarray: " << std::get<0>(myarray) << "\n"; 612 | std::cout << "first element in mytuple: " << std::get<0>(mytuple) << "\n"; 613 | 614 | return 0; 615 | } 616 | ``` 617 | Output 618 | ``` 619 | first element in myarray: 30 620 | first element in mytuple: 10 621 | ``` 622 | #### relational operators (array) 623 | 形如:arrayA != arrayB、arrayA > arrayB;依此比较数组每个元素的大小关系。 624 | ```cpp 625 | (1) 626 | template 627 | bool operator ==(const array &lhs,const array &rhs); 628 | (2) 629 | template 630 | bool operator!=(const array &lhs,const array &rhs); 631 | (3) 632 | template 633 | bool operator <(const array &lhs,const array &rhs); 634 | (4) 635 | template 636 | bool operator <=(const array &lhs,const array &rhs); 637 | (5) 638 | template 639 | bool operator>(const array &lhs,const array &rhs); 640 | (6) 641 | template 642 | bool operator> =(const array &lhs,const array &rhs); 643 | ``` 644 | Example 645 | ```cpp 646 | #include 647 | #include 648 | 649 | int main () 650 | { 651 | std::array a = {10, 20, 30, 40, 50}; 652 | std::array b = {10, 20, 30, 40, 50}; 653 | std::array c = {50, 40, 30, 20, 10}; 654 | 655 | if (a==b) std::cout << "a and b are equal\n"; 656 | if (b!=c) std::cout << "b and c are not equal\n"; 657 | if (bb) std::cout << "c is greater than b\n"; 659 | if (a<=b) std::cout << "a is less than or equal to b\n"; 660 | if (a>=b) std::cout << "a is greater than or equal to b\n"; 661 | 662 | return 0; 663 | } 664 | ``` 665 | Output 666 | ``` 667 | a and b are equal 668 | b and c are not equal 669 | b is less than c 670 | c is greater than b 671 | a is less than or equal to b 672 | a is greater than or equal to b 673 | ``` 674 | ### vector 675 | vector是表示可以改变大小的数组的序列容器。 676 | 677 | 就像数组一样,vector为它们的元素使用连续的存储位置,这意味着它们的元素也可以使用到其元素的常规指针上的偏移来访问,而且和数组一样高效。但是与数组不同的是,它们的大小可以动态地改变,它们的存储由容器自动处理。 678 | 679 | 在内部,vector使用一个动态分配的数组来存储它们的元素。这个数组可能需要重新分配,以便在插入新元素时增加大小,这意味着分配一个新数组并将所有元素移动到其中。就处理时间而言,这是一个相对昂贵的任务,因此每次将元素添加到容器时矢量都不会重新分配。 680 | 681 | 相反,vector容器可以分配一些额外的存储以适应可能的增长,并且因此容器可以具有比严格需要包含其元素(即,其大小)的存储更大的实际容量。库可以实现不同的策略的增长到内存使用和重新分配之间的平衡,但在任何情况下,再分配应仅在对数生长的间隔发生尺寸,使得在所述载体的末端各个元件的插入可以与提供分期常量时间复杂性。 682 | 683 | 因此,与数组相比,载体消耗更多的内存来交换管理存储和以有效方式动态增长的能力。 684 | 685 | 与其他动态序列容器(deques,lists和 forward\_lists )相比,vector非常有效地访问其元素(就像数组一样),并相对有效地从元素末尾添加或移除元素。对于涉及插入或移除除了结尾之外的位置的元素的操作,它们执行比其他位置更差的操作,并且具有比列表和 forward\_lists 更不一致的迭代器和引用。 686 | 687 | 针对 vector 的各种常见操作的复杂度(效率)如下: 688 | * 随机访问 - 常数 O(1) 689 | * 在尾部增删元素 - 平摊(amortized)常数 O(1)}} 690 | * 增删元素 - 至 vector 尾部的线性距离 O(n)}} 691 | 692 | ```cpp 693 | template < class T, class Alloc = allocator > class vector; 694 | ``` 695 | ![](http://img.blog.csdn.net/20160406151211233) 696 | 697 | #### vector::vector 698 | (1)empty容器构造函数(默认构造函数) 699 | 构造一个空的容器,没有元素。 700 | (2)fill构造函数 701 | 用n个元素构造一个容器。每个元素都是val的副本(如果提供)。 702 | (3)范围(range)构造器 703 | 使用与[ range,first,last]范围内的元素相同的顺序构造一个容器,其中的每个元素都是emplace -从该范围内相应的元素构造而成。 704 | (4)复制(copy)构造函数(并用分配器复制) 705 | 按照相同的顺序构造一个包含x中每个元素的副本的容器。 706 | (5)移动(move)构造函数(和分配器移动) 707 | 构造一个获取x元素的容器。 708 | 如果指定了alloc并且与x的分配器不同,那么元素将被移动。否则,没有构建元素(他们的所有权直接转移)。 709 | x保持未指定但有效的状态。 710 | (6)初始化列表构造函数 711 | 构造一个容器中的每个元件中的一个拷贝的IL,以相同的顺序。 712 | 713 | ```cpp 714 | default (1) 715 | explicit vector (const allocator_type& alloc = allocator_type()); 716 | fill (2) 717 | explicit vector (size_type n); 718 | vector (size_type n, const value_type& val, 719 | const allocator_type& alloc = allocator_type()); 720 | range (3) 721 | template 722 | vector (InputIterator first, InputIterator last, 723 | const allocator_type& alloc = allocator_type()); 724 | copy (4) 725 | vector (const vector& x); 726 | vector (const vector& x, const allocator_type& alloc); 727 | move (5) 728 | vector (vector&& x); 729 | vector (vector&& x, const allocator_type& alloc); 730 | initializer list (6) 731 | vector (initializer_list il, 732 | const allocator_type& alloc = allocator_type()); 733 | ``` 734 | Example 735 | ```cpp 736 | #include 737 | #include 738 | 739 | int main () 740 | { 741 | // constructors used in the same order as described above: 742 | std::vector first; // empty vector of ints 743 | std::vector second(4, 100); // four ints with value 100 744 | std::vector third(second.begin(), second.end());// iterating through second 745 | std::vector fourth(third); // a copy of third 746 | 747 | // the iterator constructor can also be used to construct from arrays: 748 | int myints[] = {16,2,77,29}; 749 | std::vector fifth(myints, myints + sizeof(myints) / sizeof(int)); 750 | 751 | std::cout << "The contents of fifth are:"; 752 | for(std::vector::iterator it = fifth.begin(); it != fifth.end(); ++it) 753 | std::cout << ' ' << *it; 754 | std::cout << '\n'; 755 | 756 | return 0; 757 | } 758 | ``` 759 | Output 760 | ``` 761 | The contents of fifth are: 16 2 77 29 762 | ``` 763 | #### vector::~vector 764 | 销毁容器对象。这将在每个包含的元素上调用allocator_traits::destroy,并使用其分配器释放由矢量分配的所有存储容量。 765 | ```cpp 766 | ~vector(); 767 | ``` 768 | #### vector::operator= 769 | 将新内容分配给容器,替换其当前内容,并相应地修改其大小。 770 | ```cpp 771 | copy (1) 772 | vector& operator= (const vector& x); 773 | move (2) 774 | vector& operator= (vector&& x); 775 | initializer list (3) 776 | vector& operator= (initializer_list il); 777 | ``` 778 | Example 779 | ``` 780 | #include 781 | #include 782 | 783 | int main () 784 | { 785 | std::vector foo (3,0); 786 | std::vector bar (5,0); 787 | 788 | bar = foo; 789 | foo = std::vector(); 790 | 791 | std::cout << "Size of foo: " << int(foo.size()) << '\n'; 792 | std::cout << "Size of bar: " << int(bar.size()) << '\n'; 793 | return 0; 794 | } 795 | ``` 796 | Output 797 | ``` 798 | Size of foo: 0 799 | Size of bar: 3 800 | ``` 801 | #### vector::begin 802 | #### vector::end 803 | #### vector::rbegin 804 | #### vector::rend 805 | #### vector::cbegin 806 | #### vector::cend 807 | #### vector::rcbegin 808 | #### vector::rcend 809 | #### vector::size 810 | 811 | 返回vector中元素的数量。 812 | 813 | 这是vector中保存的实际对象的数量,不一定等于其存储容量。 814 | 815 | ```cpp 816 | size_type size() const noexcept; 817 | ``` 818 | Example 819 | ```cpp 820 | #include 821 | #include 822 | 823 | int main () 824 | { 825 | std::vector myints; 826 | std::cout << "0. size: " << myints.size() << '\n'; 827 | 828 | for (int i=0; i<10; i++) myints.push_back(i); 829 | std::cout << "1. size: " << myints.size() << '\n'; 830 | 831 | myints.insert (myints.end(),10,100); 832 | std::cout << "2. size: " << myints.size() << '\n'; 833 | 834 | myints.pop_back(); 835 | std::cout << "3. size: " << myints.size() << '\n'; 836 | 837 | return 0; 838 | } 839 | ``` 840 | Output 841 | ``` 842 | 0. size: 0 843 | 1. size: 10 844 | 2. size: 20 845 | 3. size: 19 846 | ``` 847 | #### vector::max_size 848 | 返回该vector可容纳的元素的最大数量。由于已知的系统或库实现限制, 849 | 850 | 这是容器可以达到的最大潜在大小,但容器无法保证能够达到该大小:在达到该大小之前的任何时间,仍然无法分配存储。 851 | ```cpp 852 | size_type max_size() const noexcept; 853 | ``` 854 | Example 855 | ```cpp 856 | #include 857 | #include 858 | 859 | int main () 860 | { 861 | std::vector myvector; 862 | 863 | // set some content in the vector: 864 | for (int i=0; i<100; i++) myvector.push_back(i); 865 | 866 | std::cout << "size: " << myvector.size() << "\n"; 867 | std::cout << "capacity: " << myvector.capacity() << "\n"; 868 | std::cout << "max_size: " << myvector.max_size() << "\n"; 869 | return 0; 870 | } 871 | ``` 872 | A possible output for this program could be: 873 | ``` 874 | size: 100 875 | capacity: 128 876 | max_size: 1073741823 877 | ``` 878 | #### vector::resize 879 | 调整容器的大小,使其包含n个元素。 880 | 881 | 如果n小于当前的容器size,内容将被缩小到前n个元素,将其删除(并销毁它们)。 882 | 883 | 如果n大于当前容器size,则通过在末尾插入尽可能多的元素以达到大小n来扩展内容。如果指定了val,则新元素将初始化为val的副本,否则将进行值初始化。 884 | 885 | 如果n也大于当前的容器的capacity(容量),分配的存储空间将自动重新分配。 886 | 887 | 注意这个函数通过插入或者删除元素的内容来改变容器的实际内容。 888 | ```cpp 889 | void resize (size_type n); 890 | void resize (size_type n, const value_type& val); 891 | ``` 892 | Example 893 | ```cpp 894 | #include 895 | #include 896 | 897 | int main () 898 | { 899 | std::vector myvector; 900 | 901 | // set some initial content: 902 | for (int i=1;i<10;i++) myvector.push_back(i); 903 | 904 | myvector.resize(5); 905 | myvector.resize(8,100); 906 | myvector.resize(12); 907 | 908 | std::cout << "myvector contains:"; 909 | for (int i=0;i 928 | #include 929 | 930 | int main () 931 | { 932 | std::vector myvector; 933 | 934 | // set some content in the vector: 935 | for (int i=0; i<100; i++) myvector.push_back(i); 936 | 937 | std::cout << "size: " << (int) myvector.size() << '\n'; 938 | std::cout << "capacity: " << (int) myvector.capacity() << '\n'; 939 | std::cout << "max_size: " << (int) myvector.max_size() << '\n'; 940 | return 0; 941 | } 942 | ``` 943 | A possible output for this program could be: 944 | ``` 945 | size: 100 946 | capacity: 128 947 | max_size: 1073741823 948 | ``` 949 | #### vector::empty 950 | 返回vector是否为空(即,它的size是否为0) 951 | ```cpp 952 | bool empty() const noexcept; 953 | ``` 954 | Example 955 | ```cpp 956 | #include 957 | #include 958 | 959 | int main () 960 | { 961 | std::vector myvector; 962 | int sum (0); 963 | 964 | for (int i=1;i<=10;i++) myvector.push_back(i); 965 | 966 | while (!myvector.empty()) 967 | { 968 | sum += myvector.back(); 969 | myvector.pop_back(); 970 | } 971 | 972 | std::cout << "total: " << sum << '\n'; 973 | 974 | return 0; 975 | } 976 | ``` 977 | Output 978 | ``` 979 | total: 55 980 | ``` 981 | #### vector::reserve 982 | 请求vector容量至少足以包含n个元素。 983 | 984 | 如果n大于当前vector容量,则该函数使容器重新分配其存储容量,从而将其容量增加到n(或更大)。 985 | 986 | 在所有其他情况下,函数调用不会导致重新分配,并且vector容量不受影响。 987 | 988 | 这个函数对vector大小没有影响,也不能改变它的元素。 989 | ```cpp 990 | void reserve (size_type n); 991 | ``` 992 | Example 993 | ```cpp 994 | #include 995 | #include 996 | 997 | int main () 998 | { 999 | std::vector::size_type sz; 1000 | 1001 | std::vector foo; 1002 | sz = foo.capacity(); 1003 | std::cout << "making foo grow:\n"; 1004 | for (int i=0; i<100; ++i) { 1005 | foo.push_back(i); 1006 | if (sz!=foo.capacity()) { 1007 | sz = foo.capacity(); 1008 | std::cout << "capacity changed: " << sz << '\n'; 1009 | } 1010 | } 1011 | 1012 | std::vector bar; 1013 | sz = bar.capacity(); 1014 | bar.reserve(100); // this is the only difference with foo above 1015 | std::cout << "making bar grow:\n"; 1016 | for (int i=0; i<100; ++i) { 1017 | bar.push_back(i); 1018 | if (sz!=bar.capacity()) { 1019 | sz = bar.capacity(); 1020 | std::cout << "capacity changed: " << sz << '\n'; 1021 | } 1022 | } 1023 | return 0; 1024 | } 1025 | ``` 1026 | Possible output 1027 | ``` 1028 | making foo grow: 1029 | capacity changed: 1 1030 | capacity changed: 2 1031 | capacity changed: 4 1032 | capacity changed: 8 1033 | capacity changed: 16 1034 | capacity changed: 32 1035 | capacity changed: 64 1036 | capacity changed: 128 1037 | making bar grow: 1038 | capacity changed: 100 1039 | ``` 1040 | #### vector::shrink_to_fit 1041 | 要求容器减小其capacity(容量)以适应其尺寸。 1042 | 1043 | 该请求是非绑定的,并且容器实现可以自由地进行优化,并且保持capacity大于其size的vector。 这可能导致重新分配,但对矢量大小没有影响,并且不能改变其元素。 1044 | ```cpp 1045 | void shrink_to_fit(); 1046 | ``` 1047 | Example 1048 | ```cpp 1049 | #include 1050 | #include 1051 | 1052 | int main () 1053 | { 1054 | std::vector myvector (100); 1055 | std::cout << "1. capacity of myvector: " << myvector.capacity() << '\n'; 1056 | 1057 | myvector.resize(10); 1058 | std::cout << "2. capacity of myvector: " << myvector.capacity() << '\n'; 1059 | 1060 | myvector.shrink_to_fit(); 1061 | std::cout << "3. capacity of myvector: " << myvector.capacity() << '\n'; 1062 | 1063 | return 0; 1064 | } 1065 | ``` 1066 | Possible output 1067 | ``` 1068 | 1. capacity of myvector: 100 1069 | 2. capacity of myvector: 100 1070 | 3. capacity of myvector: 10 1071 | ``` 1072 | #### vector::operator[] 1073 | #### vector::at 1074 | #### vector::front 1075 | #### vector::back 1076 | #### vector::data 1077 | 1078 | #### vector::assign 1079 | 将新内容分配给vector,替换其当前内容,并相应地修改其大小。 1080 | 1081 | 在范围版本(1)中,新内容是从第一个和最后一个范围内的每个元素按相同顺序构造的元素。 1082 | 1083 | 在填充版本(2)中,新内容是n个元素,每个元素都被初始化为一个val的副本。 1084 | 1085 | 在初始化列表版本(3)中,新内容是以相同顺序作为初始化列表传递的值的副本。 1086 | 1087 | 所述内部分配器被用于(通过其性状),以分配和解除分配存储器如果重新分配发生。它也习惯于摧毁所有现有的元素,并构建新的元素。 1088 | ```cpp 1089 | range (1) 1090 | template 1091 | void assign (InputIterator first, InputIterator last); 1092 | fill (2) 1093 | void assign (size_type n, const value_type& val); 1094 | initializer list (3) 1095 | void assign (initializer_list il); 1096 | ``` 1097 | Example 1098 | ```cpp 1099 | #include 1100 | #include 1101 | 1102 | int main () 1103 | { 1104 | std::vector first; 1105 | std::vector second; 1106 | std::vector third; 1107 | 1108 | first.assign (7,100); // 7 ints with a value of 100 1109 | 1110 | std::vector::iterator it; 1111 | it=first.begin()+1; 1112 | 1113 | second.assign (it,first.end()-1); // the 5 central values of first 1114 | 1115 | int myints[] = {1776,7,4}; 1116 | third.assign (myints,myints+3); // assigning from array. 1117 | 1118 | std::cout << "Size of first: " << int (first.size()) << '\n'; 1119 | std::cout << "Size of second: " << int (second.size()) << '\n'; 1120 | std::cout << "Size of third: " << int (third.size()) << '\n'; 1121 | return 0; 1122 | } 1123 | ``` 1124 | Output 1125 | ``` 1126 | Size of first: 7 1127 | Size of second: 5 1128 | Size of third: 3 1129 | ``` 1130 | 1131 | 补充:vector::assign 与 vector::operator= 的区别: 1132 | 1133 | 1. vector::assign 实现源码 1134 | 1135 | ```cpp 1136 | void assign(size_type __n, const _Tp& __val) { _M_fill_assign(__n, __val); } 1137 | 1138 | template 1139 | void vector<_Tp, _Alloc>::_M_fill_assign(size_t __n, const value_type& __val) 1140 | { 1141 | if (__n > capacity()) { 1142 | vector<_Tp, _Alloc> __tmp(__n, __val, get_allocator()); 1143 | __tmp.swap(*this); 1144 | } 1145 | else if (__n > size()) { 1146 | fill(begin(), end(), __val); 1147 | _M_finish = uninitialized_fill_n(_M_finish, __n - size(), __val); 1148 | } 1149 | else 1150 | erase(fill_n(begin(), __n, __val), end()); 1151 | } 1152 | ``` 1153 | 1154 | 2. vector::operator= 实现源码 1155 | 1156 | ```cpp 1157 | template 1158 | vector<_Tp,_Alloc>& 1159 | vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x) 1160 | { 1161 | if (&__x != this) { 1162 | const size_type __xlen = __x.size(); 1163 | if (__xlen > capacity()) { 1164 | iterator __tmp = _M_allocate_and_copy(__xlen, __x.begin(), __x.end()); 1165 | destroy(_M_start, _M_finish); 1166 | _M_deallocate(_M_start, _M_end_of_storage - _M_start); 1167 | _M_start = __tmp; 1168 | _M_end_of_storage = _M_start + __xlen; 1169 | } 1170 | else if (size() >= __xlen) { 1171 | iterator __i = copy(__x.begin(), __x.end(), begin()); 1172 | destroy(__i, _M_finish); 1173 | } 1174 | else { 1175 | copy(__x.begin(), __x.begin() + size(), _M_start); 1176 | uninitialized_copy(__x.begin() + size(), __x.end(), _M_finish); 1177 | } 1178 | _M_finish = _M_start + __xlen; 1179 | } 1180 | return *this; 1181 | } 1182 | ``` 1183 | 1184 | #### vector::push_back 1185 | 在vector的最后一个元素之后添加一个新元素。val的内容被复制(或移动)到新的元素。 1186 | 1187 | 这有效地将容器size增加了一个,如果新的矢量size超过了当前vector的capacity,则导致所分配的存储空间自动重新分配。 1188 | ```cpp 1189 | void push_back (const value_type& val); 1190 | void push_back (value_type&& val); 1191 | ``` 1192 | Example 1193 | ```cpp 1194 | #include 1195 | #include 1196 | 1197 | int main () 1198 | { 1199 | std::vector myvector; 1200 | int myint; 1201 | 1202 | std::cout << "Please enter some integers (enter 0 to end):\n"; 1203 | 1204 | do { 1205 | std::cin >> myint; 1206 | myvector.push_back (myint); 1207 | } while (myint); 1208 | 1209 | std::cout << "myvector stores " << int(myvector.size()) << " numbers.\n"; 1210 | 1211 | return 0; 1212 | } 1213 | ``` 1214 | #### vector::pop_back 1215 | 删除vector中的最后一个元素,有效地将容器size减少一个。 1216 | 1217 | 这破坏了被删除的元素。 1218 | ```cpp 1219 | void pop_back(); 1220 | ``` 1221 | Example 1222 | ```cpp 1223 | #include 1224 | #include 1225 | 1226 | int main () 1227 | { 1228 | std::vector myvector; 1229 | int sum (0); 1230 | myvector.push_back (100); 1231 | myvector.push_back (200); 1232 | myvector.push_back (300); 1233 | 1234 | while (!myvector.empty()) 1235 | { 1236 | sum+=myvector.back(); 1237 | myvector.pop_back(); 1238 | } 1239 | 1240 | std::cout << "The elements of myvector add up to " << sum << '\n'; 1241 | 1242 | return 0; 1243 | } 1244 | ``` 1245 | Output 1246 | ``` 1247 | The elements of myvector add up to 600 1248 | ``` 1249 | #### vector::insert 1250 | 通过在指定位置的元素之前插入新元素来扩展该vector,通过插入元素的数量有效地增加容器大小。 这会导致分配的存储空间自动重新分配,只有在新的vector的size超过当前的vector的capacity的情况下。 1251 | 1252 | 由于vector使用数组作为其基础存储,因此除了将元素插入到vector末尾之后,或vector的begin之前,其他位置会导致容器重新定位位置之后的所有元素到他们的新位置。与其他种类的序列容器(例如list或forward_list)执行相同操作的操作相比,这通常是低效的操作。 1253 | ```cpp 1254 | single element (1) 1255 | iterator insert (const_iterator position, const value_type& val); 1256 | fill (2) 1257 | iterator insert (const_iterator position, size_type n, const value_type& val); 1258 | range (3) 1259 | template 1260 | iterator insert (const_iterator position, InputIterator first, InputIterator last); 1261 | move (4) 1262 | iterator insert (const_iterator position, value_type&& val); 1263 | initializer list (5) 1264 | iterator insert (const_iterator position, initializer_list il); 1265 | ``` 1266 | Example 1267 | ```cpp 1268 | #include 1269 | #include 1270 | 1271 | int main () 1272 | { 1273 | std::vector myvector (3,100); 1274 | std::vector::iterator it; 1275 | 1276 | it = myvector.begin(); 1277 | it = myvector.insert ( it , 200 ); 1278 | 1279 | myvector.insert (it,2,300); 1280 | 1281 | // "it" no longer valid, get a new one: 1282 | it = myvector.begin(); 1283 | 1284 | std::vector anothervector (2,400); 1285 | myvector.insert (it+2,anothervector.begin(),anothervector.end()); 1286 | 1287 | int myarray [] = { 501,502,503 }; 1288 | myvector.insert (myvector.begin(), myarray, myarray+3); 1289 | 1290 | std::cout << "myvector contains:"; 1291 | for (it=myvector.begin(); it v(5, 0); 1309 | std::vector::iterator vi; 1310 | 1311 | // 获取vector第一个元素的迭代器 1312 | vi = v.begin(); 1313 | 1314 | // push_back 插入元素之后可能会因为 push_back 的骚操作(创建一个新vector把旧vector的值复制到新vector),导致vector迭代器iterator的指针变成野指针,而导致insert出错 1315 | v.push_back(10); 1316 | 1317 | v.insert(vi, 2, 300); 1318 | 1319 | return 0; 1320 | } 1321 | ``` 1322 | 改正:应该把`vi = v.begin();`放到`v.push_back(10);`后面 1323 | #### vector::erase 1324 | 从vector中删除单个元素(position)或一系列元素([first,last))。 1325 | 1326 | 这有效地减少了被去除的元素的数量,从而破坏了容器的大小。 1327 | 1328 | 由于vector使用一个数组作为其底层存储,所以删除除vector结束位置之后,或vector的begin之前的元素外,将导致容器将段被擦除后的所有元素重新定位到新的位置。与其他种类的序列容器(例如list或forward_list)执行相同操作的操作相比,这通常是低效的操作。 1329 | ```cpp 1330 | iterator erase (const_iterator position); 1331 | iterator erase (const_iterator first, const_iterator last); 1332 | ``` 1333 | Example 1334 | ```cpp 1335 | #include 1336 | #include 1337 | 1338 | int main () 1339 | { 1340 | std::vector myvector; 1341 | 1342 | // set some values (from 1 to 10) 1343 | for (int i=1; i<=10; i++) myvector.push_back(i); 1344 | 1345 | // erase the 6th element 1346 | myvector.erase (myvector.begin()+5); 1347 | 1348 | // erase the first 3 elements: 1349 | myvector.erase (myvector.begin(),myvector.begin()+3); 1350 | 1351 | std::cout << "myvector contains:"; 1352 | for (unsigned i=0; i 1375 | #include 1376 | 1377 | int main () 1378 | { 1379 | std::vector foo (3,100); // three ints with a value of 100 1380 | std::vector bar (5,200); // five ints with a value of 200 1381 | 1382 | foo.swap(bar); 1383 | 1384 | std::cout << "foo contains:"; 1385 | for (unsigned i=0; i().swap(x); // clear x reallocating ` 1406 | ```cpp 1407 | void clear() noexcept; 1408 | ``` 1409 | Example 1410 | ```cpp 1411 | #include 1412 | #include 1413 | 1414 | void printVector(const std::vector &v) 1415 | { 1416 | for (auto it = v.begin(); it != v.end(); ++it) 1417 | { 1418 | std::cout << *it << ' '; 1419 | } 1420 | std::cout << std::endl; 1421 | } 1422 | 1423 | int main() 1424 | { 1425 | std::vector v1(5, 50); 1426 | 1427 | printVector(v1); 1428 | std::cout << "v1 size = " << v1.size() << std::endl; 1429 | std::cout << "v1 capacity = " << v1.capacity() << std::endl; 1430 | 1431 | v1.clear(); 1432 | 1433 | printVector(v1); 1434 | std::cout << "v1 size = " << v1.size() << std::endl; 1435 | std::cout << "v1 capacity = " << v1.capacity() << std::endl; 1436 | 1437 | v1.push_back(11); 1438 | v1.push_back(22); 1439 | 1440 | printVector(v1); 1441 | std::cout << "v1 size = " << v1.size() << std::endl; 1442 | std::cout << "v1 capacity = " << v1.capacity() << std::endl; 1443 | 1444 | return 0; 1445 | } 1446 | ``` 1447 | Output 1448 | ``` 1449 | 50 50 50 50 50 1450 | v1 size = 5 1451 | v1 capacity = 5 1452 | 1453 | v1 size = 0 1454 | v1 capacity = 5 1455 | 11 22 1456 | v1 size = 2 1457 | v1 capacity = 5 1458 | ``` 1459 | #### vector::emplace 1460 | 通过在position位置处插入新元素args来扩展容器。这个新元素是用args作为构建的参数来构建的。 1461 | 1462 | 这有效地增加了一个容器的大小。 1463 | 1464 | 分配存储空间的自动重新分配发生在新的vector的size超过当前向量容量的情况下。 1465 | 1466 | 由于vector使用数组作为其基础存储,因此除了将元素插入到vector末尾之后,或vector的begin之前,其他位置会导致容器重新定位位置之后的所有元素到他们的新位置。与其他种类的序列容器(例如list或forward_list)执行相同操作的操作相比,这通常是低效的操作。 1467 | 1468 | 该元素是通过调用allocator_traits::construct来转换args来创建的。插入一个类似的成员函数,将现有对象复制或移动到容器中。 1469 | 1470 | ```cpp 1471 | template 1472 | iterator emplace (const_iterator position, Args&&... args); 1473 | ``` 1474 | Example 1475 | ```cpp 1476 | #include 1477 | #include 1478 | 1479 | int main () 1480 | { 1481 | std::vector myvector = {10,20,30}; 1482 | 1483 | auto it = myvector.emplace ( myvector.begin()+1, 100 ); 1484 | myvector.emplace ( it, 200 ); 1485 | myvector.emplace ( myvector.end(), 300 ); 1486 | 1487 | std::cout << "myvector contains:"; 1488 | for (auto& x: myvector) 1489 | std::cout << ' ' << x; 1490 | std::cout << '\n'; 1491 | 1492 | return 0; 1493 | } 1494 | ``` 1495 | Output 1496 | ``` 1497 | myvector contains: 10 200 100 20 30 300 1498 | ``` 1499 | #### vector::emplace_back 1500 | 在vector的末尾插入一个新的元素,紧跟在当前的最后一个元素之后。这个新元素是用args作为构造函数的参数来构造的。 1501 | 1502 | 这有效地将容器大小增加了一个,如果新的矢量大小超过了当前的vector容量,则导致所分配的存储空间自动重新分配。 1503 | 1504 | 该元素是通过调用allocator_traits :: construct来转换args来创建的。 1505 | 1506 | 与push\_back相比,emplace\_back可以避免额外的复制和移动操作。 1507 | ```cpp 1508 | template 1509 | void emplace_back (Args&&... args); 1510 | ``` 1511 | 1512 | Example 1513 | 1514 | ```cpp 1515 | #include 1516 | #include 1517 | #include 1518 | 1519 | struct President 1520 | { 1521 | std::string name; 1522 | std::string country; 1523 | int year; 1524 | 1525 | President(std::string p_name, std::string p_country, int p_year) 1526 | : name(std::move(p_name)), country(std::move(p_country)), year(p_year) 1527 | { 1528 | std::cout << "I am being constructed.\n"; 1529 | } 1530 | President(President&& other) 1531 | : name(std::move(other.name)), country(std::move(other.country)), year(other.year) 1532 | { 1533 | std::cout << "I am being moved.\n"; 1534 | } 1535 | President& operator=(const President& other) = default; 1536 | }; 1537 | 1538 | int main() 1539 | { 1540 | std::vector elections; 1541 | std::cout << "emplace_back:\n"; 1542 | elections.emplace_back("Nelson Mandela", "South Africa", 1994); 1543 | 1544 | std::vector reElections; 1545 | std::cout << "\npush_back:\n"; 1546 | reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936)); 1547 | 1548 | std::cout << "\nContents:\n"; 1549 | for (President const& president: elections) { 1550 | std::cout << president.name << " was elected president of " 1551 | << president.country << " in " << president.year << ".\n"; 1552 | } 1553 | for (President const& president: reElections) { 1554 | std::cout << president.name << " was re-elected president of " 1555 | << president.country << " in " << president.year << ".\n"; 1556 | } 1557 | } 1558 | ``` 1559 | 1560 | Output 1561 | 1562 | ``` 1563 | emplace_back: 1564 | I am being constructed. 1565 | 1566 | push_back: 1567 | I am being constructed. 1568 | I am being moved. 1569 | 1570 | Contents: 1571 | Nelson Mandela was elected president of South Africa in 1994. 1572 | Franklin Delano Roosevelt was re-elected president of the USA in 1936. 1573 | ``` 1574 | #### vector::get_allocator 1575 | 返回与vector关联的构造器对象的副本。 1576 | ```cpp 1577 | allocator_type get_allocator() const noexcept; 1578 | ``` 1579 | Example 1580 | ```cpp 1581 | #include 1582 | #include 1583 | 1584 | int main () 1585 | { 1586 | std::vector myvector; 1587 | int * p; 1588 | unsigned int i; 1589 | 1590 | // allocate an array with space for 5 elements using vector's allocator: 1591 | p = myvector.get_allocator().allocate(5); 1592 | 1593 | // construct values in-place on the array: 1594 | for (i=0; i<5; i++) myvector.get_allocator().construct(&p[i],i); 1595 | 1596 | std::cout << "The allocated array contains:"; 1597 | for (i=0; i<5; i++) std::cout << ' ' << p[i]; 1598 | std::cout << '\n'; 1599 | 1600 | // destroy and deallocate: 1601 | for (i=0; i<5; i++) myvector.get_allocator().destroy(&p[i]); 1602 | myvector.get_allocator().deallocate(p,5); 1603 | 1604 | return 0; 1605 | } 1606 | ``` 1607 | Output 1608 | ``` 1609 | The allocated array contains: 0 1 2 3 4 1610 | ``` 1611 | 1612 | 注意:deallocate和destory的关系: 1613 | 1614 | deallocate实现的源码: 1615 | 1616 | template 1617 | inline void _deallocate(T* buffer) 1618 | { 1619 | ::operator delete(buffer); //为什么不用 delete [] ? ,operator delete 区别于 delete 1620 | //operator delete 是一个底层操作符 1621 | } 1622 | 1623 | destory: 1624 | 1625 | template 1626 | inline void _destory(T *ptr) 1627 | { 1628 | ptr->~T(); 1629 | } 1630 | 1631 | destory负责调用类型的析构函数,销毁相应内存上的内容(但销毁后内存地址仍保留) 1632 | 1633 | deallocate负责释放内存(此时相应内存中的值在此之前应调用destory销毁,将内存地址返回给系统,代表这部分地址使用引用-1) 1634 | 1635 | 1636 | 1637 | 1638 | #### relational operators (vector) 1639 | #### swap (vector) 1640 | #### vector 1641 | 1642 | ### deque 1643 | deque(['dek])(双端队列)是double-ended queue 的一个不规则缩写。deque是具有动态大小的序列容器,可以在两端(前端或后端)扩展或收缩。 1644 | 1645 | 特定的库可以以不同的方式实现deques,通常作为某种形式的动态数组。但是在任何情况下,它们都允许通过随机访问迭代器直接访问各个元素,通过根据需要扩展和收缩容器来自动处理存储。 1646 | 1647 | 因此,它们提供了类似于vector的功能,但是在序列的开始部分也可以高效地插入和删除元素,而不仅仅是在结尾。但是,与vector不同,deques并不保证将其所有元素存储在连续的存储位置:deque通过偏移指向另一个元素的指针访问元素会导致未定义的行为。 1648 | 1649 | 两个vector和deques提供了一个非常相似的接口,可以用于类似的目的,但内部工作方式完全不同:虽然vector使用单个数组需要偶尔重新分配以增长,但是deque的元素可以分散在不同的块的容器,容器在内部保存必要的信息以提供对其任何元素的持续时间和统一的顺序接口(通过迭代器)的直接访问。因此,deques在内部比vector更复杂一点,但是这使得他们在某些情况下更有效地增长,尤其是在重新分配变得更加昂贵的很长序列的情况下。 1650 | 1651 | 对于频繁插入或删除开始或结束位置以外的元素的操作,deques表现得更差,并且与列表和转发列表相比,迭代器和引用的一致性更低。 1652 | 1653 | deque上常见操作的复杂性(效率)如下: 1654 | 1655 | * 随机访问 - 常数O(1) 1656 | * 在结尾或开头插入或移除元素 - 摊销不变O(1) 1657 | * 插入或移除元素 - 线性O(n) 1658 | ```cpp 1659 | template < class T, class Alloc = allocator > class deque; 1660 | ``` 1661 | ![](http://img.blog.csdn.net/20170727225856144?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRlg2Nzc1ODg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 1662 | ![](https://images0.cnblogs.com/blog/559453/201401/092150340824.png) 1663 | 1664 | #### deque::deque 1665 | 1666 | 构造一个deque容器对象,根据所使用的构造函数版本初始化它的内容: 1667 | 1668 | Example 1669 | ```cpp 1670 | #include 1671 | #include 1672 | 1673 | int main () 1674 | { 1675 | unsigned int i; 1676 | 1677 | // constructors used in the same order as described above: 1678 | std::deque first; // empty deque of ints 1679 | std::deque second (4,100); // four ints with value 100 1680 | std::deque third (second.begin(),second.end()); // iterating through second 1681 | std::deque fourth (third); // a copy of third 1682 | 1683 | // the iterator constructor can be used to copy arrays: 1684 | int myints[] = {16,2,77,29}; 1685 | std::deque fifth (myints, myints + sizeof(myints) / sizeof(int) ); 1686 | 1687 | std::cout << "The contents of fifth are:"; 1688 | for (std::deque::iterator it = fifth.begin(); it!=fifth.end(); ++it) 1689 | std::cout << ' ' << *it; 1690 | 1691 | std::cout << '\n'; 1692 | 1693 | return 0; 1694 | } 1695 | ``` 1696 | Output 1697 | ``` 1698 | The contents of fifth are: 16 2 77 29 1699 | ``` 1700 | #### deque::push_back 1701 | 在当前的最后一个元素之后 ,在deque容器的末尾添加一个新元素。val的内容被复制(或移动)到新的元素。 1702 | 1703 | 这有效地增加了一个容器的大小。 1704 | ```cpp 1705 | void push_back (const value_type& val); 1706 | void push_back (value_type&& val); 1707 | ``` 1708 | Example 1709 | ```cpp 1710 | #include 1711 | #include 1712 | 1713 | int main () 1714 | { 1715 | std::deque mydeque; 1716 | int myint; 1717 | 1718 | std::cout << "Please enter some integers (enter 0 to end):\n"; 1719 | 1720 | do { 1721 | std::cin >> myint; 1722 | mydeque.push_back (myint); 1723 | } while (myint); 1724 | 1725 | std::cout << "mydeque stores " << (int) mydeque.size() << " numbers.\n"; 1726 | 1727 | return 0; 1728 | } 1729 | ``` 1730 | #### deque::push_front 1731 | 在deque容器的开始位置插入一个新的元素,位于当前的第一个元素之前。val的内容被复制(或移动)到插入的元素。 1732 | 1733 | 这有效地增加了一个容器的大小。 1734 | ```cpp 1735 | void push_front (const value_type& val); 1736 | void push_front (value_type&& val); 1737 | ``` 1738 | Example 1739 | ```cpp 1740 | #include 1741 | #include 1742 | 1743 | int main () 1744 | { 1745 | std::deque mydeque (2,100); // two ints with a value of 100 1746 | mydeque.push_front (200); 1747 | mydeque.push_front (300); 1748 | 1749 | std::cout << "mydeque contains:"; 1750 | for (std::deque::iterator it = mydeque.begin(); it != mydeque.end(); ++it) 1751 | std::cout << ' ' << *it; 1752 | std::cout << '\n'; 1753 | 1754 | return 0; 1755 | } 1756 | ``` 1757 | Output 1758 | ``` 1759 | 300 200 100 100 1760 | ``` 1761 | #### deque::pop_back 1762 | 删除deque容器中的最后一个元素,有效地将容器大小减少一个。 1763 | 1764 | 这破坏了被删除的元素。 1765 | 1766 | ```cpp 1767 | void pop_back(); 1768 | ``` 1769 | Example 1770 | ```cpp 1771 | #include 1772 | #include 1773 | 1774 | int main () 1775 | { 1776 | std::deque mydeque; 1777 | int sum (0); 1778 | mydeque.push_back (10); 1779 | mydeque.push_back (20); 1780 | mydeque.push_back (30); 1781 | 1782 | while (!mydeque.empty()) 1783 | { 1784 | sum+=mydeque.back(); 1785 | mydeque.pop_back(); 1786 | } 1787 | 1788 | std::cout << "The elements of mydeque add up to " << sum << '\n'; 1789 | 1790 | return 0; 1791 | } 1792 | ``` 1793 | Output 1794 | ``` 1795 | The elements of mydeque add up to 60 1796 | ``` 1797 | #### deque::pop_front 1798 | 删除deque容器中的第一个元素,有效地减小其大小。 1799 | 1800 | 这破坏了被删除的元素。 1801 | ```cpp 1802 | void pop_front(); 1803 | ``` 1804 | Example 1805 | ```cpp 1806 | #include 1807 | #include 1808 | 1809 | int main () 1810 | { 1811 | std::deque mydeque; 1812 | 1813 | mydeque.push_back (100); 1814 | mydeque.push_back (200); 1815 | mydeque.push_back (300); 1816 | 1817 | std::cout << "Popping out the elements in mydeque:"; 1818 | while (!mydeque.empty()) 1819 | { 1820 | std::cout << ' ' << mydeque.front(); 1821 | mydeque.pop_front(); 1822 | } 1823 | 1824 | std::cout << "\nThe final size of mydeque is " << int(mydeque.size()) << '\n'; 1825 | 1826 | return 0; 1827 | } 1828 | ``` 1829 | Output 1830 | ``` 1831 | Popping out the elements in mydeque: 100 200 300 1832 | The final size of mydeque is 0 1833 | ``` 1834 | #### deque::emplace_front 1835 | 在deque的开头插入一个新的元素,就在其当前的第一个元素之前。这个新的元素是用args作为构建的参数来构建的。 1836 | 1837 | 这有效地增加了一个容器的大小。 1838 | 1839 | 该元素是通过调用allocator_traits::construct来转换args来创建的。 1840 | 1841 | 存在一个类似的成员函数push_front,它可以将现有对象复制或移动到容器中。 1842 | ```cpp 1843 | template 1844 | void emplace_front (Args&&... args); 1845 | ``` 1846 | Example 1847 | ```cpp 1848 | #include 1849 | #include 1850 | 1851 | int main () 1852 | { 1853 | std::deque mydeque = {10,20,30}; 1854 | 1855 | mydeque.emplace_front (111); 1856 | mydeque.emplace_front (222); 1857 | 1858 | std::cout << "mydeque contains:"; 1859 | for (auto& x: mydeque) 1860 | std::cout << ' ' << x; 1861 | std::cout << '\n'; 1862 | 1863 | return 0; 1864 | } 1865 | ``` 1866 | Output 1867 | ``` 1868 | mydeque contains: 222 111 10 20 30 1869 | ``` 1870 | #### deque::emplace_back 1871 | 在deque的末尾插入一个新的元素,紧跟在当前的最后一个元素之后。这个新的元素是用args作为构建的参数来构建的。 1872 | 1873 | 这有效地增加了一个容器的大小。 1874 | 1875 | 该元素是通过调用allocator_traits::construct来转换args来创建的。 1876 | 1877 | 存在一个类似的成员函数push_back,它可以将现有对象复制或移动到容器中 1878 | ```cpp 1879 | template 1880 | void emplace_back (Args&&... args); 1881 | ``` 1882 | Example 1883 | ```cpp 1884 | #include 1885 | #include 1886 | 1887 | int main () 1888 | { 1889 | std::deque mydeque = {10,20,30}; 1890 | 1891 | mydeque.emplace_back (100); 1892 | mydeque.emplace_back (200); 1893 | 1894 | std::cout << "mydeque contains:"; 1895 | for (auto& x: mydeque) 1896 | std::cout << ' ' << x; 1897 | std::cout << '\n'; 1898 | 1899 | return 0; 1900 | } 1901 | ``` 1902 | Output 1903 | ``` 1904 | mydeque contains: 10 20 30 100 200 1905 | ``` 1906 | ### forward\_list 1907 | 1908 | forward_list(单向链表)是序列容器,允许在序列中的任何地方进行恒定的时间插入和擦除操作。 1909 | 1910 | forward\_list(单向链表)被实现为单链表; 单链表可以将它们包含的每个元素存储在不同和不相关的存储位置中。通过关联到序列中下一个元素的链接的每个元素来保留排序。forward\_list容器和列表 1911 | 1912 | 之间的主要设计区别容器是第一个内部只保留一个到下一个元素的链接,而后者每个元素保留两个链接:一个指向下一个元素,一个指向前一个元素,允许在两个方向上有效的迭代,但是每个元素消耗额外的存储空间并且插入和移除元件的时间开销略高。因此,forward_list对象比列表对象更有效率,尽管它们只能向前迭代。 1913 | 1914 | 与其他基本的标准序列容器(array,vector和deque),forward_list通常在插入,提取和移动容器内任何位置的元素方面效果更好,因此也适用于密集使用这些元素的算法,如排序算法。 1915 | 1916 | 的主要缺点修饰符Modifiers S和列表相比这些其它序列容器s是说,他们缺乏可以通过位置的元素的直接访问; 例如,要访问forward_list中的第六个元素,必须从开始位置迭代到该位置,这需要在这些位置之间的线性时间。它们还消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是大型小元素列表的重要因素)。 1917 | 1918 | 该修饰符Modifiersclass模板的设计考虑到效率:按照设计,它与简单的手写C型单链表一样高效,实际上是唯一的标准容器,为了效率的考虑故意缺少尺寸成员函数:由于其性质作为一个链表,具有一个需要一定时间的大小的成员将需要它保持一个内部计数器的大小(如列表所示)。这会消耗一些额外的存储空间,并使插入和删除操作效率稍低。要获取forward_list对象的大小,可以使用距离算法的开始和结束,这是一个需要线性时间的操作。 1919 | 1920 | ![](http://img.blog.csdn.net/20160407212133266) 1921 | 1922 | #### forward\_list::forward\_list 1923 | 1924 | ```cpp 1925 | default (1) 1926 | explicit forward_list (const allocator_type& alloc = allocator_type()); 1927 | fill (2) 1928 | explicit forward_list (size_type n); 1929 | explicit forward_list (size_type n, const value_type& val, 1930 | const allocator_type& alloc = allocator_type()); 1931 | range (3) 1932 | template 1933 | forward_list (InputIterator first, InputIterator last, 1934 | const allocator_type& alloc = allocator_type()); 1935 | copy (4) 1936 | forward_list (const forward_list& fwdlst); 1937 | forward_list (const forward_list& fwdlst, const allocator_type& alloc); 1938 | move (5) 1939 | forward_list (forward_list&& fwdlst); 1940 | forward_list (forward_list&& fwdlst, const allocator_type& alloc); 1941 | initializer list (6) 1942 | forward_list (initializer_list il, 1943 | const allocator_type& alloc = allocator_type()); 1944 | ``` 1945 | Example 1946 | ```cpp 1947 | #include 1948 | #include 1949 | 1950 | int main () 1951 | { 1952 | // constructors used in the same order as described above: 1953 | 1954 | std::forward_list first; // default: empty 1955 | std::forward_list second (3,77); // fill: 3 seventy-sevens 1956 | std::forward_list third (second.begin(), second.end()); // range initialization 1957 | std::forward_list fourth (third); // copy constructor 1958 | std::forward_list fifth (std::move(fourth)); // move ctor. (fourth wasted) 1959 | std::forward_list sixth = {3, 52, 25, 90}; // initializer_list constructor 1960 | 1961 | std::cout << "first:" ; for (int& x: first) std::cout << " " << x; std::cout << '\n'; 1962 | std::cout << "second:"; for (int& x: second) std::cout << " " << x; std::cout << '\n'; 1963 | std::cout << "third:"; for (int& x: third) std::cout << " " << x; std::cout << '\n'; 1964 | std::cout << "fourth:"; for (int& x: fourth) std::cout << " " << x; std::cout << '\n'; 1965 | std::cout << "fifth:"; for (int& x: fifth) std::cout << " " << x; std::cout << '\n'; 1966 | std::cout << "sixth:"; for (int& x: sixth) std::cout << " " << x; std::cout << '\n'; 1967 | 1968 | return 0; 1969 | } 1970 | ``` 1971 | Possible output 1972 | ``` 1973 | forward_list constructor examples: 1974 | first: 1975 | second: 77 77 77 1976 | third: 77 77 77 1977 | fourth: 1978 | fifth: 77 77 77 1979 | sixth: 3 52 25 90 1980 | ``` 1981 | 1982 | #### forward\_list::~forward\_list 1983 | 1984 | #### forward\_list::before\_begin 1985 | 返回指向容器中第一个元素之前的位置的迭代器。 1986 | 1987 | 返回的迭代器不应被解除引用:它是为了用作成员函数的参数emplace\_after,insert\_after,erase\_after或splice\_after,指定序列,其中执行该动作的位置的开始位置。 1988 | 1989 | ```cpp 1990 | iterator before_begin() noexcept; 1991 | const_iterator before_begin() const noexcept; 1992 | ``` 1993 | Example 1994 | ```cpp 1995 | #include 1996 | #include 1997 | 1998 | int main () 1999 | { 2000 | std::forward_list mylist = {20, 30, 40, 50}; 2001 | 2002 | mylist.insert_after ( mylist.before_begin(), 11 ); 2003 | 2004 | std::cout << "mylist contains:"; 2005 | for ( int& x: mylist ) std::cout << ' ' << x; 2006 | std::cout << '\n'; 2007 | 2008 | return 0; 2009 | } 2010 | ``` 2011 | Output 2012 | ``` 2013 | mylist contains: 11 20 30 40 50 2014 | ``` 2015 | #### forward\_list::cbefore\_begin 2016 | 返回指向容器中第一个元素之前的位置的const_iterator。 2017 | 2018 | 一个常量性是指向常量内容的迭代器。这个迭代器可以增加和减少(除非它本身也是const),就像forward\_list::before\_begin返回的迭代器一样,但不能用来修改它指向的内容。 2019 | 2020 | 返回的价值不得解除引用。 2021 | ```cpp 2022 | const_iterator cbefore_begin() const noexcept; 2023 | ``` 2024 | Example 2025 | ```cpp 2026 | #include 2027 | #include 2028 | 2029 | int main () 2030 | { 2031 | std::forward_list mylist = {77, 2, 16}; 2032 | 2033 | mylist.insert_after ( mylist.cbefore_begin(), 19 ); 2034 | 2035 | std::cout << "mylist contains:"; 2036 | for ( int& x: mylist ) std::cout << ' ' << x; 2037 | std::cout << '\n'; 2038 | 2039 | return 0; 2040 | } 2041 | ``` 2042 | Output 2043 | ``` 2044 | mylist contains: 19 77 2 16 2045 | ``` 2046 | 2047 | ### list 2048 | 2049 | ### stack 2050 | 2051 | ### queue 2052 | 2053 | ### priority_queue 2054 | 2055 | ### set 2056 | 2057 | ### multiset 2058 | 2059 | ### map 2060 | 2061 | map 是关联容器,按照特定顺序存储由 key value (键值) 和 mapped value (映射值) 组合形成的元素。 2062 | 2063 | 在映射中,键值通常用于对元素进行排序和唯一标识,而映射的值存储与此键关联的内容。该类型的键和映射的值可能不同,并且在部件类型被分组在一起VALUE_TYPE,这是一种对类型结合两种: 2064 | 2065 | ```cpp 2066 | typedef pair value_type; 2067 | ``` 2068 | 2069 | 在内部,映射中的元素总是按照由其内部比较对象(比较类型)指示的特定的严格弱排序标准按键排序。映射容器通常比unordered_map容器慢,以通过它们的键来访问各个元素,但是它们允许基于它们的顺序对子集进行直接迭代。 在该映射值地图可以直接通过使用其相应的键来访问括号运算符((操作符[] )。 映射通常如实施 2070 | 2071 | ```cpp 2072 | template < class Key, // map::key_type 2073 | class T, // map::mapped_type 2074 | class Compare = less, // map::key_compare 2075 | class Alloc = allocator > // map::allocator_type 2076 | > class map; 2077 | ``` 2078 | 2079 | #### map::map 2080 | 构造一个映射容器对象,根据所使用的构造器版本初始化其内容: 2081 | 2082 | (1)空容器构造函数(默认构造函数) 2083 | 2084 | 构造一个空的容器,没有元素。 2085 | 2086 | (2)范围构造函数 2087 | 2088 | 构造具有一样多的元素的范围内的容器[第一,最后一个),其中每个元件布设构造的从在该范围内它的相应的元件。 2089 | 2090 | (3)复制构造函数(并用分配器复制) 2091 | 2092 | 使用x中的每个元素的副本构造一个容器。 2093 | 2094 | (4)移动构造函数(并与分配器一起移动) 2095 | 2096 | 构造一个获取x元素的容器。 2097 | 如果指定了alloc并且与x的分配器不同,那么元素将被移动。否则,没有构建元素(他们的所有权直接转移)。 2098 | x保持未指定但有效的状态。 2099 | 2100 | (5)初始化列表构造函数 2101 | 2102 | 用il中的每个元素的副本构造一个容器。 2103 | 2104 | ```cpp 2105 | empty (1) 2106 | explicit map (const key_compare& comp = key_compare(), 2107 | const allocator_type& alloc = allocator_type()); 2108 | explicit map (const allocator_type& alloc); 2109 | range (2) 2110 | template 2111 | map (InputIterator first, InputIterator last, 2112 | const key_compare& comp = key_compare(), 2113 | const allocator_type& = allocator_type()); 2114 | copy (3) 2115 | map (const map& x); 2116 | map (const map& x, const allocator_type& alloc); 2117 | move (4) 2118 | map (map&& x); 2119 | map (map&& x, const allocator_type& alloc); 2120 | initializer list (5) 2121 | map (initializer_list il, 2122 | const key_compare& comp = key_compare(), 2123 | const allocator_type& alloc = allocator_type()); 2124 | ``` 2125 | Example 2126 | ```cpp 2127 | #include 2128 | #include 2129 | 2130 | bool fncomp (char lhs, char rhs) {return lhs first; 2140 | 2141 | first['a']=10; 2142 | first['b']=30; 2143 | first['c']=50; 2144 | first['d']=70; 2145 | 2146 | std::map second (first.begin(),first.end()); 2147 | 2148 | std::map third (second); 2149 | 2150 | std::map fourth; // class as Compare 2151 | 2152 | bool(*fn_pt)(char,char) = fncomp; 2153 | std::map fifth (fn_pt); // function pointer as Compare 2154 | 2155 | return 0; 2156 | } 2157 | ``` 2158 | #### map::begin 2159 | 返回引用map容器中第一个元素的迭代器。 2160 | 2161 | 由于map容器始终保持其元素的顺序,所以开始指向遵循容器排序标准的元素。 2162 | 2163 | 如果容器是空的,则返回的迭代器值不应被解除引用。 2164 | ```cpp 2165 | iterator begin() noexcept; 2166 | const_iterator begin() const noexcept; 2167 | ``` 2168 | Example 2169 | ```cpp 2170 | #include 2171 | #include 2172 | 2173 | int main () 2174 | { 2175 | std::map mymap; 2176 | 2177 | mymap['b'] = 100; 2178 | mymap['a'] = 200; 2179 | mymap['c'] = 300; 2180 | 2181 | // show content: 2182 | for (std::map::iterator it=mymap.begin(); it!=mymap.end(); ++it) 2183 | std::cout << it->first << " => " << it->second << '\n'; 2184 | 2185 | return 0; 2186 | } 2187 | ``` 2188 | Output 2189 | ``` 2190 | a => 200 2191 | b => 100 2192 | c => 300 2193 | ``` 2194 | 2195 | #### map::key_comp 2196 | 返回容器用于比较键的比较对象的副本。 2197 | 2198 | ```cpp 2199 | key_compare key_comp() const; 2200 | ``` 2201 | Example 2202 | ```cpp 2203 | #include 2204 | #include 2205 | 2206 | int main () 2207 | { 2208 | std::map mymap; 2209 | 2210 | std::map::key_compare mycomp = mymap.key_comp(); 2211 | 2212 | mymap['a']=100; 2213 | mymap['b']=200; 2214 | mymap['c']=300; 2215 | 2216 | std::cout << "mymap contains:\n"; 2217 | 2218 | char highest = mymap.rbegin()->first; // key value of last element 2219 | 2220 | std::map::iterator it = mymap.begin(); 2221 | do { 2222 | std::cout << it->first << " => " << it->second << '\n'; 2223 | } while ( mycomp((*it++).first, highest) ); 2224 | 2225 | std::cout << '\n'; 2226 | 2227 | return 0; 2228 | } 2229 | ``` 2230 | Output 2231 | ``` 2232 | mymap contains: 2233 | a => 100 2234 | b => 200 2235 | c => 300 2236 | ``` 2237 | #### map::value_comp 2238 | 返回可用于比较两个元素的比较对象,以获取第一个元素的键是否在第二个元素之前。 2239 | 2240 | ```cpp 2241 | value_compare value_comp() const; 2242 | ``` 2243 | Example 2244 | ```cpp 2245 | #include 2246 | #include 2247 | 2248 | int main () 2249 | { 2250 | std::map mymap; 2251 | 2252 | mymap['x']=1001; 2253 | mymap['y']=2002; 2254 | mymap['z']=3003; 2255 | 2256 | std::cout << "mymap contains:\n"; 2257 | 2258 | std::pair highest = *mymap.rbegin(); // last element 2259 | 2260 | std::map::iterator it = mymap.begin(); 2261 | do { 2262 | std::cout << it->first << " => " << it->second << '\n'; 2263 | } while ( mymap.value_comp()(*it++, highest) ); 2264 | 2265 | return 0; 2266 | } 2267 | ``` 2268 | Output 2269 | ``` 2270 | mymap contains: 2271 | x => 1001 2272 | y => 2002 2273 | z => 3003 2274 | ``` 2275 | #### map::find 2276 | 在容器中搜索具有等于k的键的元素,如果找到则返回一个迭代器,否则返回map::end的迭代器。 2277 | 2278 | 如果容器的比较对象自反地返回假(即,不管元素作为参数传递的顺序),则两个key被认为是等同的。 2279 | 2280 | 另一个成员函数map::count可以用来检查一个特定的键是否存在。 2281 | ```cpp 2282 | iterator find (const key_type& k); 2283 | const_iterator find (const key_type& k) const; 2284 | ``` 2285 | Example 2286 | ```cpp 2287 | #include 2288 | #include 2289 | 2290 | int main () 2291 | { 2292 | std::map mymap; 2293 | std::map::iterator it; 2294 | 2295 | mymap['a']=50; 2296 | mymap['b']=100; 2297 | mymap['c']=150; 2298 | mymap['d']=200; 2299 | 2300 | it = mymap.find('b'); 2301 | if (it != mymap.end()) 2302 | mymap.erase (it); 2303 | 2304 | // print content: 2305 | std::cout << "elements in mymap:" << '\n'; 2306 | std::cout << "a => " << mymap.find('a')->second << '\n'; 2307 | std::cout << "c => " << mymap.find('c')->second << '\n'; 2308 | std::cout << "d => " << mymap.find('d')->second << '\n'; 2309 | 2310 | return 0; 2311 | } 2312 | ``` 2313 | Output 2314 | ``` 2315 | elements in mymap: 2316 | a => 50 2317 | c => 150 2318 | d => 200 2319 | ``` 2320 | #### map::count 2321 | 在容器中搜索具有等于k的键的元素,并返回匹配的数量。 2322 | 2323 | 由于地图容器中的所有元素都是唯一的,因此该函数只能返回1(如果找到该元素)或返回零(否则)。 2324 | 2325 | 如果容器的比较对象自反地返回错误(即,不管按键作为参数传递的顺序),则两个键被认为是等同的。 2326 | ```cpp 2327 | size_type count (const key_type& k) const; 2328 | ``` 2329 | Example 2330 | ```cpp 2331 | #include 2332 | #include 2333 | 2334 | int main () 2335 | { 2336 | std::map mymap; 2337 | char c; 2338 | 2339 | mymap ['a']=101; 2340 | mymap ['c']=202; 2341 | mymap ['f']=303; 2342 | 2343 | for (c='a'; c<'h'; c++) 2344 | { 2345 | std::cout << c; 2346 | if (mymap.count(c)>0) 2347 | std::cout << " is an element of mymap.\n"; 2348 | else 2349 | std::cout << " is not an element of mymap.\n"; 2350 | } 2351 | 2352 | return 0; 2353 | } 2354 | ``` 2355 | Output 2356 | ``` 2357 | a is an element of mymap. 2358 | b is not an element of mymap. 2359 | c is an element of mymap. 2360 | d is not an element of mymap. 2361 | e is not an element of mymap. 2362 | f is an element of mymap. 2363 | g is not an element of mymap. 2364 | ``` 2365 | 2366 | #### map::lower_bound 2367 | 将迭代器返回到下限 2368 | 2369 | 返回指向容器中第一个元素的迭代器,该元素的键不会在k之前出现(即,它是等价的或者在其后)。 2370 | 2371 | 该函数使用其内部比较对象(key\_comp)来确定这一点,将迭代器返回到key\_comp(element\_key,k)将返回false的第一个元素。 2372 | 2373 | 如果map类用默认的比较类型(less)实例化,则函数返回一个迭代器到第一个元素,其键不小于k。 2374 | 2375 | 一个类似的成员函数upper\_bound具有相同的行为lower\_bound,除非映射包含一个key值等于k的元素:在这种情况下,lower\_bound返回指向该元素的迭代器,而upper\_bound返回指向下一个元素的迭代器。 2376 | ```cpp 2377 | iterator lower_bound (const key_type& k); 2378 | const_iterator lower_bound (const key_type& k) const; 2379 | ``` 2380 | Example 2381 | ```cpp 2382 | #include 2383 | #include 2384 | 2385 | int main () 2386 | { 2387 | std::map mymap; 2388 | std::map::iterator itlow,itup; 2389 | 2390 | mymap['a']=20; 2391 | mymap['b']=40; 2392 | mymap['c']=60; 2393 | mymap['d']=80; 2394 | mymap['e']=100; 2395 | 2396 | itlow=mymap.lower_bound ('b'); // itlow points to b 2397 | itup=mymap.upper_bound ('d'); // itup points to e (not d!) 2398 | 2399 | mymap.erase(itlow,itup); // erases [itlow,itup) 2400 | 2401 | // print content: 2402 | for (std::map::iterator it=mymap.begin(); it!=mymap.end(); ++it) 2403 | std::cout << it->first << " => " << it->second << '\n'; 2404 | 2405 | return 0; 2406 | } 2407 | ``` 2408 | Output 2409 | ``` 2410 | a => 20 2411 | e => 100 2412 | ``` 2413 | #### map::upper_bound 2414 | 2415 | 将迭代器返回到上限 2416 | 2417 | 返回一个指向容器中第一个元素的迭代器,它的关键字被认为是在k之后。 2418 | 2419 | 该函数使用其内部比较对象(key\_comp)来确定这一点,将迭代器返回到key\_comp(k,element\_key)将返回true的第一个元素。 2420 | 2421 | 如果map类用默认的比较类型(less)实例化,则函数返回一个迭代器到第一个元素,其键大于k。 2422 | 2423 | 类似的成员函数lower\_bound具有与upper\_bound相同的行为,除了map包含一个元素,其键值等于k:在这种情况下,lower\_bound返回指向该元素的迭代器,而upper\_bound返回指向下一个元素的迭代器。 2424 | 2425 | ```cpp 2426 | iterator upper_bound (const key_type& k); 2427 | const_iterator upper_bound (const key_type& k) const; 2428 | ``` 2429 | Example 2430 | ```cpp 2431 | #include 2432 | #include 2433 | 2434 | int main () 2435 | { 2436 | std::map mymap; 2437 | std::map::iterator itlow,itup; 2438 | 2439 | mymap['a']=20; 2440 | mymap['b']=40; 2441 | mymap['c']=60; 2442 | mymap['d']=80; 2443 | mymap['e']=100; 2444 | 2445 | itlow=mymap.lower_bound ('b'); // itlow points to b 2446 | itup=mymap.upper_bound ('d'); // itup points to e (not d!) 2447 | 2448 | mymap.erase(itlow,itup); // erases [itlow,itup) 2449 | 2450 | // print content: 2451 | for (std::map::iterator it=mymap.begin(); it!=mymap.end(); ++it) 2452 | std::cout << it->first << " => " << it->second << '\n'; 2453 | 2454 | return 0; 2455 | } 2456 | ``` 2457 | Output 2458 | ``` 2459 | a => 20 2460 | e => 100 2461 | ``` 2462 | 2463 | #### map::equal_range 2464 | 2465 | 获取相同元素的范围 2466 | 2467 | 返回包含容器中所有具有与k等价的键的元素的范围边界。 由于地图容器中的元素具有唯一键,所以返回的范围最多只包含一个元素。 2468 | 2469 | 如果没有找到匹配,则返回的范围具有零的长度,与两个迭代器指向具有考虑去后一个密钥对所述第一元件ķ根据容器的内部比较对象(key\_comp)。如果容器的比较对象返回false,则两个键被认为是等价的。 2470 | 2471 | 2472 | ```cpp 2473 | pair equal_range (const key_type& k) const; 2474 | pair equal_range (const key_type& k); 2475 | ``` 2476 | Example 2477 | ```cpp 2478 | #include 2479 | #include 2480 | 2481 | int main () 2482 | { 2483 | std::map mymap; 2484 | 2485 | mymap['a']=10; 2486 | mymap['b']=20; 2487 | mymap['c']=30; 2488 | 2489 | std::pair::iterator,std::map::iterator> ret; 2490 | ret = mymap.equal_range('b'); 2491 | 2492 | std::cout << "lower bound points to: "; 2493 | std::cout << ret.first->first << " => " << ret.first->second << '\n'; 2494 | 2495 | std::cout << "upper bound points to: "; 2496 | std::cout << ret.second->first << " => " << ret.second->second << '\n'; 2497 | 2498 | return 0; 2499 | } 2500 | ``` 2501 | Output 2502 | ``` 2503 | lower bound points to: 'b' => 20 2504 | upper bound points to: 'c' => 30 2505 | ``` 2506 | 2507 | ### multimap 2508 | 2509 | ### 无序容器(Unordered Container):unordered\_set、unordered\_multiset、unordered\_map、unordered\_multimap 2510 | 2511 | 包括: 2512 | 2513 | * unordered\_set 2514 | * unordered\_multiset 2515 | * unordered\_map 2516 | * unordered\_multimap 2517 | 2518 | 都是以哈希表实现的。 2519 | 2520 | ![](http://img.blog.csdn.net/20160410123436394) 2521 | 2522 | unordered\_set、unodered\_multiset结构: 2523 | 2524 | ![](http://img.blog.csdn.net/20160410123518692) 2525 | 2526 | unordered\_map、unodered\_multimap结构: 2527 | 2528 | ![](http://img.blog.csdn.net/20160410123525739) 2529 | 2530 | ### unordered_set 2531 | 2532 | ### unordered_multiset 2533 | 2534 | ### unordered_map 2535 | 2536 | ### unordered_multimap 2537 | 2538 | ### tuple 2539 | 2540 | 元组是一个能够容纳元素集合的对象。每个元素可以是不同的类型。 2541 | 2542 | ```cpp 2543 | template class tuple; 2544 | ``` 2545 | 2546 | Example 2547 | ```cpp 2548 | #include // std::cout 2549 | #include // std::tuple, std::get, std::tie, std::ignore 2550 | 2551 | int main () 2552 | { 2553 | std::tuple foo (10,'x'); 2554 | auto bar = std::make_tuple ("test", 3.1, 14, 'y'); 2555 | 2556 | std::get<2>(bar) = 100; // access element 2557 | 2558 | int myint; char mychar; 2559 | 2560 | std::tie (myint, mychar) = foo; // unpack elements 2561 | std::tie (std::ignore, std::ignore, myint, mychar) = bar; // unpack (with ignore) 2562 | 2563 | mychar = std::get<3>(bar); 2564 | 2565 | std::get<0>(foo) = std::get<2>(bar); 2566 | std::get<1>(foo) = mychar; 2567 | 2568 | std::cout << "foo contains: "; 2569 | std::cout << std::get<0>(foo) << ' '; 2570 | std::cout << std::get<1>(foo) << '\n'; 2571 | 2572 | return 0; 2573 | } 2574 | ``` 2575 | Output 2576 | ``` 2577 | foo contains: 100 y 2578 | ``` 2579 | #### tuple::tuple 2580 | 构建一个 tuple(元组)对象。 2581 | 2582 | 这涉及单独构建其元素,初始化取决于调用的构造函数形式: 2583 | 2584 | (1)默认的构造函数 2585 | 2586 | 构建一个 元组对象的元素值初始化。 2587 | 2588 | (2)复制/移动构造函数 2589 | 2590 | 该对象使用tpl的内容进行初始化 元组目的。tpl 2591 | 的相应元素被传递给每个元素的构造函数。 2592 | 2593 | (3)隐式转换构造函数 2594 | 2595 | 同上。tpl中的 2596 | 所有类型都可以隐含地转换为构造中它们各自元素的类型元组 目的。 2597 | 2598 | (4)初始化构造函数 2599 | 用elems中的相应元素初始化每个元素。elems 2600 | 的相应元素被传递给每个元素的构造函数。 2601 | 2602 | (5)对转换构造函数 2603 | 2604 | 该对象有两个对应于pr.first和的元素pr.second。PR中的所有类型都应该隐含地转换为其中各自元素的类型元组 目的。 2605 | 2606 | (6)分配器版本 2607 | 2608 | 和上面的版本一样,除了每个元素都是使用allocator alloc构造的。 2609 | 2610 | ```cpp 2611 | default (1) 2612 | constexpr tuple(); 2613 | copy / move (2) 2614 | tuple (const tuple& tpl) = default; 2615 | tuple (tuple&& tpl) = default; 2616 | implicit conversion (3) 2617 | template 2618 | tuple (const tuple& tpl); 2619 | template 2620 | tuple (tuple&& tpl); 2621 | initialization (4) 2622 | explicit tuple (const Types&... elems); 2623 | template 2624 | explicit tuple (UTypes&&... elems); 2625 | conversion from pair (5) 2626 | template 2627 | tuple (const pair& pr); 2628 | template 2629 | tuple (pair&& pr); 2630 | allocator (6) 2631 | template 2632 | tuple (allocator_arg_t aa, const Alloc& alloc); 2633 | template 2634 | tuple (allocator_arg_t aa, const Alloc& alloc, const tuple& tpl); 2635 | template 2636 | tuple (allocator_arg_t aa, const Alloc& alloc, tuple&& tpl); 2637 | template 2638 | tuple (allocator_arg_t aa, const Alloc& alloc, const tuple& tpl); 2639 | template 2640 | tuple (allocator_arg_t aa, const Alloc& alloc, tuple&& tpl); 2641 | template 2642 | tuple (allocator_arg_t aa, const Alloc& alloc, const Types&... elems); 2643 | template 2644 | tuple (allocator_arg_t aa, const Alloc& alloc, UTypes&&... elems); 2645 | template 2646 | tuple (allocator_arg_t aa, const Alloc& alloc, const pair& pr); 2647 | template 2648 | tuple (allocator_arg_t aa, const Alloc& alloc, pair&& pr); 2649 | ``` 2650 | Example 2651 | ```cpp 2652 | #include // std::cout 2653 | #include // std::make_pair 2654 | #include // std::tuple, std::make_tuple, std::get 2655 | 2656 | int main () 2657 | { 2658 | std::tuple first; // default 2659 | std::tuple second (first); // copy 2660 | std::tuple third (std::make_tuple(20,'b')); // move 2661 | std::tuple fourth (third); // implicit conversion 2662 | std::tuple fifth (10,'a'); // initialization 2663 | std::tuple sixth (std::make_pair(30,'c')); // from pair / move 2664 | 2665 | std::cout << "sixth contains: " << std::get<0>(sixth); 2666 | std::cout << " and " << std::get<1>(sixth) << '\n'; 2667 | 2668 | return 0; 2669 | } 2670 | ``` 2671 | Output 2672 | ``` 2673 | sixth contains: 30 and c 2674 | ``` 2675 | 2676 | ### pair 2677 | 这个类把一对值(values)结合在一起,这些值可能是不同的类型(T1 和 T2)。每个值可以被公有的成员变量first、second访问。 2678 | 2679 | pair是tuple(元组)的一个特例。 2680 | 2681 | pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。 2682 | 2683 | 应用: 2684 | 2685 | * 可以将两个类型数据组合成一个如map 2686 | * 当某个函数需要两个返回值时 2687 | 2688 | ```cpp 2689 | template struct pair; 2690 | ``` 2691 | #### pair::pair 2692 | 构建一个pair对象。 2693 | 2694 | 这涉及到单独构建它的两个组件对象,初始化依赖于调用的构造器形式: 2695 | 2696 | (1)默认的构造函数 2697 | 2698 | 构建一个 对对象的元素值初始化。 2699 | 2700 | (2)复制/移动构造函数(和隐式转换) 2701 | 2702 | 该对象被初始化为pr的内容 对目的。pr 2703 | 的相应成员被传递给每个成员的构造函数。 2704 | 2705 | (3)初始化构造函数 2706 | 2707 | 会员 第一是由一个和成员构建的第二与b。 2708 | 2709 | (4)分段构造 2710 | 2711 | 构造成员 first 和 second 到位,传递元素first\_args 作为参数的构造函数 first,和元素 second\_args 到的构造函数 second 。 2712 | 2713 | ```cpp 2714 | default (1) 2715 | constexpr pair(); 2716 | copy / move (2) 2717 | template pair (const pair& pr); 2718 | template pair (pair&& pr); 2719 | pair (const pair& pr) = default; 2720 | pair (pair&& pr) = default; 2721 | initialization (3) 2722 | pair (const first_type& a, const second_type& b); 2723 | template pair (U&& a, V&& b); 2724 | piecewise (4) 2725 | template 2726 | pair (piecewise_construct_t pwc, tuple first_args, 2727 | tuple second_args); 2728 | ``` 2729 | 2730 | Example 2731 | 2732 | ```cpp 2733 | #include // std::pair, std::make_pair 2734 | #include // std::string 2735 | #include // std::cout 2736 | 2737 | int main () { 2738 | std::pair product1; // default constructor 2739 | std::pair product2 ("tomatoes",2.30); // value init 2740 | std::pair product3 (product2); // copy constructor 2741 | 2742 | product1 = std::make_pair(std::string("lightbulbs"),0.99); // using make_pair (move) 2743 | 2744 | product2.first = "shoes"; // the type of first is string 2745 | product2.second = 39.90; // the type of second is double 2746 | 2747 | std::cout << "The price of " << product1.first << " is $" << product1.second << '\n'; 2748 | std::cout << "The price of " << product2.first << " is $" << product2.second << '\n'; 2749 | std::cout << "The price of " << product3.first << " is $" << product3.second << '\n'; 2750 | return 0; 2751 | } 2752 | ``` 2753 | Output 2754 | ``` 2755 | The price of lightbulbs is $0.99 2756 | The price of shoes is $39.9 2757 | The price of tomatoes is $2.3 2758 | ``` 2759 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | interview.huihut.com -------------------------------------------------------------------------------- /docs/_navbar.md: -------------------------------------------------------------------------------- 1 | * [简体中文](/) 2 | * [English](/en) -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | interview 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /images/CPU-Big-Endian.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/CPU-Big-Endian.svg.png -------------------------------------------------------------------------------- /images/CPU-Little-Endian.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/CPU-Little-Endian.svg.png -------------------------------------------------------------------------------- /images/CirLinkList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/CirLinkList.png -------------------------------------------------------------------------------- /images/DuLinkList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/DuLinkList.png -------------------------------------------------------------------------------- /images/GeneralizedList1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/GeneralizedList1.png -------------------------------------------------------------------------------- /images/GeneralizedList2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/GeneralizedList2.png -------------------------------------------------------------------------------- /images/GoogleCppStyleGuide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/GoogleCppStyleGuide.png -------------------------------------------------------------------------------- /images/HashTable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/HashTable.png -------------------------------------------------------------------------------- /images/ICMP报文格式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/ICMP报文格式.png -------------------------------------------------------------------------------- /images/IP数据报格式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/IP数据报格式.png -------------------------------------------------------------------------------- /images/ISOOSI七层网络模型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/ISOOSI七层网络模型.png -------------------------------------------------------------------------------- /images/LinkBinaryTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/LinkBinaryTree.png -------------------------------------------------------------------------------- /images/LinkList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/LinkList.png -------------------------------------------------------------------------------- /images/LinkQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/LinkQueue.png -------------------------------------------------------------------------------- /images/Self-balancingBinarySearchTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/Self-balancingBinarySearchTree.png -------------------------------------------------------------------------------- /images/SqBinaryTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/SqBinaryTree.png -------------------------------------------------------------------------------- /images/SqList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/SqList.png -------------------------------------------------------------------------------- /images/SqLoopStack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/SqLoopStack.png -------------------------------------------------------------------------------- /images/SqQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/SqQueue.png -------------------------------------------------------------------------------- /images/SqStack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/SqStack.png -------------------------------------------------------------------------------- /images/TCP-transport-connection-management.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP-transport-connection-management.png -------------------------------------------------------------------------------- /images/TCPIP协议四层模型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCPIP协议四层模型.png -------------------------------------------------------------------------------- /images/TCP三次握手建立连接.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP三次握手建立连接.png -------------------------------------------------------------------------------- /images/TCP四次挥手释放连接.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP四次挥手释放连接.png -------------------------------------------------------------------------------- /images/TCP报文.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP报文.png -------------------------------------------------------------------------------- /images/TCP拥塞窗口cwnd在拥塞控制时的变化情况.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP拥塞窗口cwnd在拥塞控制时的变化情况.png -------------------------------------------------------------------------------- /images/TCP的拥塞控制流程图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP的拥塞控制流程图.png -------------------------------------------------------------------------------- /images/TCP的有限状态机.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP的有限状态机.png -------------------------------------------------------------------------------- /images/TCP首部.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TCP首部.png -------------------------------------------------------------------------------- /images/TOC预览.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/TOC预览.png -------------------------------------------------------------------------------- /images/UDP报文.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/UDP报文.png -------------------------------------------------------------------------------- /images/UDP首部.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/UDP首部.png -------------------------------------------------------------------------------- /images/WindowsFreeLibrary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/WindowsFreeLibrary.png -------------------------------------------------------------------------------- /images/WindowsLoadLibrary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/WindowsLoadLibrary.png -------------------------------------------------------------------------------- /images/socket客户端服务器通讯.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/socket客户端服务器通讯.jpg -------------------------------------------------------------------------------- /images/利用可变窗口进行流量控制举例.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/利用可变窗口进行流量控制举例.png -------------------------------------------------------------------------------- /images/快重传示意图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/快重传示意图.png -------------------------------------------------------------------------------- /images/打印预览.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/打印预览.png -------------------------------------------------------------------------------- /images/计算机网络体系结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/计算机网络体系结构.png -------------------------------------------------------------------------------- /images/面向对象基本特征.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huihut/interview/77b04416e2c7b60750ca3740c2c12e1ee6374500/images/面向对象基本特征.png --------------------------------------------------------------------------------