├── .vscode ├── c_cpp_properties.json └── settings.json ├── README.md ├── binary-search-tree ├── 01-binary-search │ └── main.cpp ├── 02-binary-search-tree │ ├── FileOps.h │ ├── SequenceSearchTree.h │ ├── bible.txt │ ├── main │ └── main.cpp ├── 03-binary-search-tree-traverse │ ├── main │ └── main.cpp ├── 04-binary-search-tree-breadth-first │ ├── main │ └── main.cpp ├── 05-binary-search-tree-delete-min-max │ └── main.cpp └── 06-binary-search-tree-delete-node-hubbard-deletion │ └── main.cpp ├── graph-theory ├── 01-graph-representation │ ├── DenseGraph.h │ ├── SparseGraph.h │ └── main.cpp ├── 02-iterator-near-node │ ├── DenseGraph.h │ ├── SparseGraph.h │ └── main.cpp ├── 03-basic-structure-on-graph-problem │ ├── DenseGraph.h │ ├── ReadGraph.h │ ├── SparseGraph.h │ ├── main.cpp │ ├── testG1.txt │ └── testG2.txt ├── 04-DFS-in-graph │ ├── Components.h │ ├── DenseGraph.h │ ├── ReadGraph.h │ ├── SparseGraph.h │ ├── main.cpp │ ├── testG1.txt │ └── testG2.txt ├── 05-path-find │ ├── Components.h │ ├── DenseGraph.h │ ├── Path.h │ ├── ReadGraph.h │ ├── SparseGraph.h │ ├── main.cpp │ └── testG.txt └── 06-BFS-in-graph │ ├── Components.h │ ├── DenseGraph.h │ ├── Path.h │ ├── ReadGraph.h │ ├── ShortestPath.h │ ├── SparseGraph.h │ ├── main.cpp │ └── testG.txt ├── heap-sort ├── 01-MaxHeap │ └── main.cpp ├── 02-MaxHeap-Shift-Up │ └── main.cpp ├── 03-MaxHeap-Shift-Down │ └── main.cpp ├── 04-Heapify │ ├── Heap.h │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── QuickSort.h │ ├── QuickSort2Ways.h │ ├── QuickSort3Ways.h │ ├── SortTestHelper.h │ └── main.cpp ├── 05-Heap-Sort │ ├── Heap.h │ ├── HeapSort.h │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── QuickSort.h │ ├── QuickSort2Ways.h │ ├── QuickSort3Ways.h │ ├── SortTestHelper.h │ └── main.cpp ├── 06-Index-Heap │ ├── SortTtestHelper.h │ └── main.cpp ├── 07-index-Heap-Advanced │ ├── SortTestHelper.h │ └── main.cpp ├── 08-HeapSort-All │ └── main.cpp ├── extra-Heap-Sort-TopK │ └── main.cpp └── extra-heap-sort-python │ ├── MaxHeap.py │ ├── __init__.py │ └── main.py ├── minimum-span-trees └── 01-weighted-graph │ ├── DenseGraph.h │ ├── Edge.h │ ├── ReadGraph.h │ ├── SparseGraph.h │ ├── main.cpp │ └── testG1.txt ├── sort-advanced ├── 01-merge-sort │ ├── InsertionSort.h │ ├── SortTestHelper.h │ └── main.cpp ├── 02-merge-sort-advanced │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── SortTestHelper.h │ ├── main │ └── main.cpp ├── 03-merge-sort-button-up │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── SortTestHelper.h │ └── main.cpp ├── 04-quick-sort │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── SortTestHelper.h │ ├── main │ └── main.cpp ├── 05-quick-sort-advanced │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── SortTestHelper.h │ └── main.cpp ├── 06-quick-sort-two-way │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── SortTestHelper.h │ ├── main │ └── main.cpp └── 07-quick-sort-three-ways │ ├── InsertionSort.h │ ├── MergeSort.h │ ├── QuickSort.h │ ├── SortTestHelper.h │ ├── main │ └── main.cpp ├── sort-basic ├── 01-selection-sort │ ├── CMakeLists.txt │ └── main.cpp ├── 02-selection-sort-template │ ├── CMakeLists.txt │ ├── Student.h │ └── main.cpp ├── 03-selection-sort-generate-test │ ├── CMakeLists.txt │ ├── SortTestHelper.h │ └── main.cpp ├── 04-selection-sort-detect-performance │ ├── CMakeLists.txt │ ├── SortTestHelper.h │ ├── main │ └── main.cpp ├── 05-insertion-sort │ ├── SelectionSort.h │ ├── SortTestHelper.h │ └── main.cpp ├── 06-insertion-sort-advanced │ ├── SelectionSort.h │ ├── SortTestHelper.h │ ├── main │ └── main.cpp ├── 07-bubble-sort │ ├── InsertionSort.h │ ├── SelectionSort.h │ ├── SortTestHelper.h │ └── main.cpp └── 08-Shell-Sort │ ├── BubbleSort.h │ ├── InsertionSort.h │ ├── SelectionSort.h │ ├── SortTestHelper.h │ └── main.cpp ├── static ├── complete-bin-tree.png ├── index-max-heap.png ├── index-maxheap-reverse.png ├── insertion-sort-advanced.png ├── insertion-sort.png ├── merge-sort-detail.png ├── merge-sort.png ├── quick-sort-3-way-finish.png ├── quick-sort-3-way.png ├── quick-sort-partition-1.png ├── quick-sort-partition-2.png ├── quick-sort-partition.png ├── quick-sort-problem.png ├── quick-sort-two-way.png ├── quick-sort.png ├── reverse-detail.png ├── selection-sort.png └── sort-solution.png └── union-find ├── 01-quick-find-union └── main.cpp ├── 02-quick-union └── main.cpp ├── 03-quick-union-optimized-based-size └── main.cpp ├── 04-quick-union-optimized-based-on-rank └── main.cpp ├── 05-quick-union-path-compression └── main.cpp └── extra-union-find-python-version ├── __init__.py └── union_find.py /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [], 9 | "macFrameworkPath": [ 10 | "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks" 11 | ], 12 | "compilerPath": "/usr/bin/clang", 13 | "cStandard": "c11", 14 | "cppStandard": "c++17", 15 | "intelliSenseMode": "clang-x64" 16 | } 17 | ], 18 | "version": 4 19 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": true, 3 | "python.pythonPath": "/Users/3zz/anaconda3/bin/python", 4 | "files.associations": { 5 | "vector": "cpp", 6 | "ostream": "cpp" 7 | } 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 一起来学习数据结构与算法吧 2 | 3 | ## 一些常用经典算法和数据结构的回顾 4 | 5 | ### 首先是最经典的排序问题 6 | 7 | - 排序 8 | 9 | - 选择排序(Selection Sort)复杂度 O(n^2) 10 | 11 | > 找到最小的元素然后与当前位置交换 12 | > ![选择排序](./static/selection-sort.png) 13 | 14 | - 插入排序(Insertion Sort)复杂度 O(n^2) 15 | 16 | > 找到合适的位置然后插入 17 | > ![插入排序](./static/insertion-sort.png) 18 | 19 | - 改进的插入排序(取消了交换操作) 20 | 21 | > 将当前位置的元素先拿出 然后逐个与之前的元素比较 如果小于 就将之前的元素后移 在与前一位比较 22 | > ![插入排序改进](./static/insertion-sort-advanced.png) 23 | 24 | - 冒泡排序(Bubble Sort) 25 | 26 | - 希尔排序(Shell Sort) 27 | 28 | - 归并排序(Merge Sort)复杂度 O(n\*logn) 29 | 30 | > 先不断的二分 31 | > ![归并排序](./static/merge-sort.png) 32 | > 归并过程 33 | > ![归并排序](./static/merge-sort-detail.png) 34 | 35 | - 归并排序自底向上版(Merge Sort Buttom Up) 36 | 37 | > 不先对数组进行二分 直接以 1、2、4 这样大小循环合并直至数组全部合并完成 38 | 39 | - 快速排序(Quick Sort) 40 | 41 | > 先选中一个元素 然后找到它应该所在的位置 然后继续递归 42 | > ![快速排序](./static/quick-sort.png) 43 | 44 | - 第一部分 partition 45 | > 先选中一个元素 然后找到它应该所在的位置 然后继续递归 46 | > ![partition](./static/quick-sort-partition.png) 47 | > 如果此时 e > v,那么 e 直接加入到紫色的数组中 48 | > 如果此时 e < v, 那么直接将 e 与 j 所指向的位置交换即可 之后 j++ 49 | > ![partition-1](./static/quick-sort-partition-1.png) 50 | > 最后所有元素分类完毕之后 将 l 与 j 所在位置的元素交换一下即可 51 | > ![partition-2](./static/quick-sort-partition-2.png) 52 | 53 | - 快速排序存在的两点问题 54 | 55 | 1. 对于近乎有序的数组,快速排序会退化到复杂度 O(n^2),此时解决办法就是随机选取一个初始值 然后与第一个需要定位的元素 l 交换 这样操作 快速排序的期望复杂度 EO(Nlogn) 56 | 2. 对于一个  数量庞大但是所有元素都在一个很小区间的数组,快速  排序依旧会退化到复杂度 O(n^2),因为会导致大量的不平衡数组出现 57 | > ![快速排序存在问题](./static/quick-sort-problem.png) 58 | 59 | - 此时 使用双路快排(hard):scream: 60 | 61 | > 主要在 partition 过程中进行了更加细化的操作 62 | > ![双路快排](./static/quick-sort-two-way.png) 63 | 64 | - 三路快排 65 | - 这是初始排序的情况 66 | > ![初始情况](./static/quick-sort-3-way.png) 67 | - 此时是排序完毕的情况 68 | > ![三路排序完成](./static/quick-sort-3-way-finish.png) 69 | 70 | - 堆(优先队列) 71 | - 二叉堆 72 | > 堆 是一个完全二叉树 73 | > ![完全二叉树](./static/complete-bin-tree.png) 74 | 75 | - 排序算法总结 76 | > ![排序算法总结](./static/sort-solution.png) 77 | 78 | - 最大索引堆 79 | - 基础 添加index用来记录当前索引堆每个元素所在的位置 80 | > ![最大索引堆基础](./static/index-max-heap.png) 81 | - 优化 添加reverse行用来存储索引对应index中的数 82 | > ![最大索引堆优化](./static/index-maxheap-reverse.png) 83 | - reverse数组more detail 84 | > ![reverse](./static/reverse-detail.png) 85 | - 二项堆 86 | - 斐波那契堆 87 | -------------------------------------------------------------------------------- /binary-search-tree/01-binary-search/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template 6 | 7 | int binarySearch(T arr[], int n, T target) 8 | { 9 | // 在arr[l...r]之间查找target 10 | int l = 0, r = n - 1; 11 | while (l <= r) 12 | { 13 | int mid = (r - l) / 2 + l; 14 | if (arr[mid] == target) 15 | return mid; 16 | if (target < arr[mid]) 17 | // 在arr[l...mid-1]之间查找target 18 | r = mid - 1; 19 | else // target > arr[mid] 20 | // 在arr[mid+1...r]之中查找target 21 | l = mid + 1; 22 | } 23 | return -1; 24 | } -------------------------------------------------------------------------------- /binary-search-tree/02-binary-search-tree/FileOps.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_04_BINARY_SEARCH_TREE_SEARCH_FILEOPS_H 6 | #define INC_04_BINARY_SEARCH_TREE_SEARCH_FILEOPS_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | // 文件相关操作 16 | namespace FileOps{ 17 | 18 | // 读取文件名称为filename中的内容,并将其中包含的所有词语放进words中 19 | int firstCharacterIndex(const string& s, int start){ 20 | for( int i = start ; i < s.length() ; i ++ ) 21 | if( isalpha(s[i]) ) 22 | return i; 23 | return s.length(); 24 | } 25 | 26 | // 将字符串s中的所有字母转换成小写之后返回 27 | string lowerS( const string& s){ 28 | 29 | string ret = ""; 30 | for( int i = 0 ; i < s.length() ; i ++ ) 31 | ret += tolower(s[i]); 32 | return ret; 33 | } 34 | 35 | // 读取文件名称为filename中的内容,并将其中包含的所有词语放进words中 36 | bool readFile(const string& filename, vector &words){ 37 | 38 | // 文件读取 39 | string line; 40 | string contents = ""; 41 | ifstream file(filename); 42 | if( file.is_open() ){ 43 | while( getline(file, line)) 44 | contents += ( line + "\n" ); 45 | file.close(); 46 | } 47 | else{ 48 | cout<<"Can not open "< 6 | #include 7 | 8 | using namespace std; 9 | 10 | // 顺序查找表 11 | template 12 | class SequenceST 13 | { 14 | 15 | private: 16 | struct Node 17 | { 18 | Key key; 19 | Value value; 20 | Node *next; 21 | 22 | Node(Key key, Value value) 23 | { 24 | this->key = key; 25 | this->value = value; 26 | this->next = NULL; 27 | } 28 | }; 29 | Node *head; 30 | int count; 31 | 32 | public: 33 | // 构造函数 34 | SequenceST() 35 | { 36 | head = NULL; 37 | count = 0; 38 | } 39 | ~SequenceST() 40 | { 41 | while (head != NULL) 42 | { 43 | Node *node = head; 44 | head = head->next; 45 | delete node; 46 | count--; 47 | } 48 | assert(head == NULL && count == 0); 49 | } 50 | 51 | // 返回顺序查找表中的节点个数 52 | int size() 53 | { 54 | return count; 55 | } 56 | 57 | // 返回顺序查找表是否为空 58 | bool isEmpty() 59 | { 60 | return count == 0; 61 | } 62 | 63 | // 向顺序查找表中插入一个新的(key, value)数据对 64 | void insert(Key key, Value value) 65 | { 66 | // 查找一下整个顺序表,看看是否存在相同大小的key 67 | Node *node = head; 68 | while (node != NULL) 69 | { 70 | // 如果在顺序表中查找到了相同大小key的节点 71 | // 那么当前节点则不需要插入,将该key所对应的值更新为新value之后返回 72 | if (key == node->key) 73 | { 74 | node->value = value; 75 | return; 76 | } 77 | node = node->next; 78 | } 79 | // 如果顺序链表中没有相同大小的key, 则创建新节点,将新节点直接插在表头 80 | Node *newNode = new Node(key, value); 81 | newNode->next = head; 82 | head = newNode; 83 | count++; 84 | } 85 | 86 | // 查看顺序查找表中是否包含键值对为key的节点 87 | bool contain(Key key) 88 | { 89 | Node *node = head; 90 | while (node != NULL) 91 | { 92 | if (key == node->key) 93 | return true; 94 | node = node->next; 95 | } 96 | return false; 97 | } 98 | 99 | // 在顺序查找表中查找key所对应的value,若value不存在,则返回NULL 100 | Value *search(Key key) 101 | { 102 | Node *node = head; 103 | while (head != NULL) 104 | { 105 | if (key == node->key) 106 | return &(node->value); 107 | node = node->next; 108 | } 109 | return NULL; 110 | } 111 | 112 | // 在顺序查找表中删除(key, value)所对应的节点 113 | void remove(Key key) 114 | { 115 | if (head == NULL) 116 | return; 117 | 118 | // 如果待删除的节点就是头结点,需要特殊处理 119 | if (key == head->key) 120 | { 121 | Node *delNode = head; 122 | head = head->next; 123 | delete delNode; 124 | count--; 125 | return; 126 | } 127 | 128 | Node *node = head; 129 | while (node->next != NULL && node->next->key != key) 130 | node = node->next; 131 | 132 | if (node->next != NULL) 133 | { 134 | Node *delNode = node->next; 135 | node->next = delNode->next; 136 | delete delNode; 137 | count--; 138 | return; 139 | } 140 | } 141 | }; -------------------------------------------------------------------------------- /binary-search-tree/02-binary-search-tree/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/binary-search-tree/02-binary-search-tree/main -------------------------------------------------------------------------------- /binary-search-tree/02-binary-search-tree/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "SequenceSearchTree.h" 5 | #include "FileOps.h" 6 | 7 | using namespace std; 8 | 9 | template 10 | class BST 11 | { 12 | 13 | private: 14 | struct Node 15 | { 16 | Key key; 17 | Value value; 18 | Node *left; 19 | Node *right; 20 | 21 | Node(Key key, Value value) 22 | { 23 | this->key = key; 24 | this->value = value; 25 | this->left = this->right = NULL; 26 | } 27 | }; 28 | Node *root; 29 | int count; 30 | 31 | public: 32 | BST() 33 | { 34 | root = NULL; 35 | count = 0; 36 | } 37 | ~BST() 38 | { 39 | // TODO: ~BST() 40 | } 41 | int size() 42 | { 43 | return count; 44 | } 45 | bool isEmpty() 46 | { 47 | return count == 0; 48 | } 49 | // 插入一个节点 50 | void insert(Key key, Value value) 51 | { 52 | root = insert(root, key, value); 53 | } 54 | /** insert非递归实现 TODO 55 | * 需要使用一个帮助函数 search 56 | * void insert(Key key, Value value){ 57 | * Node *rt = root; 58 | * bool flag = true; 59 | * while(flag){ 60 | * if(rt->value == value) 61 | } 62 | */ 63 | // 是否包含含有这个值的子节点 64 | bool contain(Key key) 65 | { 66 | return contain(root, key); 67 | } 68 | Value *search(Key key) 69 | { 70 | return search(root, key); 71 | } 72 | 73 | private: 74 | // 向以node为跟的二叉搜索树 75 | // 返回插入新节点之后二叉搜索树的根 76 | Node *insert(Node *node, Key key, Value value) 77 | { 78 | if (node == NULL) 79 | { 80 | count++; 81 | return new Node(key, value); 82 | } 83 | if (key == node->key) 84 | node->value = value; 85 | else if (key < node->key) 86 | node->left = insert(node->left, key, value); 87 | else // key > node->key 88 | node->right = insert(node->right, key, value); 89 | return node; 90 | } 91 | bool contain(Node *node, Key key) 92 | { 93 | // 递归到底的情况 94 | if (node == NULL) 95 | return false; 96 | if (key == node->key) 97 | return true; 98 | else if (key < node->key) 99 | return contain(node->left, key); 100 | else // key > node->key 101 | return contain(node->right, key); 102 | } 103 | 104 | // 在以node为根的二叉搜索树中寻找key所对应的value 105 | Value *search(Node *node, Key key) 106 | { 107 | if (node == NULL) 108 | return NULL; 109 | if (key == node->key) 110 | return &(node->value); 111 | else if (key < node->key) 112 | return search(node->left, key); 113 | else // key>node->key 114 | return search(node->right, key); 115 | } 116 | }; 117 | 118 | // 测试二分搜索树和顺序查找表之间的性能差距 119 | // 二分搜索树的性能远远优于顺序查找表 120 | int main() 121 | { 122 | 123 | // 使用圣经作为我们的测试用例 124 | string filename = "bible.txt"; 125 | vector words; 126 | if (FileOps::readFile(filename, words)) 127 | { 128 | 129 | cout << "There are totally " << words.size() << " words in " << filename << endl; 130 | cout << endl; 131 | 132 | // 测试 BST 133 | time_t startTime = clock(); 134 | 135 | // 统计圣经中所有词的词频 136 | // 注: 这个词频统计法相对简陋, 没有考虑很多文本处理中的特殊问题 137 | // 在这里只做性能测试用 138 | BST bst = BST(); 139 | for (vector::iterator iter = words.begin(); iter != words.end(); iter++) 140 | { 141 | int *res = bst.search(*iter); 142 | if (res == NULL) 143 | bst.insert(*iter, 1); 144 | else 145 | (*res)++; 146 | } 147 | 148 | // 输出圣经中god一词出现的频率 149 | if (bst.contain("god")) 150 | cout << "'god' : " << *bst.search("god") << endl; 151 | else 152 | cout << "No word 'god' in " << filename << endl; 153 | 154 | time_t endTime = clock(); 155 | 156 | cout << "BST , time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 157 | cout << endl; 158 | 159 | // 测试顺序查找表 SST 160 | startTime = clock(); 161 | 162 | // 统计圣经中所有词的词频 163 | // 注: 这个词频统计法相对简陋, 没有考虑很多文本处理中的特殊问题 164 | // 在这里只做性能测试用 165 | SequenceST sst = SequenceST(); 166 | for (vector::iterator iter = words.begin(); iter != words.end(); iter++) 167 | { 168 | int *res = sst.search(*iter); 169 | if (res == NULL) 170 | sst.insert(*iter, 1); 171 | else 172 | (*res)++; 173 | } 174 | 175 | // 输出圣经中god一词出现的频率 176 | if (sst.contain("god")) 177 | cout << "'god' : " << *sst.search("god") << endl; 178 | else 179 | cout << "No word 'god' in " << filename << endl; 180 | 181 | endTime = clock(); 182 | 183 | cout << "SST , time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 184 | } 185 | 186 | return 0; 187 | } -------------------------------------------------------------------------------- /binary-search-tree/03-binary-search-tree-traverse/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/binary-search-tree/03-binary-search-tree-traverse/main -------------------------------------------------------------------------------- /binary-search-tree/04-binary-search-tree-breadth-first/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/binary-search-tree/04-binary-search-tree-breadth-first/main -------------------------------------------------------------------------------- /graph-theory/01-graph-representation/DenseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class DenseGraph{ 8 | private: 9 | int n, m; // 节点数和边数 10 | bool directed; // 是否为有向图 11 | vector > g; // 图的具体数据 12 | 13 | public: 14 | // 构造函数 15 | DenseGraph(int n, bool directed){ 16 | assert(n >= 0); 17 | this->n = n; 18 | this->m = 0; 19 | this->directed = directed; 20 | for(int i = 0; i < n; i++) 21 | { 22 | g.push_back(vector(n, false)); 23 | } 24 | } 25 | ~DenseGraph(){} 26 | 27 | int V(){return n;} 28 | int E(){return m;} 29 | 30 | void addEdge(int v, int w){ 31 | assert(v >= 0 && v < n); 32 | assert(w >= 0 && w < n); 33 | if(hasEdge(v,w)){ 34 | return; 35 | } 36 | g[v][w] = true; 37 | if(!directed){ 38 | g[w][v] = true; 39 | } 40 | m++; 41 | } 42 | 43 | bool hasEdge(int v, int w){ 44 | assert(v >= 0 && v = 0 && w < n); 46 | return g[v][w]; 47 | } 48 | }; -------------------------------------------------------------------------------- /graph-theory/01-graph-representation/SparseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class SparseGraph 8 | { 9 | private: 10 | int n, m; // 节点数和边数 11 | bool directed; // 是否为有向图 12 | vector > g; // 图的具体连接情况 13 | 14 | public: 15 | // 构造函数 16 | SparseGraph(int n, int directed){ 17 | this->n = n; 18 | this->m = 0; 19 | this->directed = directed; 20 | for(int i = 0;i()); 22 | } 23 | } 24 | ~SparseGraph(){} 25 | 26 | int V(){return n;} 27 | int W(){return m;} 28 | 29 | void addEdge(int v, int w){ 30 | assert(v >= 0 && v < n); 31 | assert(w >= 0 && w < n); 32 | g[v].push_back(w); 33 | // 考虑自环边 34 | if( v != w && !directed){ 35 | g[w].push_back(v); 36 | } 37 | m++; 38 | } 39 | // 需要遍历 O(n) 40 | bool hasEdge(int v, int w){ 41 | assert(v >= 0 && v < n); 42 | assert(w >= 0 && w < n); 43 | for(int i = 0;i 2 | #include 3 | 4 | using namespace std; 5 | 6 | -------------------------------------------------------------------------------- /graph-theory/02-iterator-near-node/DenseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class DenseGraph{ 8 | private: 9 | int n, m; // 节点数和边数 10 | bool directed; // 是否为有向图 11 | vector > g; // 图的具体数据 12 | 13 | public: 14 | // 构造函数 15 | DenseGraph(int n, bool directed){ 16 | assert(n >= 0); 17 | this->n = n; 18 | this->m = 0; 19 | this->directed = directed; 20 | for(int i = 0; i < n; i++) 21 | { 22 | g.push_back(vector(n, false)); 23 | } 24 | } 25 | ~DenseGraph(){} 26 | 27 | int V(){return n;} 28 | int E(){return m;} 29 | 30 | void addEdge(int v, int w){ 31 | assert(v >= 0 && v < n); 32 | assert(w >= 0 && w < n); 33 | if(hasEdge(v,w)){ 34 | return; 35 | } 36 | g[v][w] = true; 37 | if(!directed){ 38 | g[w][v] = true; 39 | } 40 | m++; 41 | } 42 | 43 | bool hasEdge(int v, int w){ 44 | assert(v >= 0 && v = 0 && w < n); 46 | return g[v][w]; 47 | } 48 | 49 | class adjIterator{ 50 | private: 51 | DenseGraph &G; 52 | int v; 53 | int index; 54 | public: 55 | adjIterator(DenseGraph &graph, int v): G(graph){ 56 | assert( v>=0 && v< G.n); 57 | this->v = v; 58 | this->index = -1; 59 | } 60 | ~adjIterator(){} 61 | // 返回图G中与顶点v相连接的第一个顶点 62 | int begin(){ 63 | // 索引从-1开始, 因为每次遍历都需要调用一次next() 64 | index = -1; 65 | return next(); 66 | } 67 | int next(){ 68 | for(index +=1;index < G.V();index++) 69 | if(G.g[v][index]) 70 | return index; 71 | return -1; 72 | } 73 | bool end(){ 74 | return index >= G.V(); 75 | } 76 | }; 77 | }; -------------------------------------------------------------------------------- /graph-theory/02-iterator-near-node/SparseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class SparseGraph 8 | { 9 | private: 10 | int n, m; // 节点数和边数 11 | bool directed; // 是否为有向图 12 | vector > g; // 图的具体连接情况 13 | 14 | public: 15 | // 构造函数 16 | SparseGraph(int n, int directed) 17 | { 18 | this->n = n; 19 | this->m = 0; 20 | this->directed = directed; 21 | for (int i = 0; i < n; i++) 22 | { 23 | g.push_back(vector()); 24 | } 25 | } 26 | ~SparseGraph() {} 27 | 28 | int V() { return n; } 29 | int W() { return m; } 30 | 31 | void addEdge(int v, int w) 32 | { 33 | assert(v >= 0 && v < n); 34 | assert(w >= 0 && w < n); 35 | g[v].push_back(w); 36 | // 考虑自环边 37 | if (v != w && !directed) 38 | { 39 | g[w].push_back(v); 40 | } 41 | m++; 42 | } 43 | // 需要遍历 O(n) 44 | bool hasEdge(int v, int w) 45 | { 46 | assert(v >= 0 && v < n); 47 | assert(w >= 0 && w < n); 48 | for (int i = 0; i < g[v].size(); i++) 49 | if (g[v][i] == w) 50 | return true; 51 | return false; 52 | } 53 | 54 | class adjIterator 55 | { 56 | private: 57 | SparseGraph &G; 58 | int v; 59 | int index; 60 | 61 | public: 62 | adjIterator(SparseGraph &graph, int v) : G(graph) 63 | { 64 | this->v = v; 65 | this->index = 0; 66 | } 67 | int begin() 68 | { 69 | index = 0; 70 | if (G.g[v].size()) 71 | { 72 | return G.g[v][index]; 73 | } 74 | return -1; 75 | } 76 | int next() 77 | { 78 | index++; 79 | if (index < G.g[v].size()) 80 | { 81 | return G.g[v][index]; 82 | } 83 | return -1; 84 | } 85 | bool end() 86 | { 87 | return index >= G.g[v].size(); 88 | } 89 | }; 90 | }; -------------------------------------------------------------------------------- /graph-theory/02-iterator-near-node/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SparseGraph.h" 3 | #include "DenseGraph.h" 4 | 5 | using namespace std; 6 | 7 | int main() 8 | { 9 | int N = 20; 10 | int M = 100; 11 | 12 | srand(time(NULL)); 13 | 14 | // Sparse Graph 15 | SparseGraph g1(N, false); 16 | for (int i = 0; i < M; i++) 17 | { 18 | int a = rand() % N; 19 | int b = rand() % N; 20 | g1.addEdge(a, b); 21 | } 22 | // 输出邻接点 23 | // O(E) 24 | for (int v = 0; v < N; v++) 25 | { 26 | cout << v << " : "; 27 | SparseGraph::adjIterator adj(g1, v); 28 | for (int w = adj.begin(); !adj.end(); w = adj.next()) 29 | { 30 | cout << w << " "; 31 | } 32 | cout << endl; 33 | } 34 | cout << endl; 35 | 36 | // Dense Graph 37 | DenseGraph g2(N, false); 38 | for (int i = 0; i < M; i++) 39 | { 40 | int a = rand() % N; 41 | int b = rand() % N; 42 | g2.addEdge(a, b); 43 | } 44 | // 输出邻接点 45 | // O(v^2) 46 | for (int v = 0; v < N; v++) 47 | { 48 | cout << v << " : "; 49 | DenseGraph::adjIterator adj(g2, v); 50 | for (int w = adj.begin(); !adj.end(); w = adj.next()) 51 | { 52 | cout << w << " "; 53 | } 54 | cout << endl; 55 | } 56 | cout << endl; 57 | return 0; 58 | } -------------------------------------------------------------------------------- /graph-theory/03-basic-structure-on-graph-problem/DenseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class DenseGraph{ 8 | private: 9 | int n, m; // 节点数和边数 10 | bool directed; // 是否为有向图 11 | vector > g; // 图的具体数据 12 | 13 | public: 14 | // 构造函数 15 | DenseGraph(int n, bool directed){ 16 | assert(n >= 0); 17 | this->n = n; 18 | this->m = 0; 19 | this->directed = directed; 20 | for(int i = 0; i < n; i++) 21 | { 22 | g.push_back(vector(n, false)); 23 | } 24 | } 25 | ~DenseGraph(){} 26 | 27 | int V(){return n;} 28 | int E(){return m;} 29 | 30 | void addEdge(int v, int w){ 31 | assert(v >= 0 && v < n); 32 | assert(w >= 0 && w < n); 33 | if(hasEdge(v,w)){ 34 | return; 35 | } 36 | g[v][w] = true; 37 | if(!directed){ 38 | g[w][v] = true; 39 | } 40 | m++; 41 | } 42 | 43 | bool hasEdge(int v, int w){ 44 | assert(v >= 0 && v = 0 && w < n); 46 | return g[v][w]; 47 | } 48 | // 打印邻接矩阵 49 | void show(){ 50 | for(int i = 0; i< n;i++){ 51 | for(int j = 0;j=0 && v< G.n); 66 | this->v = v; 67 | this->index = -1; 68 | } 69 | ~adjIterator(){} 70 | // 返回图G中与顶点v相连接的第一个顶点 71 | int begin(){ 72 | // 索引从-1开始, 因为每次遍历都需要调用一次next() 73 | index = -1; 74 | return next(); 75 | } 76 | int next(){ 77 | for(index +=1;index < G.V();index++) 78 | if(G.g[v][index]) 79 | return index; 80 | return -1; 81 | } 82 | bool end(){ 83 | return index >= G.V(); 84 | } 85 | }; 86 | }; -------------------------------------------------------------------------------- /graph-theory/03-basic-structure-on-graph-problem/ReadGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | template 10 | 11 | class ReadGraph{ 12 | 13 | public: 14 | ReadGraph(Graph &graph, const string &filename){ 15 | ifstream file(filename); 16 | string line; 17 | int V,E; 18 | 19 | assert( file.is_open()); 20 | assert(getline(file, line)); 21 | 22 | stringstream ss(line); 23 | ss>>V>>E; 24 | 25 | assert(V == graph.V()); 26 | for(int i = 0; i < E; i++) 27 | { 28 | assert(getline(file,line)); 29 | stringstream ss(line); 30 | 31 | int a,b; 32 | ss>>a>>b; 33 | assert(a >= 0 && a< V); 34 | assert(b >= 0 && b < V); 35 | graph.addEdge(a,b); 36 | } 37 | 38 | } 39 | }; -------------------------------------------------------------------------------- /graph-theory/03-basic-structure-on-graph-problem/SparseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class SparseGraph 8 | { 9 | private: 10 | int n, m; // 节点数和边数 11 | bool directed; // 是否为有向图 12 | vector > g; // 图的具体连接情况 13 | 14 | public: 15 | // 构造函数 16 | SparseGraph(int n, int directed) 17 | { 18 | this->n = n; 19 | this->m = 0; 20 | this->directed = directed; 21 | for (int i = 0; i < n; i++) 22 | { 23 | g.push_back(vector()); 24 | } 25 | } 26 | ~SparseGraph() {} 27 | 28 | int V() { return n; } 29 | int W() { return m; } 30 | 31 | void addEdge(int v, int w) 32 | { 33 | assert(v >= 0 && v < n); 34 | assert(w >= 0 && w < n); 35 | g[v].push_back(w); 36 | // 考虑自环边 37 | if (v != w && !directed) 38 | { 39 | g[w].push_back(v); 40 | } 41 | m++; 42 | } 43 | // 需要遍历 O(n) 44 | bool hasEdge(int v, int w) 45 | { 46 | assert(v >= 0 && v < n); 47 | assert(w >= 0 && w < n); 48 | for (int i = 0; i < g[v].size(); i++) 49 | if (g[v][i] == w) 50 | return true; 51 | return false; 52 | } 53 | // 显示图的连接情况 54 | void show(){ 55 | for(int i = 0; i < n; i++) 56 | { 57 | cout<<"vertx "<v = v; 77 | this->index = 0; 78 | } 79 | int begin() 80 | { 81 | index = 0; 82 | if (G.g[v].size()) 83 | { 84 | return G.g[v][index]; 85 | } 86 | return -1; 87 | } 88 | int next() 89 | { 90 | index++; 91 | if (index < G.g[v].size()) 92 | { 93 | return G.g[v][index]; 94 | } 95 | return -1; 96 | } 97 | bool end() 98 | { 99 | return index >= G.g[v].size(); 100 | } 101 | }; 102 | }; -------------------------------------------------------------------------------- /graph-theory/03-basic-structure-on-graph-problem/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ReadGraph.h" 3 | #include "DenseGraph.h" 4 | #include "SparseGraph.h" 5 | 6 | using namespace std; 7 | 8 | int main(){ 9 | string filename = "testG1.txt"; 10 | 11 | SparseGraph g1(13, false); 12 | ReadGraph readGraph1(g1, filename); 13 | g1.show(); 14 | 15 | DenseGraph g2(13, false); 16 | ReadGraph readGraph2(g2, filename); 17 | g2.show(); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /graph-theory/03-basic-structure-on-graph-problem/testG1.txt: -------------------------------------------------------------------------------- 1 | 13 13 2 | 0 5 3 | 4 3 4 | 0 1 5 | 9 12 6 | 6 4 7 | 5 4 8 | 0 2 9 | 11 12 10 | 9 10 11 | 0 6 12 | 7 8 13 | 9 11 14 | 5 3 15 | -------------------------------------------------------------------------------- /graph-theory/03-basic-structure-on-graph-problem/testG2.txt: -------------------------------------------------------------------------------- 1 | 6 8 2 | 0 1 3 | 0 2 4 | 0 5 5 | 1 2 6 | 1 3 7 | 1 4 8 | 3 4 9 | 3 5 10 | -------------------------------------------------------------------------------- /graph-theory/04-DFS-in-graph/Components.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 求无权图的联通分量 7 | template 8 | class Component{ 9 | private: 10 | Graph &G; // 图的引用 11 | bool *visited; // 记录dfs的过程中节点是否被访问 12 | int ccount; // 记录联通分量的个数 13 | int *id; // 每个节点所对应的联通分量值 14 | 15 | // 图的深度优先遍历 16 | void dfs(int v){ 17 | visited[v] = true; 18 | id[v] = ccount; 19 | typename Graph::adjIterator adj(G,v); 20 | for(int i = adj.begin(); !adj.end();i = adj.next()) 21 | { 22 | if(!visited[i]){ 23 | dfs(i); 24 | } 25 | } 26 | } 27 | public: 28 | Component(Graph &graph): G(graph){ 29 | // 初始化数组 30 | visited = new bool[G.V()]; 31 | id = new int[G.V()]; 32 | ccount = 0; 33 | for(int i = 0; i < G.V(); i++) 34 | { 35 | visited[i] = false; 36 | id[i] = -1; 37 | } 38 | // 求联通分量的个数 39 | for(int i = 0; i < G.V(); i++) 40 | { 41 | if(!visited[i]){ 42 | dfs(i); 43 | ccount++; 44 | } 45 | } 46 | } 47 | // 析构函数 48 | ~Component(){ 49 | delete[] visited; 50 | delete[] id; 51 | } 52 | // 返回图的联通分量个数 53 | int count(){ 54 | return ccount; 55 | } 56 | int isConnected(int v,int w){ 57 | assert( v >= 0 && v < G.V()); 58 | assert( w >= 0 && w < G.V()); 59 | return id[v] == id[w]; 60 | } 61 | 62 | }; -------------------------------------------------------------------------------- /graph-theory/04-DFS-in-graph/DenseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class DenseGraph{ 8 | private: 9 | int n, m; // 节点数和边数 10 | bool directed; // 是否为有向图 11 | vector > g; // 图的具体数据 12 | 13 | public: 14 | // 构造函数 15 | DenseGraph(int n, bool directed){ 16 | assert(n >= 0); 17 | this->n = n; 18 | this->m = 0; 19 | this->directed = directed; 20 | for(int i = 0; i < n; i++) 21 | { 22 | g.push_back(vector(n, false)); 23 | } 24 | } 25 | ~DenseGraph(){} 26 | 27 | int V(){return n;} 28 | int E(){return m;} 29 | 30 | void addEdge(int v, int w){ 31 | assert(v >= 0 && v < n); 32 | assert(w >= 0 && w < n); 33 | if(hasEdge(v,w)){ 34 | return; 35 | } 36 | g[v][w] = true; 37 | if(!directed){ 38 | g[w][v] = true; 39 | } 40 | m++; 41 | } 42 | 43 | bool hasEdge(int v, int w){ 44 | assert(v >= 0 && v = 0 && w < n); 46 | return g[v][w]; 47 | } 48 | // 打印邻接矩阵 49 | void show(){ 50 | for(int i = 0; i< n;i++){ 51 | for(int j = 0;j=0 && v< G.n); 66 | this->v = v; 67 | this->index = -1; 68 | } 69 | ~adjIterator(){} 70 | // 返回图G中与顶点v相连接的第一个顶点 71 | int begin(){ 72 | // 索引从-1开始, 因为每次遍历都需要调用一次next() 73 | index = -1; 74 | return next(); 75 | } 76 | int next(){ 77 | for(index +=1;index < G.V();index++) 78 | if(G.g[v][index]) 79 | return index; 80 | return -1; 81 | } 82 | bool end(){ 83 | return index >= G.V(); 84 | } 85 | }; 86 | }; -------------------------------------------------------------------------------- /graph-theory/04-DFS-in-graph/ReadGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | template 10 | 11 | class ReadGraph{ 12 | 13 | public: 14 | ReadGraph(Graph &graph, const string &filename){ 15 | ifstream file(filename); 16 | string line; 17 | int V,E; 18 | 19 | assert( file.is_open()); 20 | assert(getline(file, line)); 21 | 22 | stringstream ss(line); 23 | ss>>V>>E; 24 | 25 | assert(V == graph.V()); 26 | for(int i = 0; i < E; i++) 27 | { 28 | assert(getline(file,line)); 29 | stringstream ss(line); 30 | 31 | int a,b; 32 | ss>>a>>b; 33 | assert(a >= 0 && a< V); 34 | assert(b >= 0 && b < V); 35 | graph.addEdge(a,b); 36 | } 37 | } 38 | }; -------------------------------------------------------------------------------- /graph-theory/04-DFS-in-graph/SparseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class SparseGraph 8 | { 9 | private: 10 | int n, m; // 节点数和边数 11 | bool directed; // 是否为有向图 12 | vector > g; // 图的具体连接情况 13 | 14 | public: 15 | // 构造函数 16 | SparseGraph(int n, int directed) 17 | { 18 | this->n = n; 19 | this->m = 0; 20 | this->directed = directed; 21 | for (int i = 0; i < n; i++) 22 | { 23 | g.push_back(vector()); 24 | } 25 | } 26 | ~SparseGraph() {} 27 | 28 | int V() { return n; } 29 | int W() { return m; } 30 | 31 | void addEdge(int v, int w) 32 | { 33 | assert(v >= 0 && v < n); 34 | assert(w >= 0 && w < n); 35 | g[v].push_back(w); 36 | // 考虑自环边 37 | if (v != w && !directed) 38 | { 39 | g[w].push_back(v); 40 | } 41 | m++; 42 | } 43 | // 需要遍历 O(n) 44 | bool hasEdge(int v, int w) 45 | { 46 | assert(v >= 0 && v < n); 47 | assert(w >= 0 && w < n); 48 | for (int i = 0; i < g[v].size(); i++) 49 | if (g[v][i] == w) 50 | return true; 51 | return false; 52 | } 53 | // 显示图的连接情况 54 | void show(){ 55 | for(int i = 0; i < n; i++) 56 | { 57 | cout<<"vertx "<v = v; 77 | this->index = 0; 78 | } 79 | int begin() 80 | { 81 | index = 0; 82 | if (G.g[v].size()) 83 | { 84 | return G.g[v][index]; 85 | } 86 | return -1; 87 | } 88 | int next() 89 | { 90 | index++; 91 | if (index < G.g[v].size()) 92 | { 93 | return G.g[v][index]; 94 | } 95 | return -1; 96 | } 97 | bool end() 98 | { 99 | return index >= G.g[v].size(); 100 | } 101 | }; 102 | }; -------------------------------------------------------------------------------- /graph-theory/04-DFS-in-graph/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SparseGraph.h" 3 | #include "DenseGraph.h" 4 | #include "ReadGraph.h" 5 | #include "Components.h" 6 | 7 | using namespace std; 8 | 9 | // 测试图的联通分量算法 10 | int main() { 11 | // TestG1.txt : G1 and G2 12 | string filename1 = "testG1.txt"; 13 | SparseGraph g1 = SparseGraph(13, false); 14 | ReadGraph readGraph1(g1, filename1); 15 | Component component1(g1); 16 | cout<<"TestG1.txt, Using Sparse Graph, Component Count: "< readGraph2(g2, filename1); 20 | Component component2(g2); 21 | cout<<"TestG1.txt, Using Dense Graph, Component Count: "< readGraph3(g3, filename2); 29 | Component component3(g3); 30 | cout<<"TestG2.txt, Using Sparse Graph, Component Count: "< readGraph4(g4, filename2); 34 | Component component4(g4); 35 | cout<<"TestG2.txt, Using Dense Graph, Component Count: "< 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 求无权图的联通分量 7 | template 8 | class Component{ 9 | private: 10 | Graph &G; // 图的引用 11 | bool *visited; // 记录dfs的过程中节点是否被访问 12 | int ccount; // 记录联通分量的个数 13 | int *id; // 每个节点所对应的联通分量值 14 | 15 | // 图的深度优先遍历 16 | void dfs(int v){ 17 | visited[v] = true; 18 | id[v] = ccount; 19 | typename Graph::adjIterator adj(G,v); 20 | for(int i = adj.begin(); !adj.end();i = adj.next()) 21 | { 22 | if(!visited[i]){ 23 | dfs(i); 24 | } 25 | } 26 | } 27 | public: 28 | Component(Graph &graph): G(graph){ 29 | // 初始化数组 30 | visited = new bool[G.V()]; 31 | id = new int[G.V()]; 32 | ccount = 0; 33 | for(int i = 0; i < G.V(); i++) 34 | { 35 | visited[i] = false; 36 | id[i] = -1; 37 | } 38 | // 求联通分量的个数 39 | for(int i = 0; i < G.V(); i++) 40 | { 41 | if(!visited[i]){ 42 | dfs(i); 43 | ccount++; 44 | } 45 | } 46 | } 47 | // 析构函数 48 | ~Component(){ 49 | delete[] visited; 50 | delete[] id; 51 | } 52 | // 返回图的联通分量个数 53 | int count(){ 54 | return ccount; 55 | } 56 | int isConnected(int v,int w){ 57 | assert( v >= 0 && v < G.V()); 58 | assert( w >= 0 && w < G.V()); 59 | return id[v] == id[w]; 60 | } 61 | 62 | }; -------------------------------------------------------------------------------- /graph-theory/05-path-find/DenseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class DenseGraph{ 8 | private: 9 | int n, m; // 节点数和边数 10 | bool directed; // 是否为有向图 11 | vector > g; // 图的具体数据 12 | 13 | public: 14 | // 构造函数 15 | DenseGraph(int n, bool directed){ 16 | assert(n >= 0); 17 | this->n = n; 18 | this->m = 0; 19 | this->directed = directed; 20 | for(int i = 0; i < n; i++) 21 | { 22 | g.push_back(vector(n, false)); 23 | } 24 | } 25 | ~DenseGraph(){} 26 | 27 | int V(){return n;} 28 | int E(){return m;} 29 | 30 | void addEdge(int v, int w){ 31 | assert(v >= 0 && v < n); 32 | assert(w >= 0 && w < n); 33 | if(hasEdge(v,w)){ 34 | return; 35 | } 36 | g[v][w] = true; 37 | if(!directed){ 38 | g[w][v] = true; 39 | } 40 | m++; 41 | } 42 | 43 | bool hasEdge(int v, int w){ 44 | assert(v >= 0 && v = 0 && w < n); 46 | return g[v][w]; 47 | } 48 | // 打印邻接矩阵 49 | void show(){ 50 | for(int i = 0; i< n;i++){ 51 | for(int j = 0;j=0 && v< G.n); 66 | this->v = v; 67 | this->index = -1; 68 | } 69 | ~adjIterator(){} 70 | // 返回图G中与顶点v相连接的第一个顶点 71 | int begin(){ 72 | // 索引从-1开始, 因为每次遍历都需要调用一次next() 73 | index = -1; 74 | return next(); 75 | } 76 | int next(){ 77 | for(index +=1;index < G.V();index++) 78 | if(G.g[v][index]) 79 | return index; 80 | return -1; 81 | } 82 | bool end(){ 83 | return index >= G.V(); 84 | } 85 | }; 86 | }; -------------------------------------------------------------------------------- /graph-theory/05-path-find/Path.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz on 9/22/16. 3 | // 4 | 5 | #ifndef INC_06_FINDING_A_PATH_PATH_H 6 | #define INC_06_FINDING_A_PATH_PATH_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | // 路径查询 16 | template 17 | class Path{ 18 | 19 | private: 20 | Graph &G; // 图的引用 21 | int s; // 起始点 22 | bool* visited; // 记录dfs的过程中节点是否被访问 23 | int * from; // 记录路径, from[i]表示查找的路径上i的上一个节点 24 | 25 | // 图的深度优先遍历 26 | void dfs( int v ){ 27 | 28 | visited[v] = true; 29 | 30 | typename Graph::adjIterator adj(G, v); 31 | for( int i = adj.begin() ; !adj.end() ; i = adj.next() ){ 32 | if( !visited[i] ){ 33 | from[i] = v; 34 | dfs(i); 35 | } 36 | } 37 | } 38 | 39 | public: 40 | // 构造函数, 寻路算法, 寻找图graph从s点到其他点的路径 41 | Path(Graph &graph, int s):G(graph){ 42 | 43 | // 算法初始化 44 | assert( s >= 0 && s < G.V() ); 45 | 46 | visited = new bool[G.V()]; 47 | from = new int[G.V()]; 48 | for( int i = 0 ; i < G.V() ; i ++ ){ 49 | visited[i] = false; 50 | from[i] = -1; 51 | } 52 | this->s = s; 53 | 54 | // 寻路算法 55 | dfs(s); 56 | } 57 | 58 | // 析构函数 59 | ~Path(){ 60 | 61 | delete [] visited; 62 | delete [] from; 63 | } 64 | 65 | // 查询从s点到w点是否有路径 66 | bool hasPath(int w){ 67 | assert( w >= 0 && w < G.V() ); 68 | return visited[w]; 69 | } 70 | 71 | // 查询从s点到w点的路径, 存放在vec中 72 | void path(int w, vector &vec){ 73 | 74 | assert( hasPath(w) ); 75 | 76 | stack s; 77 | // 通过from数组逆向查找到从s到w的路径, 存放到栈中 78 | int p = w; 79 | while( p != -1 ){ 80 | s.push(p); 81 | p = from[p]; 82 | } 83 | 84 | // 从栈中依次取出元素, 获得顺序的从s到w的路径 85 | vec.clear(); 86 | while( !s.empty() ){ 87 | vec.push_back( s.top() ); 88 | s.pop(); 89 | } 90 | } 91 | 92 | // 打印出从s点到w点的路径 93 | void showPath(int w){ 94 | 95 | assert( hasPath(w) ); 96 | 97 | vector vec; 98 | path( w , vec ); 99 | for( int i = 0 ; i < vec.size() ; i ++ ){ 100 | cout< "; 105 | } 106 | } 107 | }; 108 | 109 | #endif //INC_06_FINDING_A_PATH_PATH_H 110 | -------------------------------------------------------------------------------- /graph-theory/05-path-find/ReadGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | template 10 | 11 | class ReadGraph{ 12 | 13 | public: 14 | ReadGraph(Graph &graph, const string &filename){ 15 | ifstream file(filename); 16 | string line; 17 | int V,E; 18 | 19 | assert( file.is_open()); 20 | assert(getline(file, line)); 21 | 22 | stringstream ss(line); 23 | ss>>V>>E; 24 | 25 | assert(V == graph.V()); 26 | for(int i = 0; i < E; i++) 27 | { 28 | assert(getline(file,line)); 29 | stringstream ss(line); 30 | 31 | int a,b; 32 | ss>>a>>b; 33 | assert(a >= 0 && a< V); 34 | assert(b >= 0 && b < V); 35 | graph.addEdge(a,b); 36 | } 37 | } 38 | }; -------------------------------------------------------------------------------- /graph-theory/05-path-find/SparseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class SparseGraph 8 | { 9 | private: 10 | int n, m; // 节点数和边数 11 | bool directed; // 是否为有向图 12 | vector > g; // 图的具体连接情况 13 | 14 | public: 15 | // 构造函数 16 | SparseGraph(int n, int directed) 17 | { 18 | this->n = n; 19 | this->m = 0; 20 | this->directed = directed; 21 | for (int i = 0; i < n; i++) 22 | { 23 | g.push_back(vector()); 24 | } 25 | } 26 | ~SparseGraph() {} 27 | 28 | int V() { return n; } 29 | int W() { return m; } 30 | 31 | void addEdge(int v, int w) 32 | { 33 | assert(v >= 0 && v < n); 34 | assert(w >= 0 && w < n); 35 | g[v].push_back(w); 36 | // 考虑自环边 37 | if (v != w && !directed) 38 | { 39 | g[w].push_back(v); 40 | } 41 | m++; 42 | } 43 | // 需要遍历 O(n) 44 | bool hasEdge(int v, int w) 45 | { 46 | assert(v >= 0 && v < n); 47 | assert(w >= 0 && w < n); 48 | for (int i = 0; i < g[v].size(); i++) 49 | if (g[v][i] == w) 50 | return true; 51 | return false; 52 | } 53 | // 显示图的连接情况 54 | void show(){ 55 | for(int i = 0; i < n; i++) 56 | { 57 | cout<<"vertx "<v = v; 77 | this->index = 0; 78 | } 79 | int begin() 80 | { 81 | index = 0; 82 | if (G.g[v].size()) 83 | { 84 | return G.g[v][index]; 85 | } 86 | return -1; 87 | } 88 | int next() 89 | { 90 | index++; 91 | if (index < G.g[v].size()) 92 | { 93 | return G.g[v][index]; 94 | } 95 | return -1; 96 | } 97 | bool end() 98 | { 99 | return index >= G.g[v].size(); 100 | } 101 | }; 102 | }; -------------------------------------------------------------------------------- /graph-theory/05-path-find/main.cpp: -------------------------------------------------------------------------------- 1 | #include "DenseGraph.h" 2 | #include "SparseGraph.h" 3 | #include "Path.h" 4 | #include "ReadGraph.h" 5 | 6 | using namespace std; 7 | 8 | int main(){ 9 | 10 | string filename = "testG.txt"; 11 | SparseGraph g = SparseGraph(7,false); 12 | ReadGraph readGraph(g, filename); 13 | g.show(); 14 | cout< dfs(g,0); 17 | cout<<"DFS: "; 18 | dfs.showPath(6); 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /graph-theory/05-path-find/testG.txt: -------------------------------------------------------------------------------- 1 | 7 8 2 | 0 1 3 | 0 2 4 | 0 5 5 | 0 6 6 | 3 4 7 | 3 5 8 | 4 5 9 | 4 6 10 | -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/Components.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 求无权图的联通分量 7 | template 8 | class Component{ 9 | private: 10 | Graph &G; // 图的引用 11 | bool *visited; // 记录dfs的过程中节点是否被访问 12 | int ccount; // 记录联通分量的个数 13 | int *id; // 每个节点所对应的联通分量值 14 | 15 | // 图的深度优先遍历 16 | void dfs(int v){ 17 | visited[v] = true; 18 | id[v] = ccount; 19 | typename Graph::adjIterator adj(G,v); 20 | for(int i = adj.begin(); !adj.end();i = adj.next()) 21 | { 22 | if(!visited[i]){ 23 | dfs(i); 24 | } 25 | } 26 | } 27 | public: 28 | Component(Graph &graph): G(graph){ 29 | // 初始化数组 30 | visited = new bool[G.V()]; 31 | id = new int[G.V()]; 32 | ccount = 0; 33 | for(int i = 0; i < G.V(); i++) 34 | { 35 | visited[i] = false; 36 | id[i] = -1; 37 | } 38 | // 求联通分量的个数 39 | for(int i = 0; i < G.V(); i++) 40 | { 41 | if(!visited[i]){ 42 | dfs(i); 43 | ccount++; 44 | } 45 | } 46 | } 47 | // 析构函数 48 | ~Component(){ 49 | delete[] visited; 50 | delete[] id; 51 | } 52 | // 返回图的联通分量个数 53 | int count(){ 54 | return ccount; 55 | } 56 | int isConnected(int v,int w){ 57 | assert( v >= 0 && v < G.V()); 58 | assert( w >= 0 && w < G.V()); 59 | return id[v] == id[w]; 60 | } 61 | 62 | }; -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/DenseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class DenseGraph{ 8 | private: 9 | int n, m; // 节点数和边数 10 | bool directed; // 是否为有向图 11 | vector > g; // 图的具体数据 12 | 13 | public: 14 | // 构造函数 15 | DenseGraph(int n, bool directed){ 16 | assert(n >= 0); 17 | this->n = n; 18 | this->m = 0; 19 | this->directed = directed; 20 | for(int i = 0; i < n; i++) 21 | { 22 | g.push_back(vector(n, false)); 23 | } 24 | } 25 | ~DenseGraph(){} 26 | 27 | int V(){return n;} 28 | int E(){return m;} 29 | 30 | void addEdge(int v, int w){ 31 | assert(v >= 0 && v < n); 32 | assert(w >= 0 && w < n); 33 | if(hasEdge(v,w)){ 34 | return; 35 | } 36 | g[v][w] = true; 37 | if(!directed){ 38 | g[w][v] = true; 39 | } 40 | m++; 41 | } 42 | 43 | bool hasEdge(int v, int w){ 44 | assert(v >= 0 && v = 0 && w < n); 46 | return g[v][w]; 47 | } 48 | // 打印邻接矩阵 49 | void show(){ 50 | for(int i = 0; i< n;i++){ 51 | for(int j = 0;j=0 && v< G.n); 66 | this->v = v; 67 | this->index = -1; 68 | } 69 | ~adjIterator(){} 70 | // 返回图G中与顶点v相连接的第一个顶点 71 | int begin(){ 72 | // 索引从-1开始, 因为每次遍历都需要调用一次next() 73 | index = -1; 74 | return next(); 75 | } 76 | int next(){ 77 | for(index +=1;index < G.V();index++) 78 | if(G.g[v][index]) 79 | return index; 80 | return -1; 81 | } 82 | bool end(){ 83 | return index >= G.V(); 84 | } 85 | }; 86 | }; -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/Path.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz on 9/22/16. 3 | // 4 | 5 | #ifndef INC_06_FINDING_A_PATH_PATH_H 6 | #define INC_06_FINDING_A_PATH_PATH_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | // 路径查询 16 | template 17 | class Path{ 18 | 19 | private: 20 | Graph &G; // 图的引用 21 | int s; // 起始点 22 | bool* visited; // 记录dfs的过程中节点是否被访问 23 | int * from; // 记录路径, from[i]表示查找的路径上i的上一个节点 24 | 25 | // 图的深度优先遍历 26 | void dfs( int v ){ 27 | 28 | visited[v] = true; 29 | 30 | typename Graph::adjIterator adj(G, v); 31 | for( int i = adj.begin() ; !adj.end() ; i = adj.next() ){ 32 | if( !visited[i] ){ 33 | from[i] = v; 34 | dfs(i); 35 | } 36 | } 37 | } 38 | 39 | public: 40 | // 构造函数, 寻路算法, 寻找图graph从s点到其他点的路径 41 | Path(Graph &graph, int s):G(graph){ 42 | 43 | // 算法初始化 44 | assert( s >= 0 && s < G.V() ); 45 | 46 | visited = new bool[G.V()]; 47 | from = new int[G.V()]; 48 | for( int i = 0 ; i < G.V() ; i ++ ){ 49 | visited[i] = false; 50 | from[i] = -1; 51 | } 52 | this->s = s; 53 | 54 | // 寻路算法 55 | dfs(s); 56 | } 57 | 58 | // 析构函数 59 | ~Path(){ 60 | 61 | delete [] visited; 62 | delete [] from; 63 | } 64 | 65 | // 查询从s点到w点是否有路径 66 | bool hasPath(int w){ 67 | assert( w >= 0 && w < G.V() ); 68 | return visited[w]; 69 | } 70 | 71 | // 查询从s点到w点的路径, 存放在vec中 72 | void path(int w, vector &vec){ 73 | 74 | assert( hasPath(w) ); 75 | 76 | stack s; 77 | // 通过from数组逆向查找到从s到w的路径, 存放到栈中 78 | int p = w; 79 | while( p != -1 ){ 80 | s.push(p); 81 | p = from[p]; 82 | } 83 | 84 | // 从栈中依次取出元素, 获得顺序的从s到w的路径 85 | vec.clear(); 86 | while( !s.empty() ){ 87 | vec.push_back( s.top() ); 88 | s.pop(); 89 | } 90 | } 91 | 92 | // 打印出从s点到w点的路径 93 | void showPath(int w){ 94 | 95 | assert( hasPath(w) ); 96 | 97 | vector vec; 98 | path( w , vec ); 99 | for( int i = 0 ; i < vec.size() ; i ++ ){ 100 | cout< "; 105 | } 106 | } 107 | }; 108 | 109 | #endif //INC_06_FINDING_A_PATH_PATH_H 110 | -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/ReadGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | template 10 | 11 | class ReadGraph{ 12 | 13 | public: 14 | ReadGraph(Graph &graph, const string &filename){ 15 | ifstream file(filename); 16 | string line; 17 | int V,E; 18 | 19 | assert( file.is_open()); 20 | assert(getline(file, line)); 21 | 22 | stringstream ss(line); 23 | ss>>V>>E; 24 | 25 | assert(V == graph.V()); 26 | for(int i = 0; i < E; i++) 27 | { 28 | assert(getline(file,line)); 29 | stringstream ss(line); 30 | 31 | int a,b; 32 | ss>>a>>b; 33 | assert(a >= 0 && a< V); 34 | assert(b >= 0 && b < V); 35 | graph.addEdge(a,b); 36 | } 37 | } 38 | }; -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/ShortestPath.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz on 9/22/16. 3 | // 4 | 5 | #ifndef INC_07_BFS_AND_SHORTEST_PATH_SHORTESTPATH_H 6 | #define INC_07_BFS_AND_SHORTEST_PATH_SHORTESTPATH_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | 17 | // 寻找无权图的最短路径 18 | template 19 | class ShortestPath{ 20 | 21 | private: 22 | Graph &G; // 图的引用 23 | int s; // 起始点 24 | bool *visited; // 记录dfs的过程中节点是否被访问 25 | int *from; // 记录路径, from[i]表示查找的路径上i的上一个节点 26 | int *ord; // 记录路径中节点的次序。ord[i]表示i节点在路径中的次序。 27 | 28 | public: 29 | // 构造函数, 寻找无权图graph从s点到其他点的最短路径 30 | ShortestPath(Graph &graph, int s):G(graph){ 31 | 32 | // 算法初始化 33 | assert( s >= 0 && s < graph.V() ); 34 | 35 | visited = new bool[graph.V()]; 36 | from = new int[graph.V()]; 37 | ord = new int[graph.V()]; 38 | for( int i = 0 ; i < graph.V() ; i ++ ){ 39 | visited[i] = false; 40 | from[i] = -1; 41 | ord[i] = -1; 42 | } 43 | this->s = s; 44 | 45 | // 无向图最短路径算法, 从s开始广度优先遍历整张图 46 | queue q; 47 | 48 | q.push( s ); 49 | visited[s] = true; 50 | ord[s] = 0; 51 | while( !q.empty() ){ 52 | 53 | int v = q.front(); 54 | q.pop(); 55 | 56 | typename Graph::adjIterator adj(G, v); 57 | for( int i = adj.begin() ; !adj.end() ; i = adj.next() ) 58 | if( !visited[i] ){ 59 | q.push(i); 60 | visited[i] = true; 61 | from[i] = v; 62 | ord[i] = ord[v] + 1; 63 | } 64 | } 65 | 66 | } 67 | 68 | // 析构函数 69 | ~ShortestPath(){ 70 | 71 | delete [] visited; 72 | delete [] from; 73 | delete [] ord; 74 | } 75 | 76 | // 查询从s点到w点是否有路径 77 | bool hasPath(int w){ 78 | assert( w >= 0 && w < G.V() ); 79 | return visited[w]; 80 | } 81 | 82 | // 查询从s点到w点的路径, 存放在vec中 83 | void path(int w, vector &vec){ 84 | 85 | assert( w >= 0 && w < G.V() ); 86 | 87 | stack s; 88 | // 通过from数组逆向查找到从s到w的路径, 存放到栈中 89 | int p = w; 90 | while( p != -1 ){ 91 | s.push(p); 92 | p = from[p]; 93 | } 94 | 95 | // 从栈中依次取出元素, 获得顺序的从s到w的路径 96 | vec.clear(); 97 | while( !s.empty() ){ 98 | vec.push_back( s.top() ); 99 | s.pop(); 100 | } 101 | } 102 | 103 | // 打印出从s点到w点的路径 104 | void showPath(int w){ 105 | 106 | assert( w >= 0 && w < G.V() ); 107 | 108 | vector vec; 109 | path(w, vec); 110 | for( int i = 0 ; i < vec.size() ; i ++ ){ 111 | cout< "; 116 | } 117 | } 118 | 119 | // 查看从s点到w点的最短路径长度 120 | int length(int w){ 121 | assert( w >= 0 && w < G.V() ); 122 | return ord[w]; 123 | } 124 | }; 125 | 126 | #endif //INC_07_BFS_AND_SHORTEST_PATH_SHORTESTPATH_H 127 | -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/SparseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class SparseGraph 8 | { 9 | private: 10 | int n, m; // 节点数和边数 11 | bool directed; // 是否为有向图 12 | vector > g; // 图的具体连接情况 13 | 14 | public: 15 | // 构造函数 16 | SparseGraph(int n, int directed) 17 | { 18 | this->n = n; 19 | this->m = 0; 20 | this->directed = directed; 21 | for (int i = 0; i < n; i++) 22 | { 23 | g.push_back(vector()); 24 | } 25 | } 26 | ~SparseGraph() {} 27 | 28 | int V() { return n; } 29 | int W() { return m; } 30 | 31 | void addEdge(int v, int w) 32 | { 33 | assert(v >= 0 && v < n); 34 | assert(w >= 0 && w < n); 35 | g[v].push_back(w); 36 | // 考虑自环边 37 | if (v != w && !directed) 38 | { 39 | g[w].push_back(v); 40 | } 41 | m++; 42 | } 43 | // 需要遍历 O(n) 44 | bool hasEdge(int v, int w) 45 | { 46 | assert(v >= 0 && v < n); 47 | assert(w >= 0 && w < n); 48 | for (int i = 0; i < g[v].size(); i++) 49 | if (g[v][i] == w) 50 | return true; 51 | return false; 52 | } 53 | // 显示图的连接情况 54 | void show(){ 55 | for(int i = 0; i < n; i++) 56 | { 57 | cout<<"vertx "<v = v; 77 | this->index = 0; 78 | } 79 | int begin() 80 | { 81 | index = 0; 82 | if (G.g[v].size()) 83 | { 84 | return G.g[v][index]; 85 | } 86 | return -1; 87 | } 88 | int next() 89 | { 90 | index++; 91 | if (index < G.g[v].size()) 92 | { 93 | return G.g[v][index]; 94 | } 95 | return -1; 96 | } 97 | bool end() 98 | { 99 | return index >= G.g[v].size(); 100 | } 101 | }; 102 | }; -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SparseGraph.h" 3 | #include "DenseGraph.h" 4 | #include "ReadGraph.h" 5 | #include "Path.h" 6 | #include "ShortestPath.h" 7 | 8 | using namespace std; 9 | 10 | int main(){ 11 | string filename = "testG.txt"; 12 | SparseGraph g = SparseGraph(7, false); 13 | ReadGraph readGraph(g, filename); 14 | g.show(); 15 | cout< dfs(g,0); 18 | cout<<"DFS: "; 19 | dfs.showPath(6); 20 | 21 | ShortestPath bfs(g,0); 22 | cout<<"BFS: "; 23 | bfs.showPath(6); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /graph-theory/06-BFS-in-graph/testG.txt: -------------------------------------------------------------------------------- 1 | 7 8 2 | 0 1 3 | 0 2 4 | 0 5 5 | 0 6 6 | 3 4 7 | 3 5 8 | 4 5 9 | 4 6 10 | -------------------------------------------------------------------------------- /heap-sort/01-MaxHeap/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | template 15 | class MaxHeap 16 | { 17 | private: 18 | Item *data; 19 | int count; 20 | 21 | public: 22 | // 构造函数, 构造一个空堆, 可容纳capacity个元素 23 | MaxHeap(int capacity) 24 | { 25 | data = new Item[capacity + 1]; 26 | count = 0; 27 | } 28 | 29 | ~MaxHeap() 30 | { 31 | delete[] data; 32 | } 33 | // 返回堆中的元素个数 34 | int size() 35 | { 36 | return count; 37 | } 38 | // 返回一个布尔值, 表示堆中是否为空 39 | bool isEmpty() 40 | { 41 | return count == 0; 42 | } 43 | }; 44 | 45 | int main() 46 | { 47 | MaxHeap maxheap = MaxHeap(100); 48 | cout< 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | template 15 | class MaxHeap 16 | { 17 | private: 18 | Item *data; 19 | int count; 20 | int capacity; 21 | 22 | void shiftUP(int k) 23 | { 24 | while (k > 1 && data[k / 2] < data[k]) 25 | { 26 | swap(data[k / 2], data[k]); 27 | k /= 2; 28 | } 29 | } 30 | void shiftDown(int k) 31 | { 32 | while (2 * k <= count) 33 | { 34 | int j = 2 * k; // 35 | if (j + 1 <= count && data[j + 1] > data[j]) 36 | j += 1; 37 | if (data[k] >= data[j]) 38 | break; 39 | swap(data[k], data[j]); 40 | k = j; 41 | } 42 | } 43 | 44 | public: 45 | // 构造函数, 构造一个空堆, 可容纳capacity个元素 46 | MaxHeap(int capacity) 47 | { 48 | data = new Item[capacity + 1]; 49 | count = 0; 50 | this->capacity = capacity; 51 | } 52 | 53 | MaxHeap(Item arr[], int n) 54 | { 55 | data = new Item[n + 1]; 56 | capacity = n; 57 | 58 | for (int i = 0; i < n; i++) 59 | data[i + 1] = arr[i]; 60 | count = n; 61 | 62 | for (int i = count / 2; i >= 1; i--) 63 | shiftDown(i); 64 | } 65 | 66 | ~MaxHeap() 67 | { 68 | delete[] data; 69 | } 70 | 71 | int size() 72 | { 73 | return count; 74 | } 75 | 76 | // 返回一个布尔值, 表示堆中是否为空 77 | bool isEmpty() 78 | { 79 | return count == 0; 80 | } 81 | 82 | // 向最大堆中插入一个新的元素 item 83 | void insert(Item item) 84 | { 85 | assert(count + 1 <= capacity); 86 | data[count + 1] = item; 87 | count++; 88 | shiftUP(count); 89 | } 90 | Item extractMax() 91 | { 92 | assert(count > 0); 93 | Item ret = data[1]; 94 | swap(data[1], data[count]); 95 | count--; 96 | shiftDown(1); 97 | return ret; 98 | } 99 | }; 100 | 101 | // 测试最大堆 102 | int main() 103 | { 104 | MaxHeap maxheap = MaxHeap(100); 105 | srand(time(NULL)); 106 | int n = 100; // 随机生成n个元素放入最大堆中 107 | for (int i = 0; i < n; i++) 108 | { 109 | maxheap.insert(rand() % 100); 110 | } 111 | 112 | int *arr = new int[n]; 113 | // 将maxheap中的数据逐渐使用extractMax取出来 114 | // 取出来的顺序应该是按照从大到小的顺序取出来的 115 | for (int i = 0; i < n; i++) 116 | { 117 | arr[i] = maxheap.extractMax(); 118 | cout << arr[i] << " "; 119 | } 120 | cout << endl; 121 | // 确保arr数组是从大到小排列的 122 | for (int i = 1; i < n; i++) 123 | assert(arr[i - 1] >= arr[i]); 124 | delete[] arr; 125 | return 0; 126 | } -------------------------------------------------------------------------------- /heap-sort/04-Heapify/Heap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_05_HEAPIFY_HEAP_H 6 | #define INC_05_HEAPIFY_HEAP_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | class MaxHeap 15 | { 16 | 17 | private: 18 | Item *data; 19 | int count; 20 | int capacity; 21 | 22 | void shiftUp(int k) 23 | { 24 | while (k > 1 && data[k / 2] < data[k]) 25 | { 26 | swap(data[k / 2], data[k]); 27 | k /= 2; 28 | } 29 | } 30 | 31 | void shiftDown(int k) 32 | { 33 | while (2 * k <= count) 34 | { 35 | int j = 2 * k; 36 | if (j + 1 <= count && data[j + 1] > data[j]) 37 | j++; 38 | if (data[k] >= data[j]) 39 | break; 40 | swap(data[k], data[j]); 41 | k = j; 42 | } 43 | } 44 | 45 | public: 46 | // 构造函数, 构造一个空堆, 可容纳capacity个元素 47 | MaxHeap(int capacity) 48 | { 49 | data = new Item[capacity + 1]; 50 | count = 0; 51 | this->capacity = capacity; 52 | } 53 | 54 | // 构造函数, 通过一个给定数组创建一个最大堆 55 | // 该构造堆的过程, 时间复杂度为O(n) 56 | MaxHeap(Item arr[], int n) 57 | { 58 | data = new Item[n + 1]; 59 | capacity = n; 60 | 61 | for (int i = 0; i < n; i++) 62 | data[i + 1] = arr[i]; 63 | count = n; 64 | 65 | for (int i = count / 2; i >= 1; i--) 66 | shiftDown(i); 67 | } 68 | 69 | ~MaxHeap() 70 | { 71 | delete[] data; 72 | } 73 | 74 | // 返回堆中的元素个数 75 | int size() 76 | { 77 | return count; 78 | } 79 | 80 | // 返回一个布尔值, 表示堆中是否为空 81 | bool isEmpty() 82 | { 83 | return count == 0; 84 | } 85 | 86 | // 像最大堆中插入一个新的元素 item 87 | void insert(Item item) 88 | { 89 | assert(count + 1 <= capacity); 90 | data[count + 1] = item; 91 | shiftUp(count + 1); 92 | count++; 93 | } 94 | 95 | // 从最大堆中取出堆顶元素, 即堆中所存储的最大数据 96 | Item extractMax() 97 | { 98 | assert(count > 0); 99 | Item ret = data[1]; 100 | swap(data[1], data[count]); 101 | count--; 102 | shiftDown(1); 103 | return ret; 104 | } 105 | 106 | // 获取最大堆中的堆顶元素 107 | Item getMax() 108 | { 109 | assert(count > 0); 110 | return data[1]; 111 | } 112 | }; 113 | 114 | #endif //INC_05_HEAPIFY_HEAP_H 115 | -------------------------------------------------------------------------------- /heap-sort/04-Heapify/InsertionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_05_HEAPIFY_INSERTIONSORT_H 6 | #define INC_05_HEAPIFY_INSERTIONSORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_05_HEAPIFY_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /heap-sort/04-Heapify/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_05_HEAPIFY_MERGESORT_H 6 | #define INC_05_HEAPIFY_MERGESORT_H 7 | 8 | #include 9 | #include 10 | #include "InsertionSort.h" 11 | 12 | using namespace std; 13 | 14 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 15 | // 其中aux为完成merge过程所需要的辅助空间 16 | template 17 | void __merge(T arr[], T aux[], int l, int mid, int r) 18 | { 19 | 20 | // 由于aux的大小和arr一样, 所以我们也不需要处理aux索引的偏移量 21 | // 进一步节省了计算量:) 22 | for (int i = l; i <= r; i++) 23 | aux[i] = arr[i]; 24 | 25 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 26 | int i = l, j = mid + 1; 27 | for (int k = l; k <= r; k++) 28 | { 29 | 30 | if (i > mid) 31 | { // 如果左半部分元素已经全部处理完毕 32 | arr[k] = aux[j]; 33 | j++; 34 | } 35 | else if (j > r) 36 | { // 如果右半部分元素已经全部处理完毕 37 | arr[k] = aux[i]; 38 | i++; 39 | } 40 | else if (aux[i] < aux[j]) 41 | { // 左半部分所指元素 < 右半部分所指元素 42 | arr[k] = aux[i]; 43 | i++; 44 | } 45 | else 46 | { // 左半部分所指元素 >= 右半部分所指元素 47 | arr[k] = aux[j]; 48 | j++; 49 | } 50 | } 51 | } 52 | 53 | // 使用优化的归并排序算法, 对arr[l...r]的范围进行排序 54 | // 其中aux为完成merge过程所需要的辅助空间 55 | template 56 | void __mergeSort(T arr[], T aux[], int l, int r) 57 | { 58 | 59 | // 对于小规模数组, 使用插入排序 60 | if (r - l <= 15) 61 | { 62 | insertionSort(arr, l, r); 63 | return; 64 | } 65 | 66 | int mid = (l + r) / 2; 67 | __mergeSort(arr, aux, l, mid); 68 | __mergeSort(arr, aux, mid + 1, r); 69 | 70 | // 对于arr[mid] <= arr[mid+1]的情况,不进行merge 71 | // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失 72 | if (arr[mid] > arr[mid + 1]) 73 | __merge(arr, aux, l, mid, r); 74 | } 75 | 76 | template 77 | void mergeSort(T arr[], int n) 78 | { 79 | 80 | // 在 mergeSort中, 我们一次性申请aux空间, 81 | // 并将这个辅助空间以参数形式传递给完成归并排序的各个子函数 82 | T *aux = new T[n]; 83 | 84 | __mergeSort(arr, aux, 0, n - 1); 85 | 86 | delete[] aux; // 使用C++, new出来的空间不要忘记释放掉:) 87 | } 88 | 89 | #endif //INC_05_HEAPIFY_MERGESORT_H 90 | -------------------------------------------------------------------------------- /heap-sort/04-Heapify/QuickSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_05_HEAPIFY_QUICKSORT_H 6 | #define INC_05_HEAPIFY_QUICKSORT_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include "InsertionSort.h" 12 | 13 | using namespace std; 14 | 15 | // 对arr[l...r]部分进行partition操作 16 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 17 | template 18 | int _partition(T arr[], int l, int r) 19 | { 20 | 21 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 22 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 23 | 24 | T v = arr[l]; 25 | int j = l; 26 | for (int i = l + 1; i <= r; i++) 27 | if (arr[i] < v) 28 | { 29 | j++; 30 | swap(arr[j], arr[i]); 31 | } 32 | 33 | swap(arr[l], arr[j]); 34 | 35 | return j; 36 | } 37 | 38 | // 对arr[l...r]部分进行快速排序 39 | template 40 | void _quickSort(T arr[], int l, int r) 41 | { 42 | 43 | // 对于小规模数组, 使用插入排序进行优化 44 | if (r - l <= 15) 45 | { 46 | insertionSort(arr, l, r); 47 | return; 48 | } 49 | 50 | int p = _partition(arr, l, r); 51 | _quickSort(arr, l, p - 1); 52 | _quickSort(arr, p + 1, r); 53 | } 54 | 55 | template 56 | void quickSort(T arr[], int n) 57 | { 58 | 59 | srand(time(NULL)); 60 | _quickSort(arr, 0, n - 1); 61 | } 62 | 63 | #endif //INC_05_HEAPIFY_QUICKSORT_H 64 | -------------------------------------------------------------------------------- /heap-sort/04-Heapify/QuickSort2Ways.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_05_HEAPIFY_QUICKSORT2WAYS_H 6 | #define INC_05_HEAPIFY_QUICKSORT2WAYS_H 7 | 8 | #include 9 | #include 10 | #include "InsertionSort.h" 11 | 12 | using namespace std; 13 | 14 | // 双路快速排序的partition 15 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 16 | template 17 | int _partition2(T arr[], int l, int r) 18 | { 19 | 20 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 21 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 22 | T v = arr[l]; 23 | 24 | // arr[l+1...i) <= v; arr(j...r] >= v 25 | int i = l + 1, j = r; 26 | while (true) 27 | { 28 | // 注意这里的边界, arr[i] < v, 不能是arr[i] <= v 29 | // 思考一下为什么? 30 | while (i <= r && arr[i] < v) 31 | i++; 32 | 33 | // 注意这里的边界, arr[j] > v, 不能是arr[j] >= v 34 | // 思考一下为什么? 35 | while (j >= l + 1 && arr[j] > v) 36 | j--; 37 | 38 | // 对于上面的两个边界的设定, 有的同学在课程的问答区有很好的回答:) 39 | // 大家可以参考: http://coding.imooc.com/learn/questiondetail/4920.html 40 | 41 | if (i > j) 42 | break; 43 | 44 | swap(arr[i], arr[j]); 45 | i++; 46 | j--; 47 | } 48 | 49 | swap(arr[l], arr[j]); 50 | 51 | return j; 52 | } 53 | 54 | // 对arr[l...r]部分进行快速排序 55 | template 56 | void _quickSort2Ways(T arr[], int l, int r) 57 | { 58 | 59 | // 对于小规模数组, 使用插入排序进行优化 60 | if (r - l <= 15) 61 | { 62 | insertionSort(arr, l, r); 63 | return; 64 | } 65 | 66 | // 调用双路快速排序的partition 67 | int p = _partition2(arr, l, r); 68 | _quickSort2Ways(arr, l, p - 1); 69 | _quickSort2Ways(arr, p + 1, r); 70 | } 71 | 72 | template 73 | void quickSort2Ways(T arr[], int n) 74 | { 75 | 76 | srand(time(NULL)); 77 | _quickSort2Ways(arr, 0, n - 1); 78 | } 79 | 80 | #endif //INC_05_HEAPIFY_QUICKSORT2WAYS_H 81 | -------------------------------------------------------------------------------- /heap-sort/04-Heapify/QuickSort3Ways.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_05_HEAPIFY_QUICKSORT3WAYS_H 6 | #define INC_05_HEAPIFY_QUICKSORT3WAYS_H 7 | 8 | #include 9 | #include 10 | #include "InsertionSort.h" 11 | 12 | using namespace std; 13 | 14 | // 递归的三路快速排序算法 15 | template 16 | void __quickSort3Ways(T arr[], int l, int r) 17 | { 18 | 19 | // 对于小规模数组, 使用插入排序进行优化 20 | if (r - l <= 15) 21 | { 22 | insertionSort(arr, l, r); 23 | return; 24 | } 25 | 26 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 27 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 28 | 29 | T v = arr[l]; 30 | 31 | int lt = l; // arr[l+1...lt] < v 32 | int gt = r + 1; // arr[gt...r] > v 33 | int i = l + 1; // arr[lt+1...i) == v 34 | while (i < gt) 35 | { 36 | if (arr[i] < v) 37 | { 38 | swap(arr[i], arr[lt + 1]); 39 | i++; 40 | lt++; 41 | } 42 | else if (arr[i] > v) 43 | { 44 | swap(arr[i], arr[gt - 1]); 45 | gt--; 46 | } 47 | else 48 | { // arr[i] == v 49 | i++; 50 | } 51 | } 52 | 53 | swap(arr[l], arr[lt]); 54 | 55 | __quickSort3Ways(arr, l, lt - 1); 56 | __quickSort3Ways(arr, gt, r); 57 | } 58 | 59 | template 60 | void quickSort3Ways(T arr[], int n) 61 | { 62 | 63 | srand(time(NULL)); 64 | __quickSort3Ways(arr, 0, n - 1); 65 | } 66 | 67 | #endif //INC_05_HEAPIFY_QUICKSORT3WAYS_H 68 | -------------------------------------------------------------------------------- /heap-sort/04-Heapify/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_05_HEAPIFY_SORTTESTHELPER_H 6 | #define INC_05_HEAPIFY_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 58 | copy(a, a + n, arr); 59 | return arr; 60 | } 61 | 62 | // 打印arr数组的所有内容 63 | template 64 | void printArray(T arr[], int n) 65 | { 66 | 67 | for (int i = 0; i < n; i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return; 72 | } 73 | 74 | // 判断arr数组是否有序 75 | template 76 | bool isSorted(T arr[], int n) 77 | { 78 | 79 | for (int i = 0; i < n - 1; i++) 80 | if (arr[i] > arr[i + 1]) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 87 | // 将算法的运行时间打印在控制台上 88 | template 89 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 90 | { 91 | 92 | clock_t startTime = clock(); 93 | sort(arr, n); 94 | clock_t endTime = clock(); 95 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 96 | 97 | assert(isSorted(arr, n)); 98 | 99 | return; 100 | } 101 | 102 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 103 | // 将算法的运行时间以double类型返回, 单位为秒(s) 104 | template 105 | double testSort(void (*sort)(T[], int), T arr[], int n) 106 | { 107 | 108 | clock_t startTime = clock(); 109 | sort(arr, n); 110 | clock_t endTime = clock(); 111 | 112 | assert(isSorted(arr, n)); 113 | 114 | return double(endTime - startTime) / CLOCKS_PER_SEC; 115 | } 116 | 117 | }; // namespace SortTestHelper 118 | 119 | #endif //INC_05_HEAPIFY_SORTTESTHELPER_H 120 | -------------------------------------------------------------------------------- /heap-sort/04-Heapify/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Heap.h" 4 | #include "MergeSort.h" 5 | #include "QuickSort.h" 6 | #include "QuickSort2Ways.h" 7 | #include "QuickSort3Ways.h" 8 | #include "SortTestHelper.h" 9 | 10 | using namespace std; 11 | 12 | // heapSort1, 将所有的元素依次添加到堆中, 在将所有元素从堆中依次取出来, 即完成了排序 13 | // 无论是创建堆的过程, 还是从堆中依次取出元素的过程, 时间复杂度均为O(nlogn) 14 | // 整个堆排序的整体时间复杂度为O(nlogn) 15 | template 16 | void heapSort1(T arr[], int n) 17 | { 18 | MaxHeap maxheap = MaxHeap(n); 19 | for (int i = 0; i < n; i++) 20 | maxheap.insert(arr[i]); 21 | 22 | for (int i = n - 1; i >= 0; i--) 23 | arr[i] = maxheap.extractMax(); 24 | } 25 | 26 | // heapSort2, 借助我们的heapify过程创建堆 27 | // 此时, 创建堆的过程时间复杂度为O(n), 将所有元素依次从堆中取出来, 实践复杂度为O(nlogn) 28 | // 堆排序的总体时间复杂度依然是O(nlogn), 但是比上述heapSort1性能更优, 因为创建堆的性能更优 29 | template 30 | void heapSort2(T arr[], int n) 31 | { 32 | MaxHeap maxheap = MaxHeap(arr, n); 33 | for (int i = n - 1; i >= 0; i--) 34 | arr[i] = maxheap.extractMax(); 35 | } 36 | 37 | // 比较 Merge Sort, 三种 Quick Sort 和本节介绍的两种 Heap Sort 的性能效率 38 | // 注意, 这几种排序算法都是 O(nlogn) 级别的排序算法 39 | int main() 40 | { 41 | 42 | int n = 1000000; 43 | 44 | // 测试1 一般性测试 45 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 46 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 47 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 48 | int *arr3 = SortTestHelper::copyIntArray(arr1, n); 49 | int *arr4 = SortTestHelper::copyIntArray(arr1, n); 50 | int *arr5 = SortTestHelper::copyIntArray(arr1, n); 51 | int *arr6 = SortTestHelper::copyIntArray(arr1, n); 52 | 53 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 54 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 55 | SortTestHelper::testSort("Quick Sort 2 Ways", quickSort2Ways, arr3, n); 56 | SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr4, n); 57 | SortTestHelper::testSort("Heap Sort 1", heapSort1, arr5, n); 58 | SortTestHelper::testSort("Heap Sort 2", heapSort2, arr6, n); 59 | 60 | delete[] arr1; 61 | delete[] arr2; 62 | delete[] arr3; 63 | delete[] arr4; 64 | delete[] arr5; 65 | delete[] arr6; 66 | 67 | cout << endl; 68 | 69 | // 测试2 测试近乎有序的数组 70 | int swapTimes = 100; 71 | cout << "Test for nearly ordered array, size = " << n << ", swap time = " << swapTimes << endl; 72 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 73 | arr2 = SortTestHelper::copyIntArray(arr1, n); 74 | arr3 = SortTestHelper::copyIntArray(arr1, n); 75 | arr4 = SortTestHelper::copyIntArray(arr1, n); 76 | arr5 = SortTestHelper::copyIntArray(arr1, n); 77 | arr6 = SortTestHelper::copyIntArray(arr1, n); 78 | 79 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 80 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 81 | SortTestHelper::testSort("Quick Sort 2 Ways", quickSort2Ways, arr3, n); 82 | SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr4, n); 83 | SortTestHelper::testSort("Heap Sort 1", heapSort1, arr5, n); 84 | SortTestHelper::testSort("Heap Sort 2", heapSort2, arr6, n); 85 | 86 | delete[] arr1; 87 | delete[] arr2; 88 | delete[] arr3; 89 | delete[] arr4; 90 | delete[] arr5; 91 | delete[] arr6; 92 | 93 | cout << endl; 94 | 95 | // 测试3 测试存在包含大量相同元素的数组 96 | cout << "Test for random array, size = " << n << ", random range [0,10]" << endl; 97 | arr1 = SortTestHelper::generateRandomArray(n, 0, 10); 98 | arr2 = SortTestHelper::copyIntArray(arr1, n); 99 | arr3 = SortTestHelper::copyIntArray(arr1, n); 100 | arr4 = SortTestHelper::copyIntArray(arr1, n); 101 | arr5 = SortTestHelper::copyIntArray(arr1, n); 102 | arr6 = SortTestHelper::copyIntArray(arr1, n); 103 | 104 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 105 | // 这种情况下, 普通的QuickSort退化为O(n^2)的算法, 不做测试 106 | //SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 107 | SortTestHelper::testSort("Quick Sort 2 Ways", quickSort2Ways, arr3, n); 108 | SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr4, n); 109 | SortTestHelper::testSort("Heap Sort 1", heapSort1, arr5, n); 110 | SortTestHelper::testSort("Heap Sort 2", heapSort2, arr6, n); 111 | 112 | delete[] arr1; 113 | delete[] arr2; 114 | delete[] arr3; 115 | delete[] arr4; 116 | delete[] arr5; 117 | delete[] arr6; 118 | 119 | return 0; 120 | } -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/Heap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_HEAP_H 6 | #define INC_06_HEAP_SORT_HEAP_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | class MaxHeap 15 | { 16 | 17 | private: 18 | Item *data; 19 | int count; 20 | int capacity; 21 | 22 | void shiftUp(int k) 23 | { 24 | while (k > 1 && data[k / 2] < data[k]) 25 | { 26 | swap(data[k / 2], data[k]); 27 | k /= 2; 28 | } 29 | } 30 | 31 | void shiftDown(int k) 32 | { 33 | while (2 * k <= count) 34 | { 35 | int j = 2 * k; 36 | if (j + 1 <= count && data[j + 1] > data[j]) 37 | j++; 38 | if (data[k] >= data[j]) 39 | break; 40 | swap(data[k], data[j]); 41 | k = j; 42 | } 43 | } 44 | 45 | public: 46 | // 构造函数, 构造一个空堆, 可容纳capacity个元素 47 | MaxHeap(int capacity) 48 | { 49 | data = new Item[capacity + 1]; 50 | count = 0; 51 | this->capacity = capacity; 52 | } 53 | 54 | // 构造函数, 通过一个给定数组创建一个最大堆 55 | // 该构造堆的过程, 时间复杂度为O(n) 56 | MaxHeap(Item arr[], int n) 57 | { 58 | data = new Item[n + 1]; 59 | capacity = n; 60 | 61 | for (int i = 0; i < n; i++) 62 | data[i + 1] = arr[i]; 63 | count = n; 64 | 65 | for (int i = count / 2; i >= 1; i--) 66 | shiftDown(i); 67 | } 68 | 69 | ~MaxHeap() 70 | { 71 | delete[] data; 72 | } 73 | 74 | // 返回堆中的元素个数 75 | int size() 76 | { 77 | return count; 78 | } 79 | 80 | // 返回一个布尔值, 表示堆中是否为空 81 | bool isEmpty() 82 | { 83 | return count == 0; 84 | } 85 | 86 | // 像最大堆中插入一个新的元素 item 87 | void insert(Item item) 88 | { 89 | assert(count + 1 <= capacity); 90 | data[count + 1] = item; 91 | shiftUp(count + 1); 92 | count++; 93 | } 94 | 95 | // 从最大堆中取出堆顶元素, 即堆中所存储的最大数据 96 | Item extractMax() 97 | { 98 | assert(count > 0); 99 | Item ret = data[1]; 100 | swap(data[1], data[count]); 101 | count--; 102 | shiftDown(1); 103 | return ret; 104 | } 105 | 106 | // 获取最大堆中的堆顶元素 107 | Item getMax() 108 | { 109 | assert(count > 0); 110 | return data[1]; 111 | } 112 | }; 113 | 114 | #endif //INC_06_HEAP_SORT_HEAP_H 115 | -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/HeapSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 8/16/16. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_HEAPSORT_H 6 | #define INC_06_HEAP_SORT_HEAPSORT_H 7 | 8 | #include "Heap.h" 9 | 10 | using namespace std; 11 | 12 | // heapSort1, 将所有的元素依次添加到堆中, 在将所有元素从堆中依次取出来, 即完成了排序 13 | // 无论是创建堆的过程, 还是从堆中依次取出元素的过程, 时间复杂度均为O(nlogn) 14 | // 整个堆排序的整体时间复杂度为O(nlogn) 15 | template 16 | void heapSort1(T arr[], int n) 17 | { 18 | 19 | MaxHeap maxheap = MaxHeap(n); 20 | for (int i = 0; i < n; i++) 21 | maxheap.insert(arr[i]); 22 | 23 | for (int i = n - 1; i >= 0; i--) 24 | arr[i] = maxheap.extractMax(); 25 | } 26 | 27 | // heapSort2, 借助我们的heapify过程创建堆 28 | // 此时, 创建堆的过程时间复杂度为O(n), 将所有元素依次从堆中取出来, 实践复杂度为O(nlogn) 29 | // 堆排序的总体时间复杂度依然是O(nlogn), 但是比上述heapSort1性能更优, 因为创建堆的性能更优 30 | template 31 | void heapSort2(T arr[], int n) 32 | { 33 | 34 | MaxHeap maxheap = MaxHeap(arr, n); 35 | for (int i = n - 1; i >= 0; i--) 36 | arr[i] = maxheap.extractMax(); 37 | } 38 | 39 | #endif //INC_06_HEAP_SORT_HEAPSORT_H 40 | -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/InsertionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_INSERTIONSORT_H 6 | #define INC_06_HEAP_SORT_INSERTIONSORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_06_HEAP_SORT_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 8/11/16. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_MERGESORT_H 6 | #define INC_06_HEAP_SORT_MERGESORT_H 7 | 8 | #include 9 | #include 10 | #include "InsertionSort.h" 11 | 12 | using namespace std; 13 | 14 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 15 | // 其中aux为完成merge过程所需要的辅助空间 16 | template 17 | void __merge(T arr[], T aux[], int l, int mid, int r) 18 | { 19 | 20 | // 由于aux的大小和arr一样, 所以我们也不需要处理aux索引的偏移量 21 | // 进一步节省了计算量:) 22 | for (int i = l; i <= r; i++) 23 | aux[i] = arr[i]; 24 | 25 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 26 | int i = l, j = mid + 1; 27 | for (int k = l; k <= r; k++) 28 | { 29 | if (i > mid) 30 | { // 如果左半部分元素已经全部处理完毕 31 | arr[k] = aux[j]; 32 | j++; 33 | } 34 | else if (j > r) 35 | { // 如果右半部分元素已经全部处理完毕 36 | arr[k] = aux[i]; 37 | i++; 38 | } 39 | else if (aux[i] < aux[j]) 40 | { // 左半部分所指元素 < 右半部分所指元素 41 | arr[k] = aux[i]; 42 | i++; 43 | } 44 | else 45 | { // 左半部分所指元素 >= 右半部分所指元素 46 | arr[k] = aux[j]; 47 | j++; 48 | } 49 | } 50 | } 51 | 52 | // 使用优化的归并排序算法, 对arr[l...r]的范围进行排序 53 | // 其中aux为完成merge过程所需要的辅助空间 54 | template 55 | void __mergeSort(T arr[], T aux[], int l, int r) 56 | { 57 | // 对于小规模数组, 使用插入排序 58 | if (r - l <= 15) 59 | { 60 | insertionSort(arr, l, r); 61 | return; 62 | } 63 | int mid = (l + r) / 2; 64 | __mergeSort(arr, aux, l, mid); 65 | __mergeSort(arr, aux, mid + 1, r); 66 | 67 | // 对于arr[mid] <= arr[mid+1]的情况,不进行merge 68 | // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失 69 | if (arr[mid] > arr[mid + 1]) 70 | __merge(arr, aux, l, mid, r); 71 | } 72 | 73 | template 74 | void mergeSort(T arr[], int n) 75 | { 76 | 77 | // 在 mergeSort中, 我们一次性申请aux空间, 78 | // 并将这个辅助空间以参数形式传递给完成归并排序的各个子函数 79 | T *aux = new T[n]; 80 | __mergeSort(arr, aux, 0, n - 1); 81 | delete[] aux; // 使用C++, new出来的空间不要忘记释放掉:) 82 | } 83 | 84 | #endif //INC_06_HEAP_SORT_MERGESORT_H 85 | -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/QuickSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 8/11/16. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_QUICKSORT_H 6 | #define INC_06_HEAP_SORT_QUICKSORT_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include "InsertionSort.h" 12 | 13 | using namespace std; 14 | 15 | // 对arr[l...r]部分进行partition操作 16 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 17 | template 18 | int _partition(T arr[], int l, int r) 19 | { 20 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 21 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 22 | T v = arr[l]; 23 | int j = l; 24 | for (int i = l + 1; i <= r; i++) 25 | if (arr[i] < v) 26 | { 27 | j++; 28 | swap(arr[j], arr[i]); 29 | } 30 | swap(arr[l], arr[j]); 31 | return j; 32 | } 33 | 34 | // 对arr[l...r]部分进行快速排序 35 | template 36 | void _quickSort(T arr[], int l, int r) 37 | { 38 | // 对于小规模数组, 使用插入排序进行优化 39 | if (r - l <= 15) 40 | { 41 | insertionSort(arr, l, r); 42 | return; 43 | } 44 | int p = _partition(arr, l, r); 45 | _quickSort(arr, l, p - 1); 46 | _quickSort(arr, p + 1, r); 47 | } 48 | 49 | template 50 | void quickSort(T arr[], int n) 51 | { 52 | srand(time(NULL)); 53 | _quickSort(arr, 0, n - 1); 54 | } 55 | 56 | #endif //INC_06_HEAP_SORT_QUICKSORT_H 57 | -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/QuickSort2Ways.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 4/24/17. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_QUICKSORT2WAYS_H 6 | #define INC_06_HEAP_SORT_QUICKSORT2WAYS_H 7 | 8 | #include 9 | #include 10 | #include "InsertionSort.h" 11 | 12 | using namespace std; 13 | 14 | // 双路快速排序的partition 15 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 16 | template 17 | int _partition2(T arr[], int l, int r) 18 | { 19 | 20 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 21 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 22 | T v = arr[l]; 23 | 24 | // arr[l+1...i) <= v; arr(j...r] >= v 25 | int i = l + 1, j = r; 26 | while (true) 27 | { 28 | // 注意这里的边界, arr[i] < v, 不能是arr[i] <= v 29 | // 思考一下为什么? 30 | while (i <= r && arr[i] < v) 31 | i++; 32 | 33 | // 注意这里的边界, arr[j] > v, 不能是arr[j] >= v 34 | // 思考一下为什么? 35 | while (j >= l + 1 && arr[j] > v) 36 | j--; 37 | 38 | // 对于上面的两个边界的设定, 有的同学在课程的问答区有很好的回答:) 39 | // 大家可以参考: http://coding.imooc.com/learn/questiondetail/4920.html 40 | 41 | if (i > j) 42 | break; 43 | 44 | swap(arr[i], arr[j]); 45 | i++; 46 | j--; 47 | } 48 | 49 | swap(arr[l], arr[j]); 50 | 51 | return j; 52 | } 53 | 54 | // 对arr[l...r]部分进行快速排序 55 | template 56 | void _quickSort2Ways(T arr[], int l, int r) 57 | { 58 | 59 | // 对于小规模数组, 使用插入排序进行优化 60 | if (r - l <= 15) 61 | { 62 | insertionSort(arr, l, r); 63 | return; 64 | } 65 | 66 | // 调用双路快速排序的partition 67 | int p = _partition2(arr, l, r); 68 | _quickSort2Ways(arr, l, p - 1); 69 | _quickSort2Ways(arr, p + 1, r); 70 | } 71 | 72 | template 73 | void quickSort2Ways(T arr[], int n) 74 | { 75 | 76 | srand(time(NULL)); 77 | _quickSort2Ways(arr, 0, n - 1); 78 | } 79 | 80 | #endif //INC_06_HEAP_SORT_QUICKSORT2WAYS_H 81 | -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/QuickSort3Ways.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 4/24/17. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_QUICKSORT3WAYS_H 6 | #define INC_06_HEAP_SORT_QUICKSORT3WAYS_H 7 | 8 | #include 9 | #include 10 | #include "InsertionSort.h" 11 | 12 | using namespace std; 13 | 14 | // 递归的三路快速排序算法 15 | template 16 | void __quickSort3Ways(T arr[], int l, int r) 17 | { 18 | // 对于小规模数组, 使用插入排序进行优化 19 | if (r - l <= 15) 20 | { 21 | insertionSort(arr, l, r); 22 | return; 23 | } 24 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 25 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 26 | 27 | T v = arr[l]; 28 | 29 | int lt = l; // arr[l+1...lt] < v 30 | int gt = r + 1; // arr[gt...r] > v 31 | int i = l + 1; // arr[lt+1...i) == v 32 | while (i < gt) 33 | { 34 | if (arr[i] < v) 35 | { 36 | swap(arr[i], arr[lt + 1]); 37 | i++; 38 | lt++; 39 | } 40 | else if (arr[i] > v) 41 | { 42 | swap(arr[i], arr[gt - 1]); 43 | gt--; 44 | } 45 | else 46 | { // arr[i] == v 47 | i++; 48 | } 49 | } 50 | swap(arr[l], arr[lt]); 51 | __quickSort3Ways(arr, l, lt - 1); 52 | __quickSort3Ways(arr, gt, r); 53 | } 54 | 55 | template 56 | void quickSort3Ways(T arr[], int n) 57 | { 58 | 59 | srand(time(NULL)); 60 | __quickSort3Ways(arr, 0, n - 1); 61 | } 62 | 63 | #endif //INC_06_HEAP_SORT_QUICKSORT3WAYS_H 64 | -------------------------------------------------------------------------------- /heap-sort/05-Heap-Sort/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 8/7/16. 3 | // 4 | 5 | #ifndef INC_06_HEAP_SORT_SORTTESTHELPER_H 6 | #define INC_06_HEAP_SORT_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace SortTestHelper 18 | { 19 | 20 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 21 | int *generateRandomArray(int n, int range_l, int range_r) 22 | { 23 | 24 | int *arr = new int[n]; 25 | 26 | srand(time(NULL)); 27 | for (int i = 0; i < n; i++) 28 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 29 | return arr; 30 | } 31 | 32 | // 生成一个近乎有序的数组 33 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 34 | // swapTimes定义了数组的无序程度 35 | int *generateNearlyOrderedArray(int n, int swapTimes) 36 | { 37 | 38 | int *arr = new int[n]; 39 | for (int i = 0; i < n; i++) 40 | arr[i] = i; 41 | 42 | srand(time(NULL)); 43 | for (int i = 0; i < swapTimes; i++) 44 | { 45 | int posx = rand() % n; 46 | int posy = rand() % n; 47 | swap(arr[posx], arr[posy]); 48 | } 49 | 50 | return arr; 51 | } 52 | 53 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 54 | int *copyIntArray(int a[], int n) 55 | { 56 | 57 | int *arr = new int[n]; 58 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 59 | copy(a, a + n, arr); 60 | return arr; 61 | } 62 | 63 | // 打印arr数组的所有内容 64 | template 65 | void printArray(T arr[], int n) 66 | { 67 | 68 | for (int i = 0; i < n; i++) 69 | cout << arr[i] << " "; 70 | cout << endl; 71 | 72 | return; 73 | } 74 | 75 | // 判断arr数组是否有序 76 | template 77 | bool isSorted(T arr[], int n) 78 | { 79 | 80 | for (int i = 0; i < n - 1; i++) 81 | if (arr[i] > arr[i + 1]) 82 | return false; 83 | 84 | return true; 85 | } 86 | 87 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 88 | // 将算法的运行时间打印在控制台上 89 | template 90 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 91 | { 92 | 93 | clock_t startTime = clock(); 94 | sort(arr, n); 95 | clock_t endTime = clock(); 96 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 97 | 98 | assert(isSorted(arr, n)); 99 | 100 | return; 101 | } 102 | 103 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 104 | // 将算法的运行时间以double类型返回, 单位为秒(s) 105 | template 106 | double testSort(void (*sort)(T[], int), T arr[], int n) 107 | { 108 | 109 | clock_t startTime = clock(); 110 | sort(arr, n); 111 | clock_t endTime = clock(); 112 | 113 | assert(isSorted(arr, n)); 114 | 115 | return double(endTime - startTime) / CLOCKS_PER_SEC; 116 | } 117 | 118 | }; // namespace SortTestHelper 119 | 120 | #endif //INC_06_HEAP_SORT_SORTTESTHELPER_H 121 | -------------------------------------------------------------------------------- /heap-sort/06-Index-Heap/SortTtestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_08_INDEX_HEAP_SORTTESTHELPER_H 6 | #define INC_08_INDEX_HEAP_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace SortTestHelper 18 | { 19 | 20 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 21 | int *generateRandomArray(int n, int range_l, int range_r) 22 | { 23 | 24 | int *arr = new int[n]; 25 | 26 | srand(time(NULL)); 27 | for (int i = 0; i < n; i++) 28 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 29 | return arr; 30 | } 31 | 32 | // 生成一个近乎有序的数组 33 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 34 | // swapTimes定义了数组的无序程度 35 | int *generateNearlyOrderedArray(int n, int swapTimes) 36 | { 37 | 38 | int *arr = new int[n]; 39 | for (int i = 0; i < n; i++) 40 | arr[i] = i; 41 | 42 | srand(time(NULL)); 43 | for (int i = 0; i < swapTimes; i++) 44 | { 45 | int posx = rand() % n; 46 | int posy = rand() % n; 47 | swap(arr[posx], arr[posy]); 48 | } 49 | 50 | return arr; 51 | } 52 | 53 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 54 | int *copyIntArray(int a[], int n) 55 | { 56 | 57 | int *arr = new int[n]; 58 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 59 | copy(a, a + n, arr); 60 | return arr; 61 | } 62 | 63 | // 打印arr数组的所有内容 64 | template 65 | void printArray(T arr[], int n) 66 | { 67 | 68 | for (int i = 0; i < n; i++) 69 | cout << arr[i] << " "; 70 | cout << endl; 71 | 72 | return; 73 | } 74 | 75 | // 判断arr数组是否有序 76 | template 77 | bool isSorted(T arr[], int n) 78 | { 79 | 80 | for (int i = 0; i < n - 1; i++) 81 | if (arr[i] > arr[i + 1]) 82 | return false; 83 | 84 | return true; 85 | } 86 | 87 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 88 | // 将算法的运行时间打印在控制台上 89 | template 90 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 91 | { 92 | 93 | clock_t startTime = clock(); 94 | sort(arr, n); 95 | clock_t endTime = clock(); 96 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 97 | 98 | assert(isSorted(arr, n)); 99 | 100 | return; 101 | } 102 | 103 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 104 | // 将算法的运行时间以double类型返回, 单位为秒(s) 105 | template 106 | double testSort(void (*sort)(T[], int), T arr[], int n) 107 | { 108 | 109 | clock_t startTime = clock(); 110 | sort(arr, n); 111 | clock_t endTime = clock(); 112 | 113 | assert(isSorted(arr, n)); 114 | 115 | return double(endTime - startTime) / CLOCKS_PER_SEC; 116 | } 117 | 118 | }; // namespace SortTestHelper 119 | 120 | #endif //INC_08_INDEX_HEAP_SORTTESTHELPER_H 121 | -------------------------------------------------------------------------------- /heap-sort/07-index-Heap-Advanced/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_08_INDEX_HEAP_SORTTESTHELPER_H 6 | #define INC_08_INDEX_HEAP_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace SortTestHelper 18 | { 19 | 20 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 21 | int *generateRandomArray(int n, int range_l, int range_r) 22 | { 23 | 24 | int *arr = new int[n]; 25 | 26 | srand(time(NULL)); 27 | for (int i = 0; i < n; i++) 28 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 29 | return arr; 30 | } 31 | 32 | // 生成一个近乎有序的数组 33 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 34 | // swapTimes定义了数组的无序程度 35 | int *generateNearlyOrderedArray(int n, int swapTimes) 36 | { 37 | 38 | int *arr = new int[n]; 39 | for (int i = 0; i < n; i++) 40 | arr[i] = i; 41 | 42 | srand(time(NULL)); 43 | for (int i = 0; i < swapTimes; i++) 44 | { 45 | int posx = rand() % n; 46 | int posy = rand() % n; 47 | swap(arr[posx], arr[posy]); 48 | } 49 | 50 | return arr; 51 | } 52 | 53 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 54 | int *copyIntArray(int a[], int n) 55 | { 56 | 57 | int *arr = new int[n]; 58 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 59 | copy(a, a + n, arr); 60 | return arr; 61 | } 62 | 63 | // 打印arr数组的所有内容 64 | template 65 | void printArray(T arr[], int n) 66 | { 67 | 68 | for (int i = 0; i < n; i++) 69 | cout << arr[i] << " "; 70 | cout << endl; 71 | 72 | return; 73 | } 74 | 75 | // 判断arr数组是否有序 76 | template 77 | bool isSorted(T arr[], int n) 78 | { 79 | 80 | for (int i = 0; i < n - 1; i++) 81 | if (arr[i] > arr[i + 1]) 82 | return false; 83 | 84 | return true; 85 | } 86 | 87 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 88 | // 将算法的运行时间打印在控制台上 89 | template 90 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 91 | { 92 | 93 | clock_t startTime = clock(); 94 | sort(arr, n); 95 | clock_t endTime = clock(); 96 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 97 | 98 | assert(isSorted(arr, n)); 99 | 100 | return; 101 | } 102 | 103 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 104 | // 将算法的运行时间以double类型返回, 单位为秒(s) 105 | template 106 | double testSort(void (*sort)(T[], int), T arr[], int n) 107 | { 108 | 109 | clock_t startTime = clock(); 110 | sort(arr, n); 111 | clock_t endTime = clock(); 112 | 113 | assert(isSorted(arr, n)); 114 | 115 | return double(endTime - startTime) / CLOCKS_PER_SEC; 116 | } 117 | 118 | }; // namespace SortTestHelper 119 | 120 | #endif //INC_08_INDEX_HEAP_SORTTESTHELPER_H 121 | -------------------------------------------------------------------------------- /heap-sort/08-HeapSort-All/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | 9 | class MaxHeap{ 10 | private: 11 | Item *data; 12 | int count; 13 | int capacity; 14 | void shiftUp(int k){ 15 | while(k > 1 && data[k/2] < data[k]){ 16 | swap(data[k/2], data[k]); 17 | k/=2; 18 | } 19 | } 20 | public: 21 | MaxHeap(int capicity){ 22 | data = new Item[capacity + 1]; 23 | count = 0; 24 | this->capacity = capacity; 25 | } 26 | ~MaxHeap(){ 27 | delete[] data; 28 | } 29 | int size(){ 30 | return count; 31 | } 32 | void isEmpty(){ 33 | return count == 0; 34 | } 35 | int insert(Item item){ 36 | assert(count + 1 <= capacity) 37 | data[count+1] = item; 38 | count++; 39 | shiftUp(count); 40 | } 41 | }; 42 | 43 | int main(){ 44 | return 0; 45 | } -------------------------------------------------------------------------------- /heap-sort/extra-Heap-Sort-TopK/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | void shiftDown(int *arr, int parent, int k) { 10 | int child = 2 * parent + 1; 11 | while (child < k) { 12 | if (child + 1 < k && arr[child] > arr[child + 1]) { 13 | child++; 14 | } 15 | if (arr[parent] > arr[child]) { 16 | swap(arr[parent], arr[child]); 17 | parent = child; 18 | child = 2 * parent + 1; 19 | } else { 20 | break; 21 | } 22 | } 23 | } 24 | 25 | 26 | int *HeapSet(int *arr, int n, int k) { 27 | assert(arr); 28 | assert(k > 0); 29 | int *ret = new int[k]; 30 | for (int i = 0; i < k; i++) { 31 | ret[i] = arr[i]; 32 | } 33 | for (int i = (k - 2) / 2; i >= 0; i--) { 34 | shiftDown(ret, i, k); 35 | } 36 | for(int i = k;i self._data[j]: 29 | j += 1 # switch to the right point 30 | if self._data[k] >= self._data[j]: 31 | break 32 | self._data[k], self._data[j] = self._data[j], self._data[k] 33 | k = j 34 | 35 | def _shift_up(self, k): 36 | while k > 1 and self._data[k // 2] < self._data[k]: 37 | self._data[k // 2], self._data[k] = self._data[k], self._data[k // 2] 38 | k //= 2 39 | 40 | def extract_max(self): 41 | assert self._count > 0, 'can not extract max from empty heap' 42 | ret = self._data[1] 43 | self._data[1], self._data[self._count] = self._data[self._count], self._data[1] 44 | self._count -= 1 45 | self._shift_down(1) 46 | return ret 47 | 48 | def size(self): 49 | return self._count 50 | 51 | def is_empty(self): 52 | return self._count == 0 53 | 54 | def insert(self, val): 55 | assert (self._count > 0) 56 | self._count += 1 57 | self._data.append(val) 58 | self._shift_up(self._count) 59 | 60 | 61 | def main(): 62 | data = [1] 63 | maxheap = MaxHeap(data) 64 | for i in range(10): 65 | maxheap.insert(random.randint(0, 100)) 66 | while not maxheap.is_empty(): 67 | print(maxheap.extract_max()) 68 | 69 | 70 | if __name__ == "__main__": 71 | main() 72 | # print(int(7 / 2)) 73 | -------------------------------------------------------------------------------- /heap-sort/extra-heap-sort-python/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : 3zz 3 | # @Time : 2019-08-17 23:25 4 | # @File : __init__.py 5 | -------------------------------------------------------------------------------- /heap-sort/extra-heap-sort-python/main.py: -------------------------------------------------------------------------------- 1 | import random -------------------------------------------------------------------------------- /minimum-span-trees/01-weighted-graph/DenseGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Edge.h" 5 | 6 | using namespace std; 7 | // 稠密图 - 邻接矩阵 8 | template 9 | 10 | class DenseGraph 11 | { 12 | private: 13 | int n, m; // 节点数和边数 14 | bool directed; // 是否为有向图 15 | vector *> > g; // 图的具体数据 16 | 17 | public: 18 | // 构造函数 19 | DenseGraph(int n, bool directed) 20 | { 21 | assert(n >= 0); 22 | this->n = n; 23 | this->m = 0; 24 | this->directed = directed; 25 | for (int i = 0; i < n; i++) 26 | { 27 | g.push_back(vector *>(n, NULL)); 28 | } 29 | } 30 | ~DenseGraph() { 31 | for(int i = 0; i < n; i++) 32 | { 33 | for(int j = 0; j < n; j++) 34 | { 35 | if(g[i][j] != NULL) 36 | delete g[i][j]; 37 | } 38 | } 39 | } 40 | 41 | int V() { return n; } 42 | int E() { return m; } 43 | 44 | void addEdge(int v, int w, Weight weight) 45 | { 46 | assert(v >= 0 && v < n); 47 | assert(w >= 0 && w < n); 48 | if (hasEdge(v, w)) 49 | { 50 | delete g[v][w]; 51 | if (!directed) 52 | delete g[w][v]; 53 | m--; 54 | } 55 | g[v][w] = new Edge(v, w, weight); 56 | if (!directed) 57 | g[w][v] = new Edge(w, v, weight); 58 | m++; 59 | } 60 | 61 | bool hasEdge(int v, int w) 62 | { 63 | assert(v >= 0 && v < n); 64 | assert(w >= 0 && w < n); 65 | return g[v][w] != NULL; 66 | } 67 | // 打印邻接矩阵 68 | void show() 69 | { 70 | for (int i = 0; i < n; i++) 71 | for (int j = 0; j < n; j++) 72 | if(g[i][j]) 73 | cout << g[i][j]->wt() << "\t"; 74 | else 75 | cout<<"NULL\t"; 76 | cout << endl; 77 | } 78 | 79 | class adjIterator 80 | { 81 | private: 82 | DenseGraph &G; 83 | int v; 84 | int index; 85 | 86 | public: 87 | adjIterator(DenseGraph &graph, int v) : G(graph) 88 | { 89 | assert(v >= 0 && v < G.n); 90 | this->v = v; 91 | this->index = -1; 92 | } 93 | ~adjIterator() {} 94 | // 返回图G中与顶点v相连接的第一个顶点 95 | Edge* begin() 96 | { 97 | // 索引从-1开始, 因为每次遍历都需要调用一次next() 98 | index = -1; 99 | return next(); 100 | } 101 | Edge* next() 102 | { 103 | for (index += 1; index < G.V(); index++) 104 | if (G.g[v][index]) 105 | return G.g[v][index]; 106 | return NULL; 107 | } 108 | bool end() 109 | { 110 | return index >= G.V(); 111 | } 112 | }; 113 | }; -------------------------------------------------------------------------------- /minimum-span-trees/01-weighted-graph/Edge.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz on 9/23/16. 3 | // 4 | 5 | #ifndef INC_01_WEIGHTED_GRAPH_EDGE_H 6 | #define INC_01_WEIGHTED_GRAPH_EDGE_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | // 边 14 | template 15 | class Edge{ 16 | private: 17 | int a,b; // 边的两个端点 18 | Weight weight; // 边的权值 19 | 20 | public: 21 | // 构造函数 22 | Edge(int a, int b, Weight weight){ 23 | this->a = a; 24 | this->b = b; 25 | this->weight = weight; 26 | } 27 | // 空的构造函数, 所有的成员变量都取默认值 28 | Edge(){} 29 | 30 | ~Edge(){} 31 | 32 | int v(){ return a;} // 返回第一个顶点 33 | int w(){ return b;} // 返回第二个顶点 34 | Weight wt(){ return weight;} // 返回权值 35 | 36 | // 给定一个顶点, 返回另一个顶点 37 | int other(int x){ 38 | assert( x == a || x == b ); 39 | return x == a ? b : a; 40 | } 41 | 42 | // 输出边的信息 43 | friend ostream& operator<<(ostream &os, const Edge &e){ 44 | os<& e){ 50 | return weight < e.wt(); 51 | } 52 | bool operator<=(Edge& e){ 53 | return weight <= e.wt(); 54 | } 55 | bool operator>(Edge& e){ 56 | return weight > e.wt(); 57 | } 58 | bool operator>=(Edge& e){ 59 | return weight >= e.wt(); 60 | } 61 | bool operator==(Edge& e){ 62 | return weight == e.wt(); 63 | } 64 | }; 65 | 66 | #endif //INC_01_WEIGHTED_GRAPH_EDGE_H 67 | -------------------------------------------------------------------------------- /minimum-span-trees/01-weighted-graph/ReadGraph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | template 10 | 11 | class ReadGraph{ 12 | 13 | public: 14 | ReadGraph(Graph &graph, const string &filename){ 15 | ifstream file(filename); 16 | string line; 17 | int V,E; 18 | 19 | assert( file.is_open()); 20 | assert(getline(file, line)); 21 | 22 | stringstream ss(line); 23 | ss>>V>>E; 24 | 25 | assert(V == graph.V()); 26 | for(int i = 0; i < E; i++) 27 | { 28 | assert(getline(file,line)); 29 | stringstream ss(line); 30 | 31 | int a,b; 32 | Weight w; 33 | ss>>a>>b>>w; 34 | assert(a >= 0 && a< V); 35 | assert(b >= 0 && b < V); 36 | graph.addEdge(a,b,w); 37 | } 38 | } 39 | }; -------------------------------------------------------------------------------- /minimum-span-trees/01-weighted-graph/SparseGraph.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz on 9/23/16. 3 | // 4 | 5 | #ifndef INC_01_WEIGHTED_GRAPH_SPARSEGRAPH_H 6 | #define INC_01_WEIGHTED_GRAPH_SPARSEGRAPH_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include "Edge.h" 12 | 13 | using namespace std; 14 | 15 | // 稀疏图 - 邻接表 16 | template 17 | class SparseGraph 18 | { 19 | 20 | private: 21 | int n, m; // 节点数和边数 22 | bool directed; // 是否为有向图 23 | vector *> > g; // 图的具体数据 24 | 25 | public: 26 | // 构造函数 27 | SparseGraph(int n, bool directed) 28 | { 29 | assert(n >= 0); 30 | this->n = n; 31 | this->m = 0; // 初始化没有任何边 32 | this->directed = directed; 33 | // g初始化为n个空的vector, 表示每一个g[i]都为空, 即没有任和边 34 | g = vector *> >(n, vector *>()); 35 | } 36 | 37 | // 析构函数 38 | ~SparseGraph() 39 | { 40 | for (int i = 0; i < n; i++) 41 | for (int j = 0; j < g[i].size(); j++) 42 | delete g[i][j]; 43 | } 44 | 45 | int V() { return n; } // 返回节点个数 46 | int E() { return m; } // 返回边的个数 47 | 48 | // 向图中添加一个边, 权值为weight 49 | void addEdge(int v, int w, Weight weight) 50 | { 51 | assert(v >= 0 && v < n); 52 | assert(w >= 0 && w < n); 53 | 54 | // 注意, 由于在邻接表的情况, 查找是否有重边需要遍历整个链表 55 | // 我们的程序允许重边的出现 56 | 57 | g[v].push_back(new Edge(v, w, weight)); 58 | if (v != w && !directed) 59 | g[w].push_back(new Edge(w, v, weight)); 60 | m++; 61 | } 62 | 63 | // 验证图中是否有从v到w的边 64 | bool hasEdge(int v, int w) 65 | { 66 | assert(v >= 0 && v < n); 67 | assert(w >= 0 && w < n); 68 | for (int i = 0; i < g[v].size(); i++) 69 | if (g[v][i]->other(v) == w) 70 | return true; 71 | return false; 72 | } 73 | 74 | // 显示图的信息 75 | void show() 76 | { 77 | 78 | for (int i = 0; i < n; i++) 79 | { 80 | cout << "vertex " << i << ":\t"; 81 | for (int j = 0; j < g[i].size(); j++) 82 | cout << "( to:" << g[i][j]->w() << ",wt:" << g[i][j]->wt() << " )\t"; 83 | cout << endl; 84 | } 85 | } 86 | 87 | // 邻边迭代器, 传入一个图和一个顶点, 88 | // 迭代在这个图中和这个顶点向连的所有边 89 | class adjIterator 90 | { 91 | private: 92 | SparseGraph &G; // 图G的引用 93 | int v; 94 | int index; 95 | 96 | public: 97 | // 构造函数 98 | adjIterator(SparseGraph &graph, int v) : G(graph) 99 | { 100 | this->v = v; 101 | this->index = 0; 102 | } 103 | 104 | ~adjIterator() {} 105 | 106 | // 返回图G中与顶点v相连接的第一个边 107 | Edge *begin() 108 | { 109 | index = 0; 110 | if (G.g[v].size()) 111 | return G.g[v][index]; 112 | // 若没有顶点和v相连接, 则返回NULL 113 | return NULL; 114 | } 115 | 116 | // 返回图G中与顶点v相连接的下一个边 117 | Edge *next() 118 | { 119 | index += 1; 120 | if (index < G.g[v].size()) 121 | return G.g[v][index]; 122 | return NULL; 123 | } 124 | 125 | // 查看是否已经迭代完了图G中与顶点v相连接的所有顶点 126 | bool end() 127 | { 128 | return index >= G.g[v].size(); 129 | } 130 | }; 131 | }; 132 | 133 | #endif //INC_01_WEIGHTED_GRAPH_SPARSEGRAPH_H 134 | -------------------------------------------------------------------------------- /minimum-span-trees/01-weighted-graph/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "DenseGraph.h" 4 | #include "ReadGraph.h" 5 | #include "SparseGraph.h" 6 | 7 | using namespace std; 8 | 9 | int main(){ 10 | string filename = "testG1.txt"; 11 | int V = 8; 12 | cout< g1 = DenseGraph (V, false); 16 | ReadGraph, double> readGraph1(g1, filename); 17 | g1.show(); 18 | cout< g2 = SparseGraph (V,false); 22 | ReadGraph, double> readGraph2(g2,filename); 23 | g2.show(); 24 | cout< 9 | #include 10 | 11 | using namespace std; 12 | 13 | 14 | template 15 | void insertionSort(T arr[], int n){ 16 | 17 | for( int i = 1 ; i < n ; i ++ ) { 18 | 19 | T e = arr[i]; 20 | int j; 21 | for (j = i; j > 0 && arr[j-1] > e; j--) 22 | arr[j] = arr[j-1]; 23 | arr[j] = e; 24 | } 25 | 26 | return; 27 | } 28 | 29 | #endif //OPTIONAL_02_SHELL_SORT_INSERTIONSORT_H 30 | -------------------------------------------------------------------------------- /sort-advanced/01-merge-sort/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 7/15/16. 3 | // 4 | 5 | #ifndef OPTIONAL_02_SHELL_SORT_SORTTESTHELPER_H 6 | #define OPTIONAL_02_SHELL_SORT_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | 17 | namespace SortTestHelper { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) { 21 | 22 | int *arr = new int[n]; 23 | 24 | srand(time(NULL)); 25 | for (int i = 0; i < n; i++) 26 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 27 | return arr; 28 | } 29 | 30 | // 生成一个近乎有序的数组 31 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 32 | // swapTimes定义了数组的无序程度 33 | int *generateNearlyOrderedArray(int n, int swapTimes){ 34 | 35 | int *arr = new int[n]; 36 | for(int i = 0 ; i < n ; i ++ ) 37 | arr[i] = i; 38 | 39 | srand(time(NULL)); 40 | for( int i = 0 ; i < swapTimes ; i ++ ){ 41 | int posx = rand()%n; 42 | int posy = rand()%n; 43 | swap( arr[posx] , arr[posy] ); 44 | } 45 | 46 | return arr; 47 | } 48 | 49 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 50 | int *copyIntArray(int a[], int n){ 51 | 52 | int *arr = new int[n]; 53 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 54 | copy(a, a+n, arr); 55 | return arr; 56 | } 57 | 58 | // 打印arr数组的所有内容 59 | template 60 | void printArray(T arr[], int n) { 61 | 62 | for (int i = 0; i < n; i++) 63 | cout << arr[i] << " "; 64 | cout << endl; 65 | 66 | return; 67 | } 68 | 69 | // 判断arr数组是否有序 70 | template 71 | bool isSorted(T arr[], int n) { 72 | for (int i = 0; i < n - 1; i++) 73 | if (arr[i] > arr[i + 1]) 74 | return false; 75 | return true; 76 | } 77 | 78 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 79 | template 80 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) { 81 | 82 | clock_t startTime = clock(); 83 | sort(arr, n); 84 | clock_t endTime = clock(); 85 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"< 5 | #include "SortTestHelper.h" 6 | #include "InsertionSort.h" 7 | 8 | using namespace std; 9 | 10 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 11 | template 12 | void __merge(T arr[], int l, int mid, int r) 13 | { 14 | // 定义一个额外空间用来存储数据 15 | T aux[r - l + 1]; 16 | // T *aux = new T[r - l + 1]; 17 | for (int i = l; i <= r; i++) 18 | { 19 | aux[i - l] = arr[i]; 20 | } 21 | // 将i,j分别指向两个数组开头的位置 22 | int i = l, j = mid + 1; 23 | for (int k = l; k <= r; k++) 24 | { 25 | // 如果此时第一个数组全部取完了 i已经大于mid说明后面一个数组[mid+1...r]还没取完 取它的元素即可 26 | if (i > mid) 27 | { 28 | arr[k] = aux[j - l]; 29 | j++; 30 | } // // 如果此时第二个数组全部取完了 j已经大于r 说明第一个数组[l...mid]还没取完 取它的元素即可 31 | else if (j > r) 32 | { 33 | arr[k] = aux[i - l]; 34 | i++; 35 | } // 后面两个是正常判断谁小就取谁的 36 | else if (aux[i - l] < aux[j - l]) 37 | { 38 | arr[k] = aux[i - l]; 39 | i++; 40 | } 41 | else 42 | { 43 | arr[k] = aux[j - l]; 44 | j++; 45 | } 46 | } 47 | // delete[] aux; 48 | } 49 | 50 | template 51 | void __mergeSort(T arr[], int l, int r) 52 | { 53 | if (l >= r) 54 | return; 55 | int mid = l + (r - l) / 2; 56 | __mergeSort(arr, l, mid); 57 | __mergeSort(arr, mid + 1, r); 58 | __merge(arr, l, mid, r); 59 | } 60 | 61 | template 62 | void mergeSort(T arr[], int n) 63 | { 64 | __mergeSort(arr, 0, n - 1); 65 | } 66 | 67 | // 比较InsertionSort和MergeSort两种排序算法的性能效率 68 | // 整体而言, MergeSort的性能最优, 对于近乎有序的数组的特殊情况, 见测试2的详细注释 69 | int main() 70 | { 71 | 72 | // Merge Sort是我们学习的第一个O(nlogn)复杂度的算法 73 | // 可以在1秒之内轻松处理100万数量级的数据 74 | // 注意:不要轻易尝试使用SelectionSort, InsertionSort或者BubbleSort处理100万级的数据 75 | // 否则,你就见识了O(n^2)的算法和O(nlogn)算法的本质差异:) 76 | int n = 50000; 77 | 78 | // 测试1 一般性测试 79 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 80 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 81 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 82 | 83 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr1, n); 84 | SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n); 85 | 86 | delete[] arr1; 87 | delete[] arr2; 88 | 89 | cout << endl; 90 | 91 | // 测试2 测试近乎有序的数组 92 | // 对于近乎有序的数组, 数组越有序, InsertionSort的时间性能越趋近于O(n) 93 | // 所以可以尝试, 当swapTimes比较大时, MergeSort更快 94 | // 但是当swapTimes小到一定程度, InsertionSort变得比MergeSort快 95 | int swapTimes = 10; 96 | assert(swapTimes >= 0); 97 | 98 | cout << "Test for nearly ordered array, size = " << n << ", swap time = " << swapTimes << endl; 99 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 100 | arr2 = SortTestHelper::copyIntArray(arr1, n); 101 | 102 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr1, n); 103 | SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n); 104 | 105 | delete[] arr1; 106 | delete[] arr2; 107 | 108 | return 0; 109 | } -------------------------------------------------------------------------------- /sort-advanced/02-merge-sort-advanced/InsertionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /sort-advanced/02-merge-sort-advanced/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 13 | template 14 | void __merge(T arr[], int l, int mid, int r) 15 | { 16 | 17 | //* VS不支持动态长度数组, 即不能使用 T aux[r-l+1]的方式申请aux的空间 18 | //* 使用VS的同学, 请使用new的方式申请aux空间 19 | //* 使用new申请空间, 不要忘了在__merge函数的最后, delete掉申请的空间:) 20 | T aux[r - l + 1]; 21 | //T *aux = new T[r-l+1]; 22 | 23 | for (int i = l; i <= r; i++) 24 | aux[i - l] = arr[i]; 25 | 26 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 27 | int i = l, j = mid + 1; 28 | for (int k = l; k <= r; k++) 29 | { 30 | 31 | if (i > mid) 32 | { // 如果左半部分元素已经全部处理完毕 33 | arr[k] = aux[j - l]; 34 | j++; 35 | } 36 | else if (j > r) 37 | { // 如果右半部分元素已经全部处理完毕 38 | arr[k] = aux[i - l]; 39 | i++; 40 | } 41 | else if (aux[i - l] < aux[j - l]) 42 | { // 左半部分所指元素 < 右半部分所指元素 43 | arr[k] = aux[i - l]; 44 | i++; 45 | } 46 | else 47 | { // 左半部分所指元素 >= 右半部分所指元素 48 | arr[k] = aux[j - l]; 49 | j++; 50 | } 51 | } 52 | 53 | //delete[] aux; 54 | } 55 | 56 | // 递归使用归并排序,对arr[l...r]的范围进行排序 57 | template 58 | void __mergeSort(T arr[], int l, int r) 59 | { 60 | 61 | if (l >= r) 62 | return; 63 | 64 | int mid = (l + r) / 2; 65 | __mergeSort(arr, l, mid); 66 | __mergeSort(arr, mid + 1, r); 67 | __merge(arr, l, mid, r); 68 | } 69 | 70 | template 71 | void mergeSort(T arr[], int n) 72 | { 73 | 74 | __mergeSort(arr, 0, n - 1); 75 | } 76 | 77 | #endif //INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 78 | -------------------------------------------------------------------------------- /sort-advanced/02-merge-sort-advanced/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 6 | #define INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 58 | copy(a, a + n, arr); 59 | return arr; 60 | } 61 | 62 | // 打印arr数组的所有内容 63 | template 64 | void printArray(T arr[], int n) 65 | { 66 | 67 | for (int i = 0; i < n; i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return; 72 | } 73 | 74 | // 判断arr数组是否有序 75 | template 76 | bool isSorted(T arr[], int n) 77 | { 78 | 79 | for (int i = 0; i < n - 1; i++) 80 | if (arr[i] > arr[i + 1]) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 87 | template 88 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 89 | { 90 | 91 | clock_t startTime = clock(); 92 | sort(arr, n); 93 | clock_t endTime = clock(); 94 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 95 | 96 | assert(isSorted(arr, n)); 97 | 98 | return; 99 | } 100 | 101 | }; // namespace SortTestHelper 102 | 103 | #endif //INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 104 | -------------------------------------------------------------------------------- /sort-advanced/02-merge-sort-advanced/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/sort-advanced/02-merge-sort-advanced/main -------------------------------------------------------------------------------- /sort-advanced/02-merge-sort-advanced/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SortTestHelper.h" 3 | #include "InsertionSort.h" 4 | #include "MergeSort.h" 5 | 6 | using namespace std; 7 | 8 | // 使用优化的归并排序算法, 对arr[l...r]的范围进行排序 9 | template 10 | void __mergeSort2(T arr[], int l, int r) 11 | { 12 | 13 | // 优化2: 对于小规模数组, 使用插入排序 14 | if (r - l <= 15) 15 | { 16 | insertionSort(arr, l, r); 17 | return; 18 | } 19 | 20 | int mid = (l + r) / 2; 21 | __mergeSort2(arr, l, mid); 22 | __mergeSort2(arr, mid + 1, r); 23 | 24 | // 优化1: 对于arr[mid] <= arr[mid+1]的情况,不进行merge 25 | // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失 26 | if (arr[mid] > arr[mid + 1]) 27 | __merge(arr, l, mid, r); 28 | } 29 | 30 | template 31 | void mergeSort2(T arr[], int n) 32 | { 33 | 34 | __mergeSort2(arr, 0, n - 1); 35 | } 36 | 37 | int main() 38 | { 39 | 40 | int n = 50000; 41 | 42 | // 测试1 一般性测试 43 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 44 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 45 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 46 | int *arr3 = SortTestHelper::copyIntArray(arr1, n); 47 | 48 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr1, n); 49 | SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n); 50 | SortTestHelper::testSort("Merge Sort 2", mergeSort2, arr3, n); 51 | 52 | delete[] arr1; 53 | delete[] arr2; 54 | delete[] arr3; 55 | 56 | cout << endl; 57 | 58 | // 测试2 测试近乎有序的数组 59 | int swapTimes = 10; 60 | assert(swapTimes >= 0); 61 | 62 | cout << "Test for nearly ordered array, size = " << n << ", swap time = " << swapTimes << endl; 63 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 64 | arr2 = SortTestHelper::copyIntArray(arr1, n); 65 | arr3 = SortTestHelper::copyIntArray(arr1, n); 66 | 67 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr1, n); 68 | SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n); 69 | SortTestHelper::testSort("Merge Sort 2", mergeSort2, arr3, n); 70 | 71 | delete[] arr1; 72 | delete[] arr2; 73 | delete[] arr3; 74 | 75 | return 0; 76 | } -------------------------------------------------------------------------------- /sort-advanced/03-merge-sort-button-up/InsertionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /sort-advanced/03-merge-sort-button-up/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 13 | template 14 | void __merge(T arr[], int l, int mid, int r) 15 | { 16 | 17 | //* VS不支持动态长度数组, 即不能使用 T aux[r-l+1]的方式申请aux的空间 18 | //* 使用VS的同学, 请使用new的方式申请aux空间 19 | //* 使用new申请空间, 不要忘了在__merge函数的最后, delete掉申请的空间:) 20 | T aux[r - l + 1]; 21 | //T *aux = new T[r-l+1]; 22 | 23 | for (int i = l; i <= r; i++) 24 | aux[i - l] = arr[i]; 25 | 26 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 27 | int i = l, j = mid + 1; 28 | for (int k = l; k <= r; k++) 29 | { 30 | 31 | if (i > mid) 32 | { // 如果左半部分元素已经全部处理完毕 33 | arr[k] = aux[j - l]; 34 | j++; 35 | } 36 | else if (j > r) 37 | { // 如果右半部分元素已经全部处理完毕 38 | arr[k] = aux[i - l]; 39 | i++; 40 | } 41 | else if (aux[i - l] < aux[j - l]) 42 | { // 左半部分所指元素 < 右半部分所指元素 43 | arr[k] = aux[i - l]; 44 | i++; 45 | } 46 | else 47 | { // 左半部分所指元素 >= 右半部分所指元素 48 | arr[k] = aux[j - l]; 49 | j++; 50 | } 51 | } 52 | 53 | //delete[] aux; 54 | } 55 | 56 | // 递归使用归并排序,对arr[l...r]的范围进行排序 57 | template 58 | void __mergeSort(T arr[], int l, int r) 59 | { 60 | 61 | if (l >= r) 62 | return; 63 | 64 | int mid = (l + r) / 2; 65 | __mergeSort(arr, l, mid); 66 | __mergeSort(arr, mid + 1, r); 67 | __merge(arr, l, mid, r); 68 | } 69 | 70 | template 71 | void mergeSort(T arr[], int n) 72 | { 73 | 74 | __mergeSort(arr, 0, n - 1); 75 | } 76 | 77 | #endif //INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 78 | -------------------------------------------------------------------------------- /sort-advanced/03-merge-sort-button-up/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 6 | #define INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 58 | copy(a, a + n, arr); 59 | return arr; 60 | } 61 | 62 | // 打印arr数组的所有内容 63 | template 64 | void printArray(T arr[], int n) 65 | { 66 | 67 | for (int i = 0; i < n; i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return; 72 | } 73 | 74 | // 判断arr数组是否有序 75 | template 76 | bool isSorted(T arr[], int n) 77 | { 78 | 79 | for (int i = 0; i < n - 1; i++) 80 | if (arr[i] > arr[i + 1]) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 87 | template 88 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 89 | { 90 | 91 | clock_t startTime = clock(); 92 | sort(arr, n); 93 | clock_t endTime = clock(); 94 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 95 | 96 | assert(isSorted(arr, n)); 97 | 98 | return; 99 | } 100 | 101 | }; // namespace SortTestHelper 102 | 103 | #endif //INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 104 | -------------------------------------------------------------------------------- /sort-advanced/03-merge-sort-button-up/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #include 5 | #include "SortTestHelper.h" 6 | #include "MergeSort.h" 7 | #include "InsertionSort.h" 8 | 9 | using namespace std; 10 | 11 | template 12 | // 未优化版本 13 | void mergeSortBU_ori(T arr[], int n) 14 | { 15 | for (int sz = 0; sz <= n; sz += sz) 16 | for (int i = 0; i + sz < n; i += sz + sz) 17 | // 对 arr[i...i+sz-1] 和 arr[i+sz...i+2*sz-1] 进行归并 18 | __merge(arr, i, i + sz - 1, min(i + sz + sz - 1, n - 1)); 19 | } 20 | 21 | template 22 | void mergeSortBU(T arr[], int n) 23 | { 24 | // Merge Sort Bottom Up 优化 25 | // 对于小数组, 使用插入排序优化 26 | for (int i = 0; i < n; i += 16) 27 | insertionSort(arr,i, min(i + 15, n - 1)); 28 | for (int sz = 16; sz < n; sz += sz) 29 | for (int i = 0; i < n - sz; i += sz + sz) 30 | // 对于arr[mid]<=arr[mid+1]的情况,不进行merge 31 | if (arr[i + sz - 1] > arr[i + sz]) 32 | __merge(arr, i, i + sz - 1, min(i + sz + sz - 1, n - 1)); 33 | } 34 | 35 | int main() 36 | { 37 | int n = 1000000; 38 | // 测试1 一般性测试 39 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 40 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 41 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 42 | 43 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 44 | SortTestHelper::testSort("Merge Sort Bottom Up", mergeSortBU, arr2, n); 45 | 46 | delete[] arr1; 47 | delete[] arr2; 48 | cout << endl; 49 | 50 | // 测试2 测试近乎有序的数组 51 | int swapTimes = 100; 52 | cout << "Test for nearly ordered array, size = " << n << ", swap time = " << swapTimes << endl; 53 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 54 | arr2 = SortTestHelper::copyIntArray(arr1, n); 55 | 56 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 57 | SortTestHelper::testSort("Merge Sort Bottom Up", mergeSortBU, arr2, n); 58 | 59 | delete[] arr1; 60 | delete[] arr2; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /sort-advanced/04-quick-sort/InsertionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /sort-advanced/04-quick-sort/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 13 | template 14 | void __merge(T arr[], int l, int mid, int r) 15 | { 16 | 17 | //* VS不支持动态长度数组, 即不能使用 T aux[r-l+1]的方式申请aux的空间 18 | //* 使用VS的同学, 请使用new的方式申请aux空间 19 | //* 使用new申请空间, 不要忘了在__merge函数的最后, delete掉申请的空间:) 20 | T aux[r - l + 1]; 21 | //T *aux = new T[r-l+1]; 22 | 23 | for (int i = l; i <= r; i++) 24 | aux[i - l] = arr[i]; 25 | 26 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 27 | int i = l, j = mid + 1; 28 | for (int k = l; k <= r; k++) 29 | { 30 | 31 | if (i > mid) 32 | { // 如果左半部分元素已经全部处理完毕 33 | arr[k] = aux[j - l]; 34 | j++; 35 | } 36 | else if (j > r) 37 | { // 如果右半部分元素已经全部处理完毕 38 | arr[k] = aux[i - l]; 39 | i++; 40 | } 41 | else if (aux[i - l] < aux[j - l]) 42 | { // 左半部分所指元素 < 右半部分所指元素 43 | arr[k] = aux[i - l]; 44 | i++; 45 | } 46 | else 47 | { // 左半部分所指元素 >= 右半部分所指元素 48 | arr[k] = aux[j - l]; 49 | j++; 50 | } 51 | } 52 | 53 | //delete[] aux; 54 | } 55 | 56 | // 递归使用归并排序,对arr[l...r]的范围进行排序 57 | template 58 | void __mergeSort(T arr[], int l, int r) 59 | { 60 | 61 | if (l >= r) 62 | return; 63 | 64 | int mid = (l + r) / 2; 65 | __mergeSort(arr, l, mid); 66 | __mergeSort(arr, mid + 1, r); 67 | __merge(arr, l, mid, r); 68 | } 69 | 70 | template 71 | void mergeSort(T arr[], int n) 72 | { 73 | 74 | __mergeSort(arr, 0, n - 1); 75 | } 76 | 77 | #endif //INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 78 | -------------------------------------------------------------------------------- /sort-advanced/04-quick-sort/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 6 | #define INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 58 | copy(a, a + n, arr); 59 | return arr; 60 | } 61 | 62 | // 打印arr数组的所有内容 63 | template 64 | void printArray(T arr[], int n) 65 | { 66 | 67 | for (int i = 0; i < n; i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return; 72 | } 73 | 74 | // 判断arr数组是否有序 75 | template 76 | bool isSorted(T arr[], int n) 77 | { 78 | 79 | for (int i = 0; i < n - 1; i++) 80 | if (arr[i] > arr[i + 1]) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 87 | template 88 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 89 | { 90 | 91 | clock_t startTime = clock(); 92 | sort(arr, n); 93 | clock_t endTime = clock(); 94 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 95 | 96 | assert(isSorted(arr, n)); 97 | 98 | return; 99 | } 100 | 101 | }; // namespace SortTestHelper 102 | 103 | #endif //INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 104 | -------------------------------------------------------------------------------- /sort-advanced/04-quick-sort/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/sort-advanced/04-quick-sort/main -------------------------------------------------------------------------------- /sort-advanced/04-quick-sort/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #include 5 | #include 6 | #include "SortTestHelper.h" 7 | #include "MergeSort.h" 8 | #include "InsertionSort.h" 9 | 10 | using namespace std; 11 | 12 | // 对arr[l...r]部分进行partition操作 13 | // 返回p,使得[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 14 | template 15 | int __partition(T arr[], int l, int r) 16 | { 17 | T v = arr[l]; 18 | // arr[l+1...j] < v ; arr[j+1...i] > v 19 | int j = l; 20 | for (int i = l + 1; i <= r; i++) 21 | { 22 | if (arr[i] < v) 23 | { 24 | // swap(arr[++j], arr[i]) 25 | swap(arr[j + 1], arr[i]); 26 | j++; 27 | } 28 | } 29 | swap(arr[l], arr[j]); 30 | return j; 31 | } 32 | 33 | // 对arr[l...r]部分进行快速排序 34 | template 35 | void __quickSort(T arr[], int l, int r) 36 | { 37 | if (l >= r) 38 | return; 39 | int p = __partition(arr, l, r); 40 | __quickSort(arr, l, p - 1); 41 | __quickSort(arr, p + 1, r); 42 | } 43 | 44 | template 45 | void quickSort(T arr[], int n) 46 | { 47 | __quickSort(arr, 0, n - 1); 48 | } 49 | 50 | // 比较Merge Sort和Quick Sort两种排序算法的性能效率 51 | // 两种排序算法虽然都是O(nlogn)级别的, 但是Quick Sort算法有常数级的优势 52 | // Quick Sort要比Merge Sort快, 即使我们对Merge Sort进行了优化 53 | int main() 54 | { 55 | 56 | int n = 1000000; 57 | 58 | // 测试1 一般性测试 59 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 60 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 61 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 62 | 63 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 64 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 65 | 66 | delete[] arr1; 67 | delete[] arr2; 68 | 69 | cout << endl; 70 | // 测试2 测试近乎有序的数组 71 | // 但是对于近乎有序的数组, 我们的快速排序算法退化成了O(n^2)级别的算法 72 | // 思考一下为什么对于近乎有序的数组, 快排退化成了O(n^2)的算法? :) 73 | // int swapTimes = 100; 74 | // cout<<"Test for nearly ordered array, size = "< 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /sort-advanced/05-quick-sort-advanced/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 13 | template 14 | void __merge(T arr[], int l, int mid, int r) 15 | { 16 | 17 | //* VS不支持动态长度数组, 即不能使用 T aux[r-l+1]的方式申请aux的空间 18 | //* 使用VS的同学, 请使用new的方式申请aux空间 19 | //* 使用new申请空间, 不要忘了在__merge函数的最后, delete掉申请的空间:) 20 | T aux[r - l + 1]; 21 | //T *aux = new T[r-l+1]; 22 | 23 | for (int i = l; i <= r; i++) 24 | aux[i - l] = arr[i]; 25 | 26 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 27 | int i = l, j = mid + 1; 28 | for (int k = l; k <= r; k++) 29 | { 30 | 31 | if (i > mid) 32 | { // 如果左半部分元素已经全部处理完毕 33 | arr[k] = aux[j - l]; 34 | j++; 35 | } 36 | else if (j > r) 37 | { // 如果右半部分元素已经全部处理完毕 38 | arr[k] = aux[i - l]; 39 | i++; 40 | } 41 | else if (aux[i - l] < aux[j - l]) 42 | { // 左半部分所指元素 < 右半部分所指元素 43 | arr[k] = aux[i - l]; 44 | i++; 45 | } 46 | else 47 | { // 左半部分所指元素 >= 右半部分所指元素 48 | arr[k] = aux[j - l]; 49 | j++; 50 | } 51 | } 52 | 53 | //delete[] aux; 54 | } 55 | 56 | // 递归使用归并排序,对arr[l...r]的范围进行排序 57 | template 58 | void __mergeSort(T arr[], int l, int r) 59 | { 60 | 61 | if (l >= r) 62 | return; 63 | 64 | int mid = (l + r) / 2; 65 | __mergeSort(arr, l, mid); 66 | __mergeSort(arr, mid + 1, r); 67 | __merge(arr, l, mid, r); 68 | } 69 | 70 | template 71 | void mergeSort(T arr[], int n) 72 | { 73 | 74 | __mergeSort(arr, 0, n - 1); 75 | } 76 | 77 | #endif //INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 78 | -------------------------------------------------------------------------------- /sort-advanced/05-quick-sort-advanced/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 6 | #define INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 58 | copy(a, a + n, arr); 59 | return arr; 60 | } 61 | 62 | // 打印arr数组的所有内容 63 | template 64 | void printArray(T arr[], int n) 65 | { 66 | 67 | for (int i = 0; i < n; i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return; 72 | } 73 | 74 | // 判断arr数组是否有序 75 | template 76 | bool isSorted(T arr[], int n) 77 | { 78 | 79 | for (int i = 0; i < n - 1; i++) 80 | if (arr[i] > arr[i + 1]) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 87 | template 88 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 89 | { 90 | 91 | clock_t startTime = clock(); 92 | sort(arr, n); 93 | clock_t endTime = clock(); 94 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 95 | 96 | assert(isSorted(arr, n)); 97 | 98 | return; 99 | } 100 | 101 | }; // namespace SortTestHelper 102 | 103 | #endif //INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 104 | -------------------------------------------------------------------------------- /sort-advanced/05-quick-sort-advanced/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #include 5 | #include 6 | #include "SortTestHelper.h" 7 | #include "MergeSort.h" 8 | #include "InsertionSort.h" 9 | 10 | using namespace std; 11 | 12 | // 对arr[l...r]部分进行partition操作 13 | // 返回p,使得[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 14 | template 15 | int __partition(T arr[], int l, int r) 16 | { 17 | // 挑选一个随机数作为锚定 18 | swap(arr[l],arr[rand() % (r - l + 1) + l]); 19 | T v = arr[l]; 20 | // arr[l+1...j] < v ; arr[j+1...i] > v 21 | int j = l; 22 | for (int i = l + 1; i <= r; i++) 23 | { 24 | if (arr[i] < v) 25 | { 26 | // swap(arr[++j], arr[i]) 27 | swap(arr[j + 1], arr[i]); 28 | j++; 29 | } 30 | } 31 | swap(arr[l], arr[j]); 32 | return j; 33 | } 34 | 35 | // 对arr[l...r]部分进行快速排序 36 | template 37 | void __quickSort(T arr[], int l, int r) 38 | { 39 | // if (l >= r) 40 | // return; 41 | if (r - l <= 15) 42 | { 43 | insertionSort(arr, l, r); 44 | return; 45 | } 46 | int p = __partition(arr, l, r); 47 | __quickSort(arr, l, p - 1); 48 | __quickSort(arr, p + 1, r); 49 | } 50 | 51 | template 52 | void quickSort(T arr[], int n) 53 | { 54 | srand(time(NULL)); 55 | __quickSort(arr, 0, n - 1); 56 | } 57 | 58 | // 比较Merge Sort和Quick Sort两种排序算法的性能效率 59 | // 两种排序算法虽然都是O(nlogn)级别的, 但是Quick Sort算法有常数级的优势 60 | // Quick Sort要比Merge Sort快, 即使我们对Merge Sort进行了优化 61 | int main() 62 | { 63 | 64 | int n = 1000000; 65 | 66 | // 测试1 一般性测试 67 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 68 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 69 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 70 | 71 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 72 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 73 | 74 | delete[] arr1; 75 | delete[] arr2; 76 | 77 | cout << endl; 78 | // 测试2 测试近乎有序的数组 79 | // 但是对于近乎有序的数组, 我们的快速排序算法退化成了O(n^2)级别的算法 80 | // 思考一下为什么对于近乎有序的数组, 快排退化成了O(n^2)的算法? :) 81 | // int swapTimes = 100; 82 | // cout<<"Test for nearly ordered array, size = "< 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /sort-advanced/06-quick-sort-two-way/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 13 | template 14 | void __merge(T arr[], int l, int mid, int r) 15 | { 16 | 17 | //* VS不支持动态长度数组, 即不能使用 T aux[r-l+1]的方式申请aux的空间 18 | //* 使用VS的同学, 请使用new的方式申请aux空间 19 | //* 使用new申请空间, 不要忘了在__merge函数的最后, delete掉申请的空间:) 20 | T aux[r - l + 1]; 21 | //T *aux = new T[r-l+1]; 22 | 23 | for (int i = l; i <= r; i++) 24 | aux[i - l] = arr[i]; 25 | 26 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 27 | int i = l, j = mid + 1; 28 | for (int k = l; k <= r; k++) 29 | { 30 | 31 | if (i > mid) 32 | { // 如果左半部分元素已经全部处理完毕 33 | arr[k] = aux[j - l]; 34 | j++; 35 | } 36 | else if (j > r) 37 | { // 如果右半部分元素已经全部处理完毕 38 | arr[k] = aux[i - l]; 39 | i++; 40 | } 41 | else if (aux[i - l] < aux[j - l]) 42 | { // 左半部分所指元素 < 右半部分所指元素 43 | arr[k] = aux[i - l]; 44 | i++; 45 | } 46 | else 47 | { // 左半部分所指元素 >= 右半部分所指元素 48 | arr[k] = aux[j - l]; 49 | j++; 50 | } 51 | } 52 | 53 | //delete[] aux; 54 | } 55 | 56 | // 递归使用归并排序,对arr[l...r]的范围进行排序 57 | template 58 | void __mergeSort(T arr[], int l, int r) 59 | { 60 | 61 | if (l >= r) 62 | return; 63 | 64 | int mid = (l + r) / 2; 65 | __mergeSort(arr, l, mid); 66 | __mergeSort(arr, mid + 1, r); 67 | __merge(arr, l, mid, r); 68 | } 69 | 70 | template 71 | void mergeSort(T arr[], int n) 72 | { 73 | 74 | __mergeSort(arr, 0, n - 1); 75 | } 76 | 77 | #endif //INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 78 | -------------------------------------------------------------------------------- /sort-advanced/06-quick-sort-two-way/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 6 | #define INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 58 | copy(a, a + n, arr); 59 | return arr; 60 | } 61 | 62 | // 打印arr数组的所有内容 63 | template 64 | void printArray(T arr[], int n) 65 | { 66 | 67 | for (int i = 0; i < n; i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return; 72 | } 73 | 74 | // 判断arr数组是否有序 75 | template 76 | bool isSorted(T arr[], int n) 77 | { 78 | 79 | for (int i = 0; i < n - 1; i++) 80 | if (arr[i] > arr[i + 1]) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 87 | template 88 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 89 | { 90 | 91 | clock_t startTime = clock(); 92 | sort(arr, n); 93 | clock_t endTime = clock(); 94 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 95 | 96 | assert(isSorted(arr, n)); 97 | 98 | return; 99 | } 100 | 101 | }; // namespace SortTestHelper 102 | 103 | #endif //INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 104 | -------------------------------------------------------------------------------- /sort-advanced/06-quick-sort-two-way/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/sort-advanced/06-quick-sort-two-way/main -------------------------------------------------------------------------------- /sort-advanced/06-quick-sort-two-way/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #include 5 | #include 6 | #include "SortTestHelper.h" 7 | #include "MergeSort.h" 8 | #include "InsertionSort.h" 9 | 10 | using namespace std; 11 | 12 | // 对arr[l...r]部分进行partition操作 13 | // 返回p,使得[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 14 | template 15 | int __partition(T arr[], int l, int r) 16 | { 17 | // 挑选一个随机数作为锚定 18 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 19 | T v = arr[l]; 20 | // arr[l+1...j] < v ; arr[j+1...i] > v 21 | int j = l; 22 | for (int i = l + 1; i <= r; i++) 23 | { 24 | if (arr[i] < v) 25 | { 26 | // swap(arr[++j], arr[i]) 27 | swap(arr[j + 1], arr[i]); 28 | j++; 29 | } 30 | } 31 | swap(arr[l], arr[j]); 32 | return j; 33 | } 34 | 35 | // 双路快速排序的partition 36 | // 返回p, 使得arr[l...p-1] <= arr[p] ; arr[p+1...r] >= arr[p] 37 | // 双路快排处理的元素正好等于arr[p]的时候要注意,详见下面的注释:) 38 | template 39 | int __partition2(T arr[], int l, int r) 40 | { 41 | // 选择一个随机数为锚定 42 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 43 | T v = arr[l]; 44 | // arr[l+1...i) <= v; arr(j...r] >= v 45 | int i = l + 1, j = r; 46 | while (true) 47 | { 48 | while (i <= r && arr[i] < v) 49 | i++; 50 | while (j >= l + 1 && arr[j] > v) 51 | j--; 52 | if (i > j) 53 | break; 54 | swap(arr[i], arr[j]); 55 | i++; 56 | j--; 57 | } 58 | swap(arr[l], arr[j]); 59 | return j; 60 | } 61 | 62 | // 对arr[l...r]部分进行快速排序 63 | template 64 | void __quickSort(T arr[], int l, int r) 65 | { 66 | // if (l >= r) 67 | // return; 68 | if (r - l <= 15) 69 | { 70 | insertionSort(arr, l, r); 71 | return; 72 | } 73 | int p = __partition2(arr, l, r); 74 | __quickSort(arr, l, p - 1); 75 | __quickSort(arr, p + 1, r); 76 | } 77 | 78 | template 79 | void quickSort(T arr[], int n) 80 | { 81 | srand(time(NULL)); 82 | __quickSort(arr, 0, n - 1); 83 | } 84 | 85 | // 比较Merge Sort和Quick Sort两种排序算法的性能效率 86 | // 两种排序算法虽然都是O(nlogn)级别的, 但是Quick Sort算法有常数级的优势 87 | // Quick Sort要比Merge Sort快, 即使我们对Merge Sort进行了优化 88 | int main() 89 | { 90 | 91 | int n = 1000000; 92 | 93 | // 测试1 一般性测试 94 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 95 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 96 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 97 | 98 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 99 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 100 | 101 | delete[] arr1; 102 | delete[] arr2; 103 | 104 | cout << endl; 105 | // 测试2 测试近乎有序的数组 106 | // 但是对于近乎有序的数组, 我们的快速排序算法退化成了O(n^2)级别的算法 107 | // 思考一下为什么对于近乎有序的数组, 快排退化成了O(n^2)的算法? :) 108 | // int swapTimes = 100; 109 | // cout<<"Test for nearly ordered array, size = "< 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void insertionSort(T arr[], int n) 15 | { 16 | 17 | for (int i = 1; i < n; i++) 18 | { 19 | 20 | T e = arr[i]; 21 | int j; 22 | for (j = i; j > 0 && arr[j - 1] > e; j--) 23 | arr[j] = arr[j - 1]; 24 | arr[j] = e; 25 | } 26 | 27 | return; 28 | } 29 | 30 | // 对arr[l...r]范围的数组进行插入排序 31 | template 32 | void insertionSort(T arr[], int l, int r) 33 | { 34 | 35 | for (int i = l + 1; i <= r; i++) 36 | { 37 | 38 | T e = arr[i]; 39 | int j; 40 | for (j = i; j > l && arr[j - 1] > e; j--) 41 | arr[j] = arr[j - 1]; 42 | arr[j] = e; 43 | } 44 | 45 | return; 46 | } 47 | 48 | #endif //INC_03_MERGE_SORT_ADVANCE_INSERTIONSORT_H 49 | -------------------------------------------------------------------------------- /sort-advanced/07-quick-sort-three-ways/MergeSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 6 | #define INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 13 | template 14 | void __merge(T arr[], int l, int mid, int r) 15 | { 16 | 17 | //* VS不支持动态长度数组, 即不能使用 T aux[r-l+1]的方式申请aux的空间 18 | //* 使用VS的同学, 请使用new的方式申请aux空间 19 | //* 使用new申请空间, 不要忘了在__merge函数的最后, delete掉申请的空间:) 20 | T aux[r - l + 1]; 21 | //T *aux = new T[r-l+1]; 22 | 23 | for (int i = l; i <= r; i++) 24 | aux[i - l] = arr[i]; 25 | 26 | // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 27 | int i = l, j = mid + 1; 28 | for (int k = l; k <= r; k++) 29 | { 30 | 31 | if (i > mid) 32 | { // 如果左半部分元素已经全部处理完毕 33 | arr[k] = aux[j - l]; 34 | j++; 35 | } 36 | else if (j > r) 37 | { // 如果右半部分元素已经全部处理完毕 38 | arr[k] = aux[i - l]; 39 | i++; 40 | } 41 | else if (aux[i - l] < aux[j - l]) 42 | { // 左半部分所指元素 < 右半部分所指元素 43 | arr[k] = aux[i - l]; 44 | i++; 45 | } 46 | else 47 | { // 左半部分所指元素 >= 右半部分所指元素 48 | arr[k] = aux[j - l]; 49 | j++; 50 | } 51 | } 52 | 53 | //delete[] aux; 54 | } 55 | 56 | // 递归使用归并排序,对arr[l...r]的范围进行排序 57 | template 58 | void __mergeSort(T arr[], int l, int r) 59 | { 60 | 61 | if (l >= r) 62 | return; 63 | 64 | int mid = (l + r) / 2; 65 | __mergeSort(arr, l, mid); 66 | __mergeSort(arr, mid + 1, r); 67 | __merge(arr, l, mid, r); 68 | } 69 | 70 | template 71 | void mergeSort(T arr[], int n) 72 | { 73 | 74 | __mergeSort(arr, 0, n - 1); 75 | } 76 | 77 | #endif //INC_03_MERGE_SORT_ADVANCE_MERGESORT_H 78 | -------------------------------------------------------------------------------- /sort-advanced/07-quick-sort-three-ways/QuickSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 7/23/16. 3 | // 4 | 5 | #ifndef INC_07_QUICK_SORT_THREE_WAYS_QUICKSORT_H 6 | #define INC_07_QUICK_SORT_THREE_WAYS_QUICKSORT_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include "InsertionSort.h" 12 | 13 | using namespace std; 14 | 15 | // 对arr[l...r]部分进行partition操作 16 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 17 | template 18 | int _partition(T arr[], int l, int r) 19 | { 20 | 21 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 22 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 23 | 24 | T v = arr[l]; 25 | int j = l; 26 | for (int i = l + 1; i <= r; i++) 27 | if (arr[i] < v) 28 | { 29 | j++; 30 | swap(arr[j], arr[i]); 31 | } 32 | 33 | swap(arr[l], arr[j]); 34 | 35 | return j; 36 | } 37 | 38 | // 双路快速排序的partition 39 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 40 | template 41 | int _partition2(T arr[], int l, int r) 42 | { 43 | 44 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 45 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 46 | T v = arr[l]; 47 | 48 | // arr[l+1...i) <= v; arr(j...r] >= v 49 | int i = l + 1, j = r; 50 | while (true) 51 | { 52 | // 注意这里的边界, arr[i] < v, 不能是arr[i] <= v 53 | // 思考一下为什么? 54 | while (i <= r && arr[i] < v) 55 | i++; 56 | 57 | // 注意这里的边界, arr[j] > v, 不能是arr[j] >= v 58 | // 思考一下为什么? 59 | while (j >= l + 1 && arr[j] > v) 60 | j--; 61 | 62 | // 对于上面的两个边界的设定, 有的同学在课程的问答区有很好的回答:) 63 | // 大家可以参考: http://coding.imooc.com/learn/questiondetail/4920.html 64 | 65 | if (i > j) 66 | break; 67 | 68 | swap(arr[i], arr[j]); 69 | i++; 70 | j--; 71 | } 72 | 73 | swap(arr[l], arr[j]); 74 | 75 | return j; 76 | } 77 | 78 | // 对arr[l...r]部分进行快速排序 79 | template 80 | void _quickSort(T arr[], int l, int r) 81 | { 82 | 83 | // 对于小规模数组, 使用插入排序进行优化 84 | if (r - l <= 15) 85 | { 86 | insertionSort(arr, l, r); 87 | return; 88 | } 89 | 90 | // 调用双路快速排序的partition 91 | int p = _partition2(arr, l, r); 92 | _quickSort(arr, l, p - 1); 93 | _quickSort(arr, p + 1, r); 94 | } 95 | 96 | template 97 | void quickSort(T arr[], int n) 98 | { 99 | 100 | srand(time(NULL)); 101 | _quickSort(arr, 0, n - 1); 102 | } 103 | 104 | #endif //INC_07_QUICK_SORT_THREE_WAYS_QUICKSORT_H 105 | -------------------------------------------------------------------------------- /sort-advanced/07-quick-sort-three-ways/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 6 | #define INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 58 | copy(a, a + n, arr); 59 | return arr; 60 | } 61 | 62 | // 打印arr数组的所有内容 63 | template 64 | void printArray(T arr[], int n) 65 | { 66 | 67 | for (int i = 0; i < n; i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return; 72 | } 73 | 74 | // 判断arr数组是否有序 75 | template 76 | bool isSorted(T arr[], int n) 77 | { 78 | 79 | for (int i = 0; i < n - 1; i++) 80 | if (arr[i] > arr[i + 1]) 81 | return false; 82 | 83 | return true; 84 | } 85 | 86 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 87 | template 88 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 89 | { 90 | 91 | clock_t startTime = clock(); 92 | sort(arr, n); 93 | clock_t endTime = clock(); 94 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 95 | 96 | assert(isSorted(arr, n)); 97 | 98 | return; 99 | } 100 | 101 | }; // namespace SortTestHelper 102 | 103 | #endif //INC_03_MERGE_SORT_ADVANCE_SORTTESTHELPER_H 104 | -------------------------------------------------------------------------------- /sort-advanced/07-quick-sort-three-ways/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/sort-advanced/07-quick-sort-three-ways/main -------------------------------------------------------------------------------- /sort-advanced/07-quick-sort-three-ways/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #include 5 | #include 6 | #include "SortTestHelper.h" 7 | #include "MergeSort.h" 8 | #include "InsertionSort.h" 9 | #include "QuickSort.h" 10 | 11 | using namespace std; 12 | 13 | template 14 | void __quickSort3Ways(T arr[], int l, int r) 15 | { 16 | if (r - l <= 15) 17 | { 18 | insertionSort(arr, l, r); 19 | return; 20 | } 21 | // partition 22 | swap(arr[l], arr[rand() % (r - l + 1) + l]); 23 | T v = arr[l]; 24 | int lt = l; // arr[l+1...lt] < v 25 | int gt = r + 1; // arr[gt...r] > v 26 | int i = l + 1; // arr[lt+1...i) == v 27 | while (i < gt) 28 | { 29 | if (arr[i] < v) 30 | { 31 | swap(arr[i], arr[lt + 1]); 32 | lt++; 33 | i++; 34 | } 35 | else if (arr[i] > v) 36 | { 37 | swap(arr[i], arr[gt - 1]); 38 | gt--; 39 | } 40 | else 41 | { 42 | // arr[i] == v 43 | i++; 44 | } 45 | } 46 | swap(arr[l], arr[lt]); 47 | __quickSort3Ways(arr, l, lt - 1); 48 | __quickSort3Ways(arr, gt, r); 49 | } 50 | 51 | template 52 | void quickSort3Ways(T arr[], int n) 53 | { 54 | srand(time(NULL)); 55 | __quickSort3Ways(arr, 0, n - 1); 56 | } 57 | 58 | int main() 59 | { 60 | int n = 1000000; 61 | 62 | // 测试1 一般性测试 63 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 64 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 65 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 66 | int *arr3 = SortTestHelper::copyIntArray(arr1, n); 67 | 68 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 69 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 70 | SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr3, n); 71 | 72 | delete[] arr1; 73 | delete[] arr2; 74 | delete[] arr3; 75 | 76 | cout << endl; 77 | 78 | // 测试2 测试近乎有序的数组 79 | int swapTimes = 100; 80 | cout << "Test for nearly ordered array, size = " << n << ", swap time = " << swapTimes << endl; 81 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 82 | arr2 = SortTestHelper::copyIntArray(arr1, n); 83 | arr3 = SortTestHelper::copyIntArray(arr1, n); 84 | 85 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 86 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 87 | SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr3, n); 88 | 89 | delete[] arr1; 90 | delete[] arr2; 91 | delete[] arr3; 92 | 93 | cout << endl; 94 | 95 | // 测试3 测试存在包含大量相同元素的数组 96 | cout << "Test for random array, size = " << n << ", random range [0,10]" << endl; 97 | arr1 = SortTestHelper::generateRandomArray(n, 0, 10); 98 | arr2 = SortTestHelper::copyIntArray(arr1, n); 99 | arr3 = SortTestHelper::copyIntArray(arr1, n); 100 | 101 | SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n); 102 | SortTestHelper::testSort("Quick Sort", quickSort, arr2, n); 103 | SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr3, n); 104 | 105 | delete[] arr1; 106 | delete[] arr2; 107 | delete[] arr3; 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /sort-basic/01-selection-sort/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(SelectionSort) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 5 | 6 | set(SOURCE_FILES main.cpp) 7 | add_executable(SelectionSort ${SOURCE_FILES}) -------------------------------------------------------------------------------- /sort-basic/01-selection-sort/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 郑天航 on 2019-06-30. 3 | // 4 | # include 5 | 6 | using namespace std; 7 | void selectionSort( int arr[], int n) { 8 | for (int i = 0; i < n; ++i) { 9 | // 寻找[i,n]区间里面的最小值 10 | int minIndex = i; 11 | for (int j = i+1; j < n; ++j) { 12 | if (arr[j] < arr[minIndex]) 13 | minIndex = j; 14 | } 15 | swap(arr[i], arr[minIndex]); 16 | } 17 | } 18 | 19 | int main() { 20 | int a[10] = {10,9,8,7,6,5,4,3,2,1}; 21 | selectionSort(a, 10); 22 | for(int i =0;i<10;i++) 23 | cout< 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | struct Student{ 14 | 15 | string name; 16 | int score; 17 | 18 | // 重载小于运算法,定义Student之间的比较方式 19 | // 如果分数相等,则按照名字的字母序排序 20 | // 如果分数不等,则分数高的靠前 21 | bool operator<(const Student& otherStudent){ 22 | return score != otherStudent.score ? 23 | score > otherStudent.score : name < otherStudent.name; 24 | } 25 | 26 | // 重载<<符号, 定义Student实例的打印输出方式 27 | // * 很多同学看到这里的C++语法, 头就大了, 甚至还有同学表示要重新学习C++语言 28 | // * 对于这个课程, 大可不必。C++语言并不是这个课程的重点, 29 | // * 大家也完全可以使用自己的方式书写代码, 最终只要能够打印出结果就好了, 比如设置一个成员函数, 叫做show()... 30 | // * 推荐大家阅读我在问答区向大家分享的一个学习心得: 【学习心得分享】请大家抓大放小,不要纠结于C++语言的语法细节 31 | // * 链接: http://coding.imooc.com/learn/questiondetail/4100.html 32 | friend ostream& operator<<(ostream &os, const Student &student){ 33 | 34 | os<<"Student: "< 5 | #include "Student.h" 6 | 7 | using namespace std; 8 | 9 | template 10 | void selectionSort(T arr[], int n) { 11 | 12 | for (int i = 0; i < n; i++) { 13 | 14 | int minIndex = i; 15 | for (int j = i + 1; j < n; j++) 16 | if (arr[j] < arr[minIndex]) 17 | minIndex = j; 18 | 19 | swap(arr[i], arr[minIndex]); 20 | } 21 | } 22 | 23 | int main() { 24 | 25 | // 测试模板函数,传入整型数组 26 | int a[10] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; 27 | selectionSort(a, 10); 28 | for (int i = 0; i < 10; i++) 29 | cout << a[i] << " "; 30 | cout << endl; 31 | 32 | // 测试模板函数,传入浮点数数组 33 | float b[4] = {4.4, 3.3, 2.2, 1.1}; 34 | selectionSort(b, 4); 35 | for (int i = 0; i < 4; i++) 36 | cout << b[i] << " "; 37 | cout << endl; 38 | 39 | // 测试模板函数,传入字符串数组 40 | string c[4] = {"D", "C", "B", "A"}; 41 | selectionSort(c, 4); 42 | for (int i = 0; i < 4; i++) 43 | cout << c[i] << " "; 44 | cout << endl; 45 | 46 | // 测试模板函数,传入自定义结构体Student数组 47 | Student d[4] = {{"D", 90}, 48 | {"C", 100}, 49 | {"B", 95}, 50 | {"A", 95}}; 51 | selectionSort(d, 4); 52 | for (int i = 0; i < 4; i++) 53 | cout << d[i]; 54 | cout << endl; 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /sort-basic/03-selection-sort-generate-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(SelectionSort) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 5 | 6 | set(SOURCE_FILES main.cpp) 7 | add_executable(SelectionSort ${SOURCE_FILES}) -------------------------------------------------------------------------------- /sort-basic/03-selection-sort-generate-test/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #ifndef INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 5 | #define INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | namespace SortTestHelper 13 | { 14 | // 生成有n个元素的随机数组, 每个元素的随机范围为[rangeL, rangeR] 15 | int *generageRandomArray(int n, int rangeL, int rangeR) 16 | { 17 | assert(rangeL <= rangeR); 18 | int *arr = new int[n]; 19 | srand(time(NULL)); 20 | for (int i = 0; i < n; i++) 21 | { 22 | arr[i] = rand() % (rangeR - rangeL + 1) + rangeL; 23 | } 24 | return arr; 25 | } 26 | template 27 | 28 | void printArray(T arr[], int n) 29 | { 30 | for (int i = 0; i < n; i++) 31 | cout << arr[i] << " "; 32 | cout << endl; 33 | return; 34 | } 35 | }; // namespace SortTestHelper 36 | #endif //INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H -------------------------------------------------------------------------------- /sort-basic/03-selection-sort-generate-test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SortTestHelper.h" 3 | 4 | using namespace std; 5 | 6 | template 7 | void selectionSort(T arr[], int n) 8 | { 9 | for (int i = 0; i < n; i++) 10 | { 11 | int minIndex = i; 12 | for (int j = i + 1; j < n; j++) 13 | if (arr[j] < arr[minIndex]) 14 | minIndex = j; 15 | swap(arr[i], arr[minIndex]); 16 | } 17 | } 18 | 19 | int main() 20 | { 21 | // 测试排序算法辅助函数 22 | int N = 20000; 23 | int *arr = SortTestHelper::generageRandomArray(N, 0, 100000); 24 | selectionSort(arr, N); 25 | SortTestHelper::printArray(arr, N); 26 | delete[] arr; 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /sort-basic/04-selection-sort-detect-performance/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(SelectionSort) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 5 | 6 | set(SOURCE_FILES main.cpp) 7 | add_executable(SelectionSort ${SOURCE_FILES}) -------------------------------------------------------------------------------- /sort-basic/04-selection-sort-detect-performance/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #ifndef INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 5 | #define INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | namespace SortTestHelper 13 | { 14 | // 生成有n个元素的随机数组, 每个元素的随机范围为[rangeL, rangeR] 15 | int *generageRandomArray(int n, int rangeL, int rangeR) 16 | { 17 | assert(rangeL <= rangeR); 18 | int *arr = new int[n]; 19 | srand(time(NULL)); 20 | for (int i = 0; i < n; i++) 21 | { 22 | arr[i] = rand() % (rangeR - rangeL + 1) + rangeL; 23 | } 24 | return arr; 25 | } 26 | 27 | template 28 | 29 | void printArray(T arr[], int n) 30 | { 31 | for (int i = 0; i < n; i++) 32 | cout << arr[i] << " "; 33 | cout << endl; 34 | return; 35 | } 36 | 37 | template 38 | 39 | bool isSorted(T arr[], int n) 40 | { 41 | for (int i = 0; i < n - 1; i++) 42 | if (arr[i] > arr[i + 1]) 43 | return false; 44 | return true; 45 | } 46 | 47 | template 48 | 49 | void testSort(string sortName, void (*sort)(T[], int), T arr[], int n) 50 | { 51 | clock_t startTime = clock(); 52 | sort(arr, n); 53 | clock_t endTime = clock(); 54 | assert( isSorted(arr, n)); 55 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl; 56 | return; 57 | } 58 | }; // namespace SortTestHelper 59 | #endif //INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H -------------------------------------------------------------------------------- /sort-basic/04-selection-sort-detect-performance/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/sort-basic/04-selection-sort-detect-performance/main -------------------------------------------------------------------------------- /sort-basic/04-selection-sort-detect-performance/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SortTestHelper.h" 3 | 4 | using namespace std; 5 | 6 | template 7 | void selectionSort(T arr[], int n) 8 | { 9 | for (int i = 0; i < n; i++) 10 | { 11 | int minIndex = i; 12 | for (int j = i + 1; j < n; j++) 13 | if (arr[j] < arr[minIndex]) 14 | minIndex = j; 15 | swap(arr[i], arr[minIndex]); 16 | } 17 | } 18 | 19 | int main() 20 | { 21 | // 测试排序算法辅助函数 22 | int N = 10000; 23 | int *arr = SortTestHelper::generageRandomArray(N, 0, 100000); 24 | // selectionSort(arr, N); 25 | // SortTestHelper::printArray(arr, N); 26 | SortTestHelper::testSort("Selection Sort", selectionSort, arr, N); 27 | delete[] arr; 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /sort-basic/05-insertion-sort/SelectionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #ifndef INC_04_INSERTION_SORT_SELECTIONSORT_H 5 | #define INC_04_INSERTION_SORT_SELECTIONSORT_H 6 | 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | 14 | void selectionSort(T arr[], int n) 15 | { 16 | for (int i = 0; i < n; i++) 17 | { 18 | int minIndex = i; 19 | for (int j = i + 1; j < n; j++) 20 | if (arr[j] < arr[minIndex]) 21 | minIndex = j; 22 | swap(arr[i], arr[minIndex]); 23 | } 24 | } 25 | 26 | #endif //INC_04_INSERTION_SORT_SELECTIONSORT_H -------------------------------------------------------------------------------- /sort-basic/05-insertion-sort/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #ifndef INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 5 | #define INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | namespace SortTestHelper 13 | { 14 | // 生成有n个元素的随机数组, 每个元素的随机范围为[rangeL, rangeR] 15 | int *generateRandomArray(int n, int rangeL, int rangeR) 16 | { 17 | assert(rangeL <= rangeR); 18 | int *arr = new int[n]; 19 | srand(time(NULL)); 20 | for (int i = 0; i < n; i++) 21 | { 22 | arr[i] = rand() % (rangeR - rangeL + 1) + rangeL; 23 | } 24 | return arr; 25 | } 26 | 27 | // 打印数组 28 | template 29 | void printArray(T arr[], int n) 30 | { 31 | for (int i = 0; i < n; i++) 32 | cout << arr[i] << " "; 33 | cout << endl; 34 | return; 35 | } 36 | 37 | // 查看是否已经排序 38 | template 39 | bool isSorted(T arr[], int n) 40 | { 41 | for (int i = 0; i < n - 1; i++) 42 | if (arr[i] > arr[i + 1]) 43 | return false; 44 | return true; 45 | } 46 | 47 | // 测试排序性能 48 | template 49 | void testSort(string sortName, void (*sort)(T[], int), T arr[], int n) 50 | { 51 | clock_t startTime = clock(); 52 | sort(arr, n); 53 | clock_t endTime = clock(); 54 | assert( isSorted(arr, n)); 55 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl; 56 | return; 57 | } 58 | 59 | // 复制一个整形函数 60 | int* copyIntArray(int a[], int n){ 61 | int* arr = new int[n]; 62 | copy(a,a + n, arr); 63 | return arr; 64 | } 65 | }; // namespace SortTestHelper 66 | #endif //INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H -------------------------------------------------------------------------------- /sort-basic/05-insertion-sort/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SortTestHelper.h" 3 | #include "SelectionSort.h" 4 | 5 | using namespace std; 6 | 7 | template 8 | void insertionSort(T arr[], int n) 9 | { 10 | for (int i = 1; i < n; i++) 11 | { 12 | // 寻找元素arr[i]合适的插入位置 13 | for (int j = i; j > 0 && arr[j] < arr[j - 1]; j--) 14 | swap(arr[j], arr[j - 1]); 15 | } 16 | } 17 | 18 | int main() 19 | { 20 | // 测试排序算法辅助函数 21 | int N = 10000; 22 | int *arr = SortTestHelper::generateRandomArray(N, 0, N); 23 | int *arr2 = SortTestHelper::copyIntArray(arr, N); 24 | SortTestHelper::testSort("Selection Sort", selectionSort, arr, N); 25 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr, N); 26 | delete[] arr; 27 | delete[] arr2; 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /sort-basic/06-insertion-sort-advanced/SelectionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #ifndef INC_04_INSERTION_SORT_SELECTIONSORT_H 5 | #define INC_04_INSERTION_SORT_SELECTIONSORT_H 6 | 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | 14 | void selectionSort(T arr[], int n) 15 | { 16 | for (int i = 0; i < n; i++) 17 | { 18 | int minIndex = i; 19 | for (int j = i + 1; j < n; j++) 20 | if (arr[j] < arr[minIndex]) 21 | minIndex = j; 22 | swap(arr[i], arr[minIndex]); 23 | } 24 | } 25 | 26 | #endif //INC_04_INSERTION_SORT_SELECTIONSORT_H -------------------------------------------------------------------------------- /sort-basic/06-insertion-sort-advanced/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #ifndef INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 5 | #define INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H 6 | 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | namespace SortTestHelper 13 | { 14 | // 生成有n个元素的随机数组, 每个元素的随机范围为[rangeL, rangeR] 15 | int *generateRandomArray(int n, int rangeL, int rangeR) 16 | { 17 | assert(rangeL <= rangeR); 18 | int *arr = new int[n]; 19 | srand(time(NULL)); 20 | for (int i = 0; i < n; i++) 21 | { 22 | arr[i] = rand() % (rangeR - rangeL + 1) + rangeL; 23 | } 24 | return arr; 25 | } 26 | 27 | // 生成一个近乎有序的数组 28 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 29 | // swapTimes定义了数组的无序程度: 30 | // swapTimes == 0 时, 数组完全有序 31 | // swapTimes 越大, 数组越趋向于无序 32 | int *generateNearlyOrderedArray(int n, int swapTimes) 33 | { 34 | int *arr = new int[n]; 35 | for (int i = 0; i < n; i++) 36 | arr[i] = i; 37 | srand(time(NULL)); 38 | for (int i = 0; i < swapTimes; i++) 39 | { 40 | int posx = rand() % n; 41 | int posy = rand() % n; 42 | swap(arr[posx], arr[posy]); 43 | } 44 | return arr; 45 | } 46 | 47 | // 打印数组 48 | template 49 | void printArray(T arr[], int n) 50 | { 51 | for (int i = 0; i < n; i++) 52 | cout << arr[i] << " "; 53 | cout << endl; 54 | return; 55 | } 56 | 57 | // 查看是否已经排序 58 | template 59 | bool isSorted(T arr[], int n) 60 | { 61 | for (int i = 0; i < n - 1; i++) 62 | if (arr[i] > arr[i + 1]) 63 | return false; 64 | return true; 65 | } 66 | 67 | // 测试排序性能 68 | template 69 | void testSort(string sortName, void (*sort)(T[], int), T arr[], int n) 70 | { 71 | clock_t startTime = clock(); 72 | sort(arr, n); 73 | clock_t endTime = clock(); 74 | assert(isSorted(arr, n)); 75 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl; 76 | return; 77 | } 78 | 79 | // 复制一个整形函数 80 | int *copyIntArray(int a[], int n) 81 | { 82 | int *arr = new int[n]; 83 | copy(a, a + n, arr); 84 | return arr; 85 | } 86 | }; // namespace SortTestHelper 87 | #endif //INC_03_SELECTION_SORT_GENERATE_TEST_CASES_SORTTESTHELPER_H -------------------------------------------------------------------------------- /sort-basic/06-insertion-sort-advanced/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/sort-basic/06-insertion-sort-advanced/main -------------------------------------------------------------------------------- /sort-basic/06-insertion-sort-advanced/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SortTestHelper.h" 3 | #include "SelectionSort.h" 4 | 5 | using namespace std; 6 | 7 | template 8 | void insertionSort(T arr[], int n) 9 | { 10 | for (int i = 1; i < n; i++) 11 | { 12 | // 寻找元素arr[i]合适的插入位置 13 | T e = arr[i]; 14 | int j; // j保存元素e应该插入的位置 15 | for (j = i; j > 0 && arr[j-1] > e; j--) 16 | arr[j] = arr[j-1]; 17 | arr[j] = e; 18 | } 19 | } 20 | 21 | int main() 22 | { 23 | // 测试排序算法辅助函数 24 | int N = 10000; 25 | int *arr = SortTestHelper::generateNearlyOrderedArray(N, 10); 26 | int *arr2 = SortTestHelper::copyIntArray(arr, N); 27 | SortTestHelper::testSort("Selection Sort", selectionSort, arr, N); 28 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr, N); 29 | delete[] arr; 30 | delete[] arr2; 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /sort-basic/07-bubble-sort/InsertionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | 5 | #ifndef CHAPTER_02_COMPLETED_CODE_INSERTIONSORT_H 6 | #define CHAPTER_02_COMPLETED_CODE_INSERTIONSORT_H 7 | 8 | template 9 | 10 | void insertionSort(T arr[], int n) 11 | { 12 | for (int i = 1; i < n; i++) 13 | { 14 | T e = arr[i]; 15 | int j;// j保存元素e应该插入的位置 16 | for (j = 1; j > 0 && arr[j - 1] > e; j--) 17 | arr[j] = arr[j - 1]; 18 | arr[j] = e; 19 | } 20 | return; 21 | } 22 | #endif //CHAPTER_02_COMPLETED_CODE_INSERTIONSORT_H -------------------------------------------------------------------------------- /sort-basic/07-bubble-sort/SelectionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by 3zz. 3 | // 4 | #ifndef INC_04_INSERTION_SORT_SELECTIONSORT_H 5 | #define INC_04_INSERTION_SORT_SELECTIONSORT_H 6 | 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | 14 | void selectionSort(T arr[], int n) 15 | { 16 | for (int i = 0; i < n; i++) 17 | { 18 | int minIndex = i; 19 | for (int j = i + 1; j < n; j++) 20 | if (arr[j] < arr[minIndex]) 21 | minIndex = j; 22 | swap(arr[i], arr[minIndex]); 23 | } 24 | } 25 | 26 | #endif //INC_04_INSERTION_SORT_SELECTIONSORT_H -------------------------------------------------------------------------------- /sort-basic/07-bubble-sort/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 3zz. 3 | // 4 | 5 | #ifndef OPTIONAL_01_BUBBLE_SORT_SORTTESTHELPER_H 6 | #define OPTIONAL_01_BUBBLE_SORT_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | namespace SortTestHelper 17 | { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) 21 | { 22 | 23 | int *arr = new int[n]; 24 | 25 | srand(time(NULL)); 26 | for (int i = 0; i < n; i++) 27 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 28 | return arr; 29 | } 30 | 31 | // 生成一个近乎有序的数组 32 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 33 | // swapTimes定义了数组的无序程度 34 | int *generateNearlyOrderedArray(int n, int swapTimes) 35 | { 36 | 37 | int *arr = new int[n]; 38 | for (int i = 0; i < n; i++) 39 | arr[i] = i; 40 | 41 | srand(time(NULL)); 42 | for (int i = 0; i < swapTimes; i++) 43 | { 44 | int posx = rand() % n; 45 | int posy = rand() % n; 46 | swap(arr[posx], arr[posy]); 47 | } 48 | 49 | return arr; 50 | } 51 | 52 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 53 | int *copyIntArray(int a[], int n) 54 | { 55 | 56 | int *arr = new int[n]; 57 | copy(a, a + n, arr); 58 | return arr; 59 | } 60 | 61 | // 打印arr数组的所有内容 62 | template 63 | void printArray(T arr[], int n) 64 | { 65 | 66 | for (int i = 0; i < n; i++) 67 | cout << arr[i] << " "; 68 | cout << endl; 69 | 70 | return; 71 | } 72 | 73 | // 判断arr数组是否有序 74 | template 75 | bool isSorted(T arr[], int n) 76 | { 77 | 78 | for (int i = 0; i < n - 1; i++) 79 | if (arr[i] > arr[i + 1]) 80 | return false; 81 | 82 | return true; 83 | } 84 | 85 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 86 | template 87 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) 88 | { 89 | 90 | clock_t startTime = clock(); 91 | sort(arr, n); 92 | clock_t endTime = clock(); 93 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; 94 | assert(isSorted(arr, n)); 95 | return; 96 | } 97 | 98 | }; // namespace SortTestHelper 99 | 100 | #endif //OPTIONAL_01_BUBBLE_SORT_SORTTESTHELPER_H -------------------------------------------------------------------------------- /sort-basic/07-bubble-sort/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "SortTestHelper.h" 4 | #include "SelectionSort.h" 5 | #include "InsertionSort.h" 6 | 7 | using namespace std; 8 | 9 | // 我们的第一版bubbleSort 10 | template 11 | void bubbleSort(T arr[], int n) 12 | { 13 | bool swapped; 14 | do 15 | { 16 | swapped = false; 17 | for (int i = 1; i < n; i++) 18 | if (arr[i - 1] > arr[i]) 19 | { 20 | swap(arr[i - 1], arr[i]); 21 | swapped = true; 22 | } 23 | // 优化, 每一趟Bubble Sort都将最大的元素放在了最后的位置 24 | // 所以下一次排序, 最后的元素可以不再考虑 25 | n--; 26 | } while (swapped); 27 | } 28 | 29 | // 我们的第二版bubbleSort,使用newn进行优化 30 | template 31 | void bubbleSort2(T arr[], int n) 32 | { 33 | int newn; // 使用newn进行优化 34 | do 35 | { 36 | newn = 0; 37 | for (int i = 1; i < n; i++) 38 | if (arr[i - 1] > arr[i]) 39 | { 40 | swap(arr[i - 1], arr[i]); 41 | // 记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑 42 | newn = i; 43 | } 44 | n = newn; 45 | } while (newn > 0); 46 | } 47 | 48 | int main() 49 | { 50 | int n = 20000; 51 | // 测试1 一般测试 52 | cout << "Test for random array, size = " << n << ", randome range [0, " << n << "]" << endl; 53 | 54 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 55 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 56 | int *arr3 = SortTestHelper::copyIntArray(arr1, n); 57 | int *arr4 = SortTestHelper::copyIntArray(arr1, n); 58 | 59 | SortTestHelper::testSort("Selection Sort", selectionSort, arr1, n); 60 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr2, n); 61 | SortTestHelper::testSort("Bubble Sort", bubbleSort, arr3, n); 62 | SortTestHelper::testSort("Bubble Sort 2", bubbleSort, arr4, n); 63 | 64 | delete[] arr1; 65 | delete[] arr2; 66 | delete[] arr3; 67 | delete[] arr4; 68 | 69 | cout << endl; 70 | 71 | // 测试2 测试近乎有序的数组 72 | int swapTimes = 100; 73 | 74 | cout << "Test for nNearly ordered array, size = " << n << ", swap time = " << swapTimes << endl; 75 | 76 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 77 | arr2 = SortTestHelper::copyIntArray(arr1, n); 78 | arr3 = SortTestHelper::copyIntArray(arr1, n); 79 | arr4 = SortTestHelper::copyIntArray(arr1, n); 80 | 81 | SortTestHelper::testSort("Selection Sort", selectionSort, arr1, n); 82 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr2, n); 83 | SortTestHelper::testSort("Bubble Sort", bubbleSort, arr3, n); 84 | SortTestHelper::testSort("Bubble Sort 2", bubbleSort, arr4, n); 85 | 86 | delete[] arr1; 87 | delete[] arr2; 88 | delete[] arr3; 89 | delete[] arr4; 90 | 91 | cout << endl; 92 | 93 | // 测试3 测试完全有序的数组 94 | // 对于完全有序的数组,冒泡排序法也将成为O(n)级别的算法 95 | swapTimes = 0; 96 | n = 10000000; // 由于插入排序法和冒泡排序法在完全有序的情况下都将成为O(n)算法 97 | // 所以我们的测试数据规模变大,为1000,0000 98 | cout << "Test for ordered array, size = " << n << endl; 99 | 100 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 101 | arr2 = SortTestHelper::copyIntArray(arr1, n); 102 | arr3 = SortTestHelper::copyIntArray(arr1, n); 103 | arr4 = SortTestHelper::copyIntArray(arr1, n); 104 | 105 | // 在这种情况下,不再测试选择排序算法 106 | //SortTestHelper::testSort("Selection Sort", selectionSort, arr1, n); 107 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr2, n); 108 | SortTestHelper::testSort("Bubble Sort", bubbleSort, arr3, n); 109 | SortTestHelper::testSort("Bubble Sort 2", bubbleSort, arr4, n); 110 | 111 | delete[] arr1; 112 | delete[] arr2; 113 | delete[] arr3; 114 | delete[] arr4; 115 | 116 | return 0; 117 | } -------------------------------------------------------------------------------- /sort-basic/08-Shell-Sort/BubbleSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 7/15/16. 3 | // 4 | 5 | #ifndef OPTIONAL_02_SHELL_SORT_BUBBLESORT_H 6 | #define OPTIONAL_02_SHELL_SORT_BUBBLESORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | void bubbleSort( T arr[] , int n){ 15 | 16 | int newn; // 使用newn进行优化 17 | 18 | do{ 19 | newn = 0; 20 | for( int i = 1 ; i < n ; i ++ ) 21 | if( arr[i-1] > arr[i] ){ 22 | swap( arr[i-1] , arr[i] ); 23 | 24 | // 记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑 25 | newn = i; 26 | } 27 | n = newn; 28 | }while(newn > 0); 29 | } 30 | 31 | #endif //OPTIONAL_02_SHELL_SORT_BUBBLESORT_H 32 | -------------------------------------------------------------------------------- /sort-basic/08-Shell-Sort/InsertionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 7/15/16. 3 | // 4 | 5 | #ifndef OPTIONAL_02_SHELL_SORT_INSERTIONSORT_H 6 | #define OPTIONAL_02_SHELL_SORT_INSERTIONSORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | 14 | template 15 | void insertionSort(T arr[], int n){ 16 | 17 | for( int i = 1 ; i < n ; i ++ ) { 18 | 19 | T e = arr[i]; 20 | int j; 21 | for (j = i; j > 0 && arr[j-1] > e; j--) 22 | arr[j] = arr[j-1]; 23 | arr[j] = e; 24 | } 25 | 26 | return; 27 | } 28 | 29 | #endif //OPTIONAL_02_SHELL_SORT_INSERTIONSORT_H 30 | -------------------------------------------------------------------------------- /sort-basic/08-Shell-Sort/SelectionSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 7/15/16. 3 | // 4 | 5 | #ifndef OPTIONAL_02_SHELL_SORT_SELECTIONSORT_H 6 | #define OPTIONAL_02_SHELL_SORT_SELECTIONSORT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | 14 | template 15 | void selectionSort(T arr[], int n){ 16 | 17 | for(int i = 0 ; i < n ; i ++){ 18 | 19 | int minIndex = i; 20 | for( int j = i + 1 ; j < n ; j ++ ) 21 | if( arr[j] < arr[minIndex] ) 22 | minIndex = j; 23 | 24 | swap( arr[i] , arr[minIndex] ); 25 | } 26 | } 27 | 28 | #endif //OPTIONAL_02_SHELL_SORT_SELECTIONSORT_H 29 | -------------------------------------------------------------------------------- /sort-basic/08-Shell-Sort/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liuyubobobo on 7/15/16. 3 | // 4 | 5 | #ifndef OPTIONAL_02_SHELL_SORT_SORTTESTHELPER_H 6 | #define OPTIONAL_02_SHELL_SORT_SORTTESTHELPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | 17 | namespace SortTestHelper { 18 | 19 | // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] 20 | int *generateRandomArray(int n, int range_l, int range_r) { 21 | 22 | int *arr = new int[n]; 23 | 24 | srand(time(NULL)); 25 | for (int i = 0; i < n; i++) 26 | arr[i] = rand() % (range_r - range_l + 1) + range_l; 27 | return arr; 28 | } 29 | 30 | // 生成一个近乎有序的数组 31 | // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 32 | // swapTimes定义了数组的无序程度 33 | int *generateNearlyOrderedArray(int n, int swapTimes){ 34 | 35 | int *arr = new int[n]; 36 | for(int i = 0 ; i < n ; i ++ ) 37 | arr[i] = i; 38 | 39 | srand(time(NULL)); 40 | for( int i = 0 ; i < swapTimes ; i ++ ){ 41 | int posx = rand()%n; 42 | int posy = rand()%n; 43 | swap( arr[posx] , arr[posy] ); 44 | } 45 | 46 | return arr; 47 | } 48 | 49 | // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组 50 | int *copyIntArray(int a[], int n){ 51 | 52 | int *arr = new int[n]; 53 | //* 在VS中, copy函数被认为是不安全的, 请大家手动写一遍for循环:) 54 | copy(a, a+n, arr); 55 | return arr; 56 | } 57 | 58 | // 打印arr数组的所有内容 59 | template 60 | void printArray(T arr[], int n) { 61 | 62 | for (int i = 0; i < n; i++) 63 | cout << arr[i] << " "; 64 | cout << endl; 65 | 66 | return; 67 | } 68 | 69 | // 判断arr数组是否有序 70 | template 71 | bool isSorted(T arr[], int n) { 72 | for (int i = 0; i < n - 1; i++) 73 | if (arr[i] > arr[i + 1]) 74 | return false; 75 | return true; 76 | } 77 | 78 | // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间 79 | template 80 | void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) { 81 | 82 | clock_t startTime = clock(); 83 | sort(arr, n); 84 | clock_t endTime = clock(); 85 | cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"< 2 | #include "SortTestHelper.h" 3 | #include "SelectionSort.h" 4 | #include "InsertionSort.h" 5 | #include "BubbleSort.h" 6 | 7 | using namespace std; 8 | 9 | template 10 | void shellSort(T arr[], int n) 11 | { 12 | // 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093... 13 | int h = 1; 14 | while (h < n / 3) 15 | h = 3 * h + 1; 16 | while (h >= 1) 17 | { 18 | // h-sort the array 19 | for (int i = h; i < n; i++) 20 | { 21 | // 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序 22 | T e = arr[i]; 23 | int j; 24 | for (j = i; j >= h && e < arr[j - h]; j -= h) 25 | arr[j] = arr[j - h]; 26 | arr[j] = e; 27 | } 28 | h /= 3; 29 | } 30 | } 31 | 32 | // 比较SelectionSort, InsertionSort和BubbleSort和ShellSort四种排序算法的性能效率 33 | // ShellSort是这四种排序算法中性能最优的排序算法 34 | int main() 35 | { 36 | 37 | int n = 20000; 38 | 39 | // 测试1 一般测试 40 | cout << "Test for random array, size = " << n << ", random range [0, " << n << "]" << endl; 41 | 42 | int *arr1 = SortTestHelper::generateRandomArray(n, 0, n); 43 | int *arr2 = SortTestHelper::copyIntArray(arr1, n); 44 | int *arr3 = SortTestHelper::copyIntArray(arr1, n); 45 | int *arr4 = SortTestHelper::copyIntArray(arr1, n); 46 | 47 | SortTestHelper::testSort("Selection Sort", selectionSort, arr1, n); 48 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr2, n); 49 | SortTestHelper::testSort("Bubble Sort", bubbleSort, arr3, n); 50 | SortTestHelper::testSort("Shell Sort", shellSort, arr4, n); 51 | 52 | delete[] arr1; 53 | delete[] arr2; 54 | delete[] arr3; 55 | delete[] arr4; 56 | 57 | cout << endl; 58 | 59 | // 测试2 测试近乎有序的数组 60 | int swapTimes = 100; 61 | 62 | cout << "Test for nearly ordered array, size = " << n << ", swap time = " << swapTimes << endl; 63 | 64 | arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes); 65 | arr2 = SortTestHelper::copyIntArray(arr1, n); 66 | arr3 = SortTestHelper::copyIntArray(arr1, n); 67 | arr4 = SortTestHelper::copyIntArray(arr1, n); 68 | 69 | SortTestHelper::testSort("Selection Sort", selectionSort, arr1, n); 70 | SortTestHelper::testSort("Insertion Sort", insertionSort, arr2, n); 71 | SortTestHelper::testSort("Bubble Sort", bubbleSort, arr3, n); 72 | SortTestHelper::testSort("Shell Sort", shellSort, arr4, n); 73 | 74 | delete[] arr1; 75 | delete[] arr2; 76 | delete[] arr3; 77 | delete[] arr4; 78 | 79 | return 0; 80 | } -------------------------------------------------------------------------------- /static/complete-bin-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/complete-bin-tree.png -------------------------------------------------------------------------------- /static/index-max-heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/index-max-heap.png -------------------------------------------------------------------------------- /static/index-maxheap-reverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/index-maxheap-reverse.png -------------------------------------------------------------------------------- /static/insertion-sort-advanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/insertion-sort-advanced.png -------------------------------------------------------------------------------- /static/insertion-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/insertion-sort.png -------------------------------------------------------------------------------- /static/merge-sort-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/merge-sort-detail.png -------------------------------------------------------------------------------- /static/merge-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/merge-sort.png -------------------------------------------------------------------------------- /static/quick-sort-3-way-finish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort-3-way-finish.png -------------------------------------------------------------------------------- /static/quick-sort-3-way.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort-3-way.png -------------------------------------------------------------------------------- /static/quick-sort-partition-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort-partition-1.png -------------------------------------------------------------------------------- /static/quick-sort-partition-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort-partition-2.png -------------------------------------------------------------------------------- /static/quick-sort-partition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort-partition.png -------------------------------------------------------------------------------- /static/quick-sort-problem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort-problem.png -------------------------------------------------------------------------------- /static/quick-sort-two-way.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort-two-way.png -------------------------------------------------------------------------------- /static/quick-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/quick-sort.png -------------------------------------------------------------------------------- /static/reverse-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/reverse-detail.png -------------------------------------------------------------------------------- /static/selection-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/selection-sort.png -------------------------------------------------------------------------------- /static/sort-solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zu3zz/Learn_some_algorithm_and_data_structure/a25c6c8809a2a4fa51b64d605501e3112f99faf1/static/sort-solution.png -------------------------------------------------------------------------------- /union-find/01-quick-find-union/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | namespace UF1 7 | { 8 | class UnionFind 9 | { 10 | private: 11 | int *id; 12 | int count; 13 | 14 | public: 15 | UnionFind(int n) 16 | { 17 | count = n; 18 | id = new int[n]; 19 | for (int i = 0; i < n; i++) 20 | id[i] = i; 21 | } 22 | ~UnionFind() 23 | { 24 | delete[] id; 25 | } 26 | int find(int p) 27 | { 28 | assert(p >= 0 && p < count); 29 | return id[p]; 30 | } 31 | 32 | bool isConnected(int p, int q) 33 | { 34 | return find(p) == find(q); 35 | } 36 | void unionElements(int p, int q) 37 | { 38 | int pID = find(p); 39 | int qID = find(q); 40 | if (pID == qID) 41 | return; 42 | for (int i = 0; i < count; i++) 43 | if (id[i] == qID) 44 | id[i] = pID; 45 | } 46 | }; 47 | } // namespace UF1 -------------------------------------------------------------------------------- /union-find/02-quick-union/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | namespace UF2{ 7 | class UnionFind{ 8 | private: 9 | int* parent; 10 | int count; 11 | public: 12 | UnionFind(int count){ 13 | parent = new int(count); 14 | this->count = count; 15 | for(int i = 0; i < count; i++) 16 | parent[i] = i; 17 | } 18 | ~UnionFind(){ 19 | delete [] parent; 20 | } 21 | int find(int p){ 22 | assert(p>=0 && p 2 | #include 3 | 4 | using namespace std; 5 | 6 | namespace UF3{ 7 | class UnionFind{ 8 | private: 9 | int* parent; 10 | int* sz; // sz[i]表示以i为根的集合中元素的个数 11 | int count; 12 | public: 13 | UnionFind(int count){ 14 | parent = new int[count]; 15 | this->count = count; 16 | for(int i = 0; i < count; i++){ 17 | parent[i] = i; 18 | sz[i] = 1; 19 | } 20 | } 21 | ~UnionFind(){ 22 | delete [] parent; 23 | delete [] sz; 24 | } 25 | int find(int q){ 26 | assert(q >= 0 && q < count); 27 | while(q != parent[q]){ 28 | q = parent[q]; 29 | } 30 | return q; 31 | } 32 | bool isConnected(int q, int p){ 33 | return find(q) == find(p); 34 | } 35 | void unionElements(int q, int p){ 36 | int qRoot = find(q); 37 | int pRoot = find(p); 38 | if(qRoot == pRoot) 39 | return; 40 | if(sz[qRoot] < sz[pRoot]){ 41 | parent[qRoot] = pRoot; 42 | sz[pRoot] += sz[qRoot]; 43 | } else { 44 | parent[pRoot] = qRoot; 45 | sz[qRoot] += sz[pRoot]; 46 | } 47 | } 48 | }; 49 | } -------------------------------------------------------------------------------- /union-find/04-quick-union-optimized-based-on-rank/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | namespace UF4{ 7 | class UnionFind{ 8 | private: 9 | int* parent; 10 | int* rank; // size[i]表示以i为根的集合所表示的层数 11 | int count; 12 | public: 13 | UnionFind(int count){ 14 | parent = new int[count]; 15 | rank = new int[count]; 16 | this->count = count; 17 | for(int i = 0; i < count; i++) 18 | { 19 | parent[i] = i; 20 | rank[i] = 1; 21 | } 22 | } 23 | ~UnionFind(){ 24 | delete [] parent; 25 | delete [] rank; 26 | } 27 | int find(int q){ 28 | assert(q >= 0 && q < count); 29 | while(q != parent[q]){ 30 | q = parent[q]; 31 | } 32 | return q; 33 | } 34 | bool isConnected(int p, int q){ 35 | return find(q) == find(q); 36 | } 37 | void unionElements(int p, int q){ 38 | int pRoot = find(p); 39 | int qRoot = find(q); 40 | if(qRoot == pRoot) 41 | return; 42 | if(rank[pRoot] < rank[qRoot]){ 43 | parent[pRoot] = qRoot; 44 | } else if (rank[qRoot] < rank[pRoot]){ 45 | parent[qRoot] = pRoot; 46 | } else { // rank[pRoot] = rank[qRoot] 47 | parent[pRoot] = qRoot; 48 | rank[qRoot] +=1; 49 | } 50 | } 51 | }; 52 | } -------------------------------------------------------------------------------- /union-find/05-quick-union-path-compression/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | namespace UF5{ 7 | class UnionFind{ 8 | private: 9 | int* parent; 10 | int* rank; 11 | int count; 12 | public: 13 | UnionFind(int count){ 14 | parent = new int[count]; 15 | rank = new int[count]; 16 | this->count = count; 17 | } 18 | ~UnionFind(){ 19 | delete [] parent; 20 | delete [] rank; 21 | } 22 | int find(int q){ 23 | assert(q >= 0 && q < count); 24 | /* path compression 25 | * not best solution 26 | while(q != parent[q]){ 27 | parent[q] = parent[parent[q]] 28 | q = parent[q]; 29 | } 30 | return q; 31 | */ 32 | // using recursion to get shortest tree 33 | if(q != parent[q]) 34 | parent[q] = find(parent[q]); 35 | return parent[q]; 36 | } 37 | bool isConnected(int q, int p){ 38 | return find(q) == find(p); 39 | } 40 | void unionElements(int q, int p){ 41 | int pRoot = find(p); 42 | int qRoot = find(q); 43 | if(qRoot == pRoot){ 44 | return; 45 | } 46 | if(rank[qRoot] < rank[pRoot]){ 47 | parent[qRoot] = pRoot; 48 | } else if(rank[pRoot] < rank[qRoot]){ 49 | parent[pRoot] = qRoot; 50 | } else { // rank[qRoot] == rank[pRoot] 51 | parent[pRoot] = qRoot; 52 | rank[pRoot] += 1; 53 | } 54 | } 55 | }; 56 | } -------------------------------------------------------------------------------- /union-find/extra-union-find-python-version/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : 3zz 3 | # @Time : 2019-09-02 17:23 4 | # @File : __init__.py 5 | --------------------------------------------------------------------------------