├── 1_Fundamental ├── README.md └── UnionFind.h ├── 2_Sorting ├── HeapSort.h ├── Heapsort_test.cpp ├── Insertion.h ├── Insertion_test.cpp ├── Quick3way.h ├── Quick3way_test.cpp └── README.md ├── 3_Searching ├── BinarySearchTree.h ├── BinarySearchTree_test.cpp ├── README.md ├── RedBlackTree.h └── RedBlackTree_test.cpp ├── 4_Graphs ├── BFSPath.h ├── BellmanFordSP.h ├── DFSCC.h ├── DFSDirectedCycle.h ├── DFSTopo.h ├── DiEdge.h ├── Digraph.h ├── DijkstraSP.h ├── DirectedGraph_test.cpp ├── Edge.h ├── EdgeWeightedDigraph.h ├── EdgeWeightedGraph.h ├── Graph.h ├── KruskalMST.h ├── LazyPrimMST.h ├── MinTree_test.cpp ├── PrimMST.h ├── README.md ├── ShortestPath_test.cpp ├── TopoLongestPath.h ├── UndirectedGraph_test.cpp └── UnionFind.h ├── 5_Strings ├── Huffman.h ├── Huffman_test.cpp ├── Quick3String.h ├── Quick3String_test.cpp └── README.md ├── 6_Context ├── FlowEdge.h ├── FlowFordFulkerson.h ├── FlowNetwork.h ├── README.md ├── SuffixArray.h └── SuffixArray_test.cpp ├── README.md └── func.h /1_Fundamental/README.md: -------------------------------------------------------------------------------- 1 | 代码链接: 2 | xxxxxxxxx 3 | 4 | # 1.binary search 5 | url get data练习 6 | edu.princeton.cs.algs4 普林斯顿算法 jar包 7 | 8 | # 2.dataStruct 9 | queue stack bag 链表实现 10 | 11 | # 3.Union Find 12 | 连通集的查找 13 | API: union find connected 14 | key: 辅助数组id 15 | >Quick find 16 | id[] 相同集合的元素,id[]相同 17 | 18 | >Quick union 19 | id[] 当前元素的root节点序号 20 | 21 | >Weighted QuickUnion 22 | union操作加入size判断 使得较小的子树root指向较大的子树root 23 | 小树加到大树上 避免origin quick union depth的过深 24 | 25 | 代码不在这里加了 一定要掌握 26 | 27 | 28 | ``` java 29 | //TODO iterator()方法返回一个实现hasnext() 和 next()方法的迭代器 30 | 31 | //first是自己定义的node类型 含有item和next结构 32 | 33 | public Iterator iterator() { 34 | return new ListIterator(first); 35 | } 36 | 37 | // an iterator, doesn't implement remove() since it's optional 38 | private class ListIterator implements Iterator { 39 | private Node current; 40 | 41 | public ListIterator(Node first) { 42 | current = first; 43 | } 44 | 45 | public boolean hasNext() { return current != null; } 46 | public void remove() { throw new UnsupportedOperationException(); } 47 | 48 | public Item next() { 49 | if (!hasNext()) throw new NoSuchElementException(); 50 | Item item = current.item; 51 | current = current.next; 52 | return item; 53 | } 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /1_Fundamental/UnionFind.h: -------------------------------------------------------------------------------- 1 | #ifndef UNIONFIND_H_INCLUDED 2 | #define UNIONFIND_H_INCLUDED 3 | #include"func.h" 4 | /* 5 | 实现weighted union find 6 | 小树加入大树 从而减少树的高度 7 | */ 8 | 9 | class UnionFind{ 10 | private: 11 | vector parent; 12 | vector sz; 13 | int unionCount; 14 | public: 15 | UnionFind(int vertexNum) 16 | :unionCount(vertexNum){ 17 | parent.resize(vertexNum); 18 | sz.resize(vertexNum,1); 19 | for(int i=0;i& nums){ 20 | int n = nums.size(); 21 | for(int k=n/2;k>=1;k--) 22 | sink(nums,k,n); 23 | while(n>1){ 24 | swap(nums,1,n--); //最大值放在数组后面保存 25 | sink(nums,1,n); 26 | } 27 | } 28 | private: 29 | //父节点k 不断下沉 直到k大于两个子节点 30 | static void sink(vector& nums,int k,int n){ 31 | while(2*k<=n){ 32 | //k的子节点2k 2k+1中val较大值为j 33 | int j=2*k; 34 | if(j&nums,int i,int j){ 46 | int tmp = nums[i-1]; 47 | nums[i-1]=nums[j-1]; 48 | nums[j-1]=tmp; 49 | } 50 | static bool less(vector&nums,int i,int j){ 51 | return nums[i-1] test={5,4,4,4,44,-1,2,7}; 14 | HeapSort::hsort(test); 15 | for(auto i:test) 16 | cout<& nums){ 8 | int len = nums.size(); 9 | for(int i=1;i0&&nums[j] test={5,4,-1,2,7}; 5 | Insertion::insort(test); 6 | for(auto i:test) 7 | cout<& nums){ 15 | q3sort(nums,0,(int)nums.size()-1); 16 | } 17 | static void q3sort(vector& nums,int lo, int hi){ 18 | if(hiv) std::swap(nums[i],nums[gt--]); 25 | else i++; 26 | } 27 | //得到 nums[lo..lt-1] < v=nums[lt..gt] < nums[gt+1...hi] 28 | q3sort(nums,lo,lt-1); 29 | q3sort(nums,gt+1,hi); 30 | } 31 | }; 32 | 33 | 34 | #endif // QUICK3WAY_H_INCLUDED 35 | -------------------------------------------------------------------------------- /2_Sorting/Quick3way_test.cpp: -------------------------------------------------------------------------------- 1 | #include"Quick3way.h" 2 | 3 | int main(){ 4 | vector test={5,4,4,4,44,-1,2,7}; 5 | Quick3way::q3sort(test); 6 | for(auto i:test) 7 | cout< Select sort P156 6 | key:选择第i小的元素放入a[i]位置 7 | note:运行时间和输入顺序无关 8 | 9 | >Insertion sort P157 10 | key:当前索引左边的所有元素是有序的,但是最终位置尚不确定 11 | note:运行时间和输入顺序相关(1.部分有序 2.小数组)建议使用insert sort 12 | note2:有稳定性 13 | res: time(insert) < time(select) 14 | 15 | >Shell sort P162 16 | key:数组中间隔h步长的元素是有序的, h从N/3递减为1 17 | key2:基于插入排序((只会交换相邻元素),shell sort是交换h步长的元素 18 | note:避免插入排序的极端情况--最后一位是最小元素--插入排序需要逐步移动到起始位置 19 | 20 | # 2.Merge Sort 21 | key:归并两个有序的数组; 22 | key2:递归到小数组;在进行归并(辅助数组N) 23 | note:有稳定性 24 | improvement:1.加快小数组排序(n < 8,则使用插入排序) 2.递归中交换参数避免重复辅助数组的赋值(MergeX file) 25 | 26 | # 3.Quick Sort 27 | key: partition切分 28 | improvement:1.n < 8,则使用插入排序 2.中位数作为a[lo] 3.random shuffle 29 | 4.三向快排 30 | ```java 31 | // quicksort the subarray a[lo .. hi] using 3-way partitioning 32 | void sort(Comparable[] a, int lo, int hi) { 33 | if (hi <= lo) return; 34 | int lt = lo, gt = hi; 35 | Comparable v = a[lo]; 36 | int i = lo + 1; 37 | //TODO 小于v的值放在lt左侧 大于v的值放在gt右侧 38 | //TODO 等于v的值在 (lt,i)之间 39 | while (i <= gt) { 40 | int cmp = a[i].compareTo(v); 41 | if (cmp < 0) exch(a, lt++, i++); //a[i] < v 交换a[i]和a[lt] 42 | else if (cmp > 0) exch(a, i, gt--); //a[i] > v 交换a[i]和a[gt] 43 | else i++; 44 | } 45 | 46 | // a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]. 47 | sort(a, lo, lt-1); 48 | sort(a, gt+1, hi); 49 | assert isSorted(a, lo, hi); 50 | } 51 | ``` 52 | 53 | # 4.Priority Queue 54 | key: ordered array实现 或者 unordered array实现 或者 二叉树实现 55 | key2: 二叉树findMax+insert 都是是O(logN) 56 | note: 无法利用缓存 因为数组元素很少直接和相邻元素比较 57 | > heap 58 | key: 父节点序号k,则子节点为2k,2k+. 子节点为k,父节点为k/2 59 | key:sink swim要掌握 60 | ```java 61 | void sort(Comparable[] pq) { 62 | int n = pq.length; 63 | //TODO 构建有序堆 64 | //TODO 相当于从倒数第二层开始遍历到root sink下沉构建 65 | for (int k = n/2; k >= 1; k--) 66 | sink(pq, k, n); 67 | //TODO 当前最大值pq[1]和最后一位交换 + 重新sink剩余(n-1)个元素 68 | while (n > 1) { 69 | exch(pq, 1, n--); 70 | sink(pq, 1, n); 71 | } 72 | } 73 | 74 | void sink(Comparable[] pq, int k, int n) { 75 | while (2*k <= n) { 76 | //TODO k的子节点2k, 2k+1 中val较大的值 == j 77 | int j = 2*k; 78 | if (j < n && less(pq, j, j+1)) j++; 79 | //TODO 不需要交换 则break 80 | if (!less(pq, k, j)) break; 81 | exch(pq, k, j); 82 | k = j; 83 | } 84 | } 85 | ``` 86 | -------------------------------------------------------------------------------- /3_Searching/BinarySearchTree.h: -------------------------------------------------------------------------------- 1 | #ifndef BINARYSEARCHTREE_H_INCLUDED 2 | #define BINARYSEARCHTREE_H_INCLUDED 3 | #include"func.h" 4 | /* 5 | key: Int 6 | val: string 7 | */ 8 | 9 | class BST{ 10 | private: 11 | class Node{ 12 | public: 13 | int key; 14 | string val; 15 | int Size; 16 | Node* left; 17 | Node* right; 18 | Node(int k,string v,int s) 19 | :key(k),val(v),Size(s){ 20 | left=NULL; 21 | right=NULL; 22 | } 23 | }; 24 | Node* root; 25 | public: 26 | BST(){root=NULL;} 27 | int sizeTree(Node* root){if(root==NULL) return 0;else return root->Size;} 28 | int sizeTree(){return sizeTree(root);} 29 | bool isEmpty(){return sizeTree()==0;} 30 | bool contains(int key){ return get(key)!="";} 31 | string get(int key){return get(root,key);} 32 | string get(Node* root,int key){ 33 | if(root->key==key) return root->val; 34 | else if(root->key > key) 35 | return get(root->left,key); 36 | else 37 | return get(root->right,key); 38 | } 39 | //插入新元素 或者 更新val 40 | void put(int key,string val){ 41 | // cout<key == key) 48 | root->val = val; 49 | else if(root->key > key) 50 | root->left = put(root->left,key,val); 51 | else 52 | root->right = put(root->right,key,val); 53 | 54 | root->Size = 1+sizeTree(root->left)+sizeTree(root->right); 55 | return root; 56 | } 57 | //删除极小值 58 | void deleteMin(){root=deleteMin(root);} 59 | Node* deleteMin(Node* root){ 60 | if(root->left==NULL) return root->right; //删除根节点 61 | root->left = deleteMin(root->left); 62 | root->Size = sizeTree(root->left) + sizeTree(root->right); 63 | return root; 64 | } 65 | //删除 66 | void deleteKey(int key){root = deleteKey(root,key);} 67 | Node* deleteKey(Node* root, int key){ 68 | if(root->key > key) 69 | root->left = deleteKey(root->left,key); 70 | else if(root->key < key) 71 | root->right = deleteKey(root->right,key); 72 | else{ 73 | if(root->right==NULL) return root->left; 74 | if(root->left==NULL) return root->right; 75 | //待删除节点 左右子树均不为空 76 | //右子树最小节点替换待删除节点 77 | Node* tmp = root; 78 | root = minLeaf(root->right); //右子树最小节点 79 | root->right = deleteMin(tmp->right); 80 | root->left = tmp->left; 81 | } 82 | } 83 | //寻找最小leaf 84 | Node* minLeaf(Node* root){ 85 | if(root->left==NULL) return root; 86 | else return minLeaf(root->left); 87 | } 88 | vector print(){ 89 | vector BFS; 90 | queue pq; 91 | pq.push(root); 92 | while(!pq.empty()){ 93 | Node* tmp = pq.front(); 94 | pq.pop(); 95 | BFS.push_back(tmp->key); 96 | if(tmp->left!=NULL) 97 | pq.push(tmp->left); 98 | if(tmp->right!=NULL) 99 | pq.push(tmp->right); 100 | } 101 | return BFS; 102 | } 103 | 104 | }; 105 | 106 | 107 | #endif // BINARYSEARCHTREE_H_INCLUDED 108 | -------------------------------------------------------------------------------- /3_Searching/BinarySearchTree_test.cpp: -------------------------------------------------------------------------------- 1 | #include"BinarySearchTree.h" 2 | 3 | int main(){ 4 | BST* bst = new BST(); 5 | std::ostringstream ss; 6 | for(int i=0;i<10;i++){ 7 | ss << i; 8 | bst->put(i,ss.str()); 9 | } 10 | 11 | bst->deleteKey(5); 12 | vector BFS = bst->print(); 13 | for(auto i:BFS) //按照层级输出 14 | cout<无序链表 6 | key: 插入时间O(1) 查找时间O(N) 7 | note: 新元素直接插入链表头部 8 | >有序数组 9 | key:查找使用二分查找 10 | key: 插入时间O(N) 查找时间O(lgN) 11 | note: 插入元素 12 | 13 | # BinarySearchTree 14 | >1.基本实现 15 | get/put 时间复杂度O(1.39lgN) 16 | note: put操作 节点总是最后一层的leaf 17 | note: 随机的数据可能导致树的不平衡 复杂度为1.39lgN 18 | 19 | >2.有序性相关API 20 | flooring 向下取整 21 | 向下取整: tree中的节点 不大于给定查找值key 22 | ceiling 向上取整 23 | select rank 24 | max最后一层最右边的节点 min最后一层最左边的节点 25 | 26 | >3.删除delete 27 | 删除的节点使用其右子树的最小值替换 28 | ```java 29 | private Node delete(Node x, Key key) { 30 | if (x == null) return null; 31 | 32 | int cmp = key.compareTo(x.key); 33 | if (cmp < 0) x.left = delete(x.left, key); 34 | else if (cmp > 0) x.right = delete(x.right, key); 35 | else { 36 | if (x.right == null) return x.left; 37 | if (x.left == null) return x.right; 38 | //TODO 待删除节点x 有左右子树 39 | //TODO min(x.right) x右子树最小节点替换待删除节点x 40 | Node t = x; 41 | x = min(t.right); //min也是寻找最小节点的函数 42 | x.right = deleteMin(t.right);//删掉右子树最小值 43 | x.left = t.left; 44 | } 45 | x.size = size(x.left) + size(x.right) + 1; 46 | return x; 47 | } 48 | ``` 49 | >4. 范围查找 50 | note: 中序遍历的二叉搜索树是有序的; queue; 51 | note: 掌握inorder的递归代码格式 P268 52 | 53 | # BalancedSearchTree 54 | >1. 2-3树 55 | key数目是2, value数目是3(小于,中间,大于) 56 | note: 生长方式=自下而上 57 | 理解 不同情况的下的插入变换方法 58 | 59 | >2. 红黑树 60 | note: 时间复杂度 1.00lgN (对比二叉树),因为红黑树是平衡的 61 | note: 思考:新插入的节点都是红色的 62 | 63 | C++重构 lite版本的 代码链接:https://github.com/ISCASTEAM/Algorithm/tree/master/Tree 64 | 重点: 两种旋转 + 颜色转换 P280 65 | 66 | P275 67 | 各种插入情况 汇总为三句话 68 | *c++插入实现* 69 | ```cpp 70 | RedBlackTree::Node* RedBlackTree::put(Node* h,int key,string val){ 71 | if(h==NULL){ 72 | _size ++; 73 | return new RedBlackTree::Node(key,val,_red); 74 | } 75 | if(h->_key == key) h->_val = val; 76 | else if(h->_key > key) h->left = put(h->left,key,val); 77 | else h->right = put(h->right,key,val); 78 | 79 | //TODO fix-up links 80 | if(isRed(h->right) && !isRed(h->left)) h = rotateLeft(h); 81 | if(isRed(h->left) && isRed(h->left->left))h = rotateRight(h); 82 | if(isRed(h->left) && isRed(h->right)) flipColors(h); 83 | 84 | return h; 85 | } 86 | ``` 87 | 88 | *左右旋转 + 颜色转换* 89 | ```cpp 90 | Node* rotateRight(Node* h){ 91 | Node* tmp = h->left; 92 | h->left = tmp->right; 93 | tmp->right = h; 94 | tmp->color = h->color; 95 | h->color = _red; 96 | return tmp; 97 | } 98 | Node* rotateLeft(Node* h){ 99 | Node* tmp = h->right; 100 | h->right = tmp->left; 101 | tmp->left = h; 102 | tmp->color = h->color; 103 | h->color = _red; 104 | return tmp; 105 | } 106 | void flipColors(Node* h){ 107 | h->color = _red; 108 | h->left->color = _black; 109 | h->right->color = _black; 110 | } 111 | ``` 112 | *BST删除操作 P291* 113 | 114 | 115 | # HashTable 116 | *get put 都是常数时间* 117 | key:散列函数将key转化为数组索引; 处理碰撞冲突 118 | e.g java return (key.hashcode() & 0x7fffffff) % M 119 | note: 缺点 =》 有序性的API无法支持 120 | >1. 拉链法 P297 121 | 相同key,链表串起来val 122 | 123 | >2. 线性探测法 124 | 碰撞发生时,检测下一个位置是否为Null 125 | note: 删除操作,两个方法1.后面非空元素重新put一遍 2.置空NULL + 需要将后面元素前移一位 126 | 127 | 128 | # Application 129 | 思考: 130 | 稀疏矩阵 * vector如何在常数时间内完成 特别是当矩阵非常大时候 131 | P323 132 | -------------------------------------------------------------------------------- /3_Searching/RedBlackTree.h: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | 3 | class RedBlackTree{ 4 | public: 5 | RedBlackTree():_root(NULL),_size(0){}; 6 | string get(int key){ return get(_root,key);} 7 | void put(int key,string val){ 8 | _root = put(_root,key,val); 9 | _root->color = _black; 10 | } 11 | 12 | private: 13 | class Node{ 14 | public: 15 | Node(int key,string val,bool color) 16 | :_key(key),_val(val),color(color){ 17 | left = NULL; 18 | right = NULL; 19 | } 20 | //private: 21 | int _key; 22 | string _val; 23 | Node* left; 24 | Node* right; 25 | bool color; 26 | }; 27 | Node* _root; 28 | int _size; 29 | 30 | string get(Node*,int); 31 | Node* put(Node*,int,string); 32 | 33 | Node* rotateRight(Node* h){ 34 | Node* tmp = h->left; 35 | h->left = tmp->right; 36 | tmp->right = h; 37 | tmp->color = h->color; 38 | h->color = _red; 39 | return tmp; 40 | } 41 | Node* rotateLeft(Node* h){ 42 | Node* tmp = h->right; 43 | h->right = tmp->left; 44 | tmp->left = h; 45 | tmp->color = h->color; 46 | h->color = _red; 47 | return tmp; 48 | } 49 | void flipColors(Node* h){ 50 | h->color = _red; 51 | h->left->color = _black; 52 | h->right->color = _black; 53 | } 54 | bool isRed(Node* x){ 55 | if(x == NULL) return false; 56 | return x->color == _red; 57 | } 58 | int getmin(Node* root){ 59 | int key = -1; 60 | while(root!=NULL){ 61 | key = root->_key; 62 | root = root->left; 63 | } 64 | return key; 65 | } 66 | int getmax(Node* root){ 67 | int key = -1; 68 | while(root!=NULL){ 69 | key = root->_key; 70 | root = root->right; 71 | } 72 | return key; 73 | } 74 | void getKeys(Node* root,queue& res){ 75 | //inorder BFS 76 | if(root==NULL) return; 77 | getKeys(root->left,res); 78 | res.push(root->_key); 79 | getKeys(root->right,res); 80 | } 81 | public: 82 | bool contains(int){ return _size;} 83 | int getsize(){return this->_size;} 84 | int getmin(){ return getmin(_root);} 85 | int getmax(){return getmax(_root);} 86 | void getKeys(queue& res){ return getKeys(_root,res);} 87 | int getRoot(){return _root->_key;} 88 | //each path from root to leaf has the same black number 89 | bool isBalanced(){ 90 | int black = 0; 91 | Node* root = _root; 92 | while(root!=NULL){ 93 | if(!isRed(root)) black++; 94 | root = root->left; 95 | } 96 | return isBalanced(root,black); 97 | } 98 | bool isBalanced(Node* root, int numBlack){ 99 | if(root==NULL) return numBlack==0; 100 | if(isRed(root)) numBlack--; 101 | return isBalanced(root->left,numBlack) &&isBalanced(root,numBlack); 102 | } 103 | protected: 104 | const bool _red = true; 105 | const bool _black = false; 106 | 107 | }; 108 | 109 | string RedBlackTree::get(Node* x, int key){ 110 | while(x != NULL){ 111 | if(x->_key == key) return x->_val; 112 | else if(x->_key > key) return get(x->left,key); 113 | else return get(x->right,key); 114 | } 115 | return NULL; 116 | } 117 | 118 | RedBlackTree::Node* RedBlackTree::put(Node* h,int key,string val){ 119 | if(h==NULL){ 120 | _size ++; 121 | return new RedBlackTree::Node(key,val,_red); 122 | } 123 | if(h->_key == key) h->_val = val; 124 | else if(h->_key > key) h->left = put(h->left,key,val); 125 | else h->right = put(h->right,key,val); 126 | 127 | //TODO fix-up links 128 | if(isRed(h->right) && !isRed(h->left)) h = rotateLeft(h); 129 | if(isRed(h->left) && isRed(h->left->left))h = rotateRight(h); 130 | if(isRed(h->left) && isRed(h->right)) flipColors(h); 131 | 132 | return h; 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /3_Searching/RedBlackTree_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "RedBlackTree.h" 3 | 4 | int main(){ 5 | string test = "ABCDEFG"; 6 | RedBlackTree* rbt = new RedBlackTree(); 7 | for(int i=0;i<7;i++){ 8 | // cout<put(i,string(1,test[i])); 10 | } 11 | cout<<"root="<getRoot()< res; 21 | rbt->getKeys(res); 22 | while(!res.empty()) {cout< marked; 8 | vector edgeto; //父节点 9 | public: 10 | BFSPath(Graph* G){ 11 | marked.resize(G->getV(),false); 12 | edgeto.reserve(G->getV()); 13 | } 14 | 15 | void bfs(Graph* G, int s){ 16 | /* 17 | input: 图结构Graph, 起始点S 18 | */ 19 | queue q; 20 | marked[s] = true; 21 | q.push(s); 22 | 23 | while(!q.empty()){ 24 | int v = q.front(); 25 | q.pop(); 26 | for(int w:G->getadj(v)){ 27 | if(!marked[w]){ 28 | edgeto[w] = v; //区别于BFS代码 29 | marked[w]=true; 30 | q.push(w); 31 | } 32 | } 33 | } 34 | } 35 | //从起始点S到节点V的路径 36 | void pathTo(stack& path,int s,int v){ 37 | for(int i=v;i!=s;i=edgeto[i]) 38 | path.push(i); 39 | path.push(s); 40 | } 41 | 42 | }; 43 | 44 | #endif // BFSPATH_H_INCLUDED 45 | -------------------------------------------------------------------------------- /4_Graphs/BellmanFordSP.h: -------------------------------------------------------------------------------- 1 | #ifndef BELLMANFORDSP_H_INCLUDED 2 | #define BELLMANFORDSP_H_INCLUDED 3 | #include"EdgeWeightedDigraph.h" 4 | /* 5 | 定理: 6 | 1.distTo[S]=0,其他点无穷大。任意顺序relax所有边 7 | 2.1 重复V(顶点个数)轮 则停止 8 | 2.2 edgeTo[]存在负权重环 则停止 9 | 10 | 3.note:优化: 11 | idea: 只有上一轮distTo[]发生变化的顶点指出的边才可能改变其他distTo[]的值,FIFO队列记录这样的顶点 12 | ==》 一轮代表执行一次relax(G,v) ?? 13 | queue1 保存即将被放松的顶点 14 | bool[] 判断顶点是否已经存在于queue1 15 | */ 16 | 17 | class BellmanSP{ 18 | private: 19 | vector distTo; 20 | vector edgeTo; 21 | vector onQ; 22 | queue fifo; //待执行relax的顶点 23 | int relaxCalls; 24 | void relax(EdgeWeightedDigraph* G,int v){ 25 | for(DiEdge e:G->getadj(v)){ 26 | int w = e.to(); 27 | if(distTo[w] > distTo[v]+e.getWeight()){ //注意符号方向 28 | distTo[w] = distTo[v]+e.getWeight(); 29 | edgeTo[w]=e; 30 | //加入queue 31 | if(onQ[w]==false){ 32 | fifo.push(w); 33 | onQ[w]=true; 34 | } 35 | } 36 | if(relaxCalls% G->getV()==0){ 37 | // findNegativeCycle(); //这里我就不实现了 38 | // if(hasNCycle) return; 39 | } 40 | } 41 | } 42 | 43 | public: 44 | BellmanSP(EdgeWeightedDigraph* G){ 45 | edgeTo.resize(G->getV()); 46 | distTo.resize(G->getV(),std::numeric_limits::max()); 47 | onQ.resize(G->getV(),false); 48 | relaxCalls=0; 49 | } 50 | 51 | void getBellmanSP(EdgeWeightedDigraph* G,int s){ 52 | distTo[s]=0.0; 53 | onQ[s]=true; 54 | fifo.push(s); 55 | // while(!fifo.empty() && !hasNegativeCycle()) 56 | while(!fifo.empty()){ 57 | int v=fifo.front(); 58 | fifo.pop(); 59 | onQ[v]=false; 60 | relax(G,v); 61 | } 62 | } 63 | 64 | //其他API 65 | double getdistTo(int v){return distTo[v];} 66 | bool hasPathTo(int v){return distTo[v]::max();} 67 | vector pathTo(int v){ 68 | vector pathRes; 69 | stack path; 70 | if(!hasPathTo(v)) return vector(); 71 | for(DiEdge e=edgeTo[v]; e!=DiEdge();e=edgeTo[e.from()]) 72 | path.push(e); 73 | while(!path.empty()){ 74 | DiEdge e = path.top(); 75 | path.pop(); 76 | pathRes.push_back(e); 77 | } 78 | return pathRes; //未包含起点 79 | } 80 | }; 81 | 82 | 83 | #endif // BELLMANFORDSP_H_INCLUDED 84 | -------------------------------------------------------------------------------- /4_Graphs/DFSCC.h: -------------------------------------------------------------------------------- 1 | #ifndef DFSCC_H_INCLUDED 2 | #define DFSCC_H_INCLUDED 3 | 4 | /*TODO 判断图存在多少个连通分量 5 | 思路: 6 | 所有未标记的节点 执行一遍完整DFS遍历 7 | DFS代表从某一个节点出发 能到达的所有节点都会被标记 8 | */ 9 | #include"Graph.h" 10 | 11 | class DFSCC{ 12 | private: 13 | vector marked; 14 | vector id; //id[v]表示所在连通集的编号 15 | public: 16 | int setCount = 0; 17 | DFSCC(Graph* G){ 18 | marked.reserve(G->getV()); 19 | id.reserve(G->getV()); 20 | } 21 | 22 | void dfs(Graph* G, int v){ 23 | marked[v] = true; 24 | id[v]=setCount; //在DFS代码上添加 25 | for(int w : G->getadj(v)){ 26 | if(!marked[w]) 27 | dfs(G,w); 28 | } 29 | 30 | } 31 | int getSetNum(Graph* G){ 32 | for(int v=0;vgetV();v++){ 33 | if(!marked[v]){ 34 | dfs(G,v); 35 | setCount++; 36 | } 37 | } 38 | return setCount; 39 | } 40 | }; 41 | 42 | #endif // DFSCC_H_INCLUDED 43 | -------------------------------------------------------------------------------- /4_Graphs/DFSDirectedCycle.h: -------------------------------------------------------------------------------- 1 | #ifndef DFSDIRECTEDCYCLE_H_INCLUDED 2 | #define DFSDIRECTEDCYCLE_H_INCLUDED 3 | #include"Digraph.h" 4 | /* 5 | 有向图 判断是否存在有向环 6 | 7 | 不存在环路 topological order算法的前提 8 | */ 9 | 10 | class DFSDirectedCycle{ 11 | private: 12 | vector marked; 13 | vector edgeTo; 14 | vector onstack; 15 | stack cycle; 16 | 17 | public: 18 | DFSDirectedCycle(Digraph* G){ 19 | marked.resize(G->getV(),false); 20 | edgeTo.reserve(G->getV()); 21 | onstack.resize(G->getV(),false); 22 | } 23 | bool hasCycle(Digraph* G){ 24 | for(int v=0;vgetV();v++){ 25 | if(!marked[v] && cycle.empty()) 26 | dfs(G,v); 27 | } 28 | if(cycle.empty()) return false; 29 | else return true; 30 | } 31 | void dfs(Digraph* G,int v){ 32 | marked[v]=true; 33 | onstack[v]=true; 34 | 35 | //正常的dfs流程 36 | for(int w:G->getadj(v)){ 37 | if(!cycle.empty()) return; 38 | else if(!marked[w]){ 39 | edgeTo[w]=v; 40 | dfs(G,w); 41 | } 42 | //判断是否构成环路 43 | else if(onstack[w]){ 44 | for(int tmp=v;tmp!=w;tmp=edgeTo[tmp]) 45 | cycle.push(tmp); 46 | cycle.push(w); //子节点w是环的终点 47 | } 48 | } 49 | 50 | onstack[v]=false; 51 | } 52 | }; 53 | 54 | 55 | #endif // DFSDIRECTEDCYCLE_H_INCLUDED 56 | -------------------------------------------------------------------------------- /4_Graphs/DFSTopo.h: -------------------------------------------------------------------------------- 1 | #ifndef DFSTOPO_H_INCLUDED 2 | #define DFSTOPO_H_INCLUDED 3 | #include"Digraph.h" 4 | #include"EdgeWeightedDigraph.h" 5 | /* 6 | 拓扑排序 DFS+一行代码 7 | 8 | BFS是将入度为零的先加入queue 9 | */ 10 | 11 | class DFSTopo{ 12 | private: 13 | vector marked; 14 | stack reversePost; 15 | 16 | public: 17 | DFSTopo(Digraph* G){ 18 | marked.resize(G->getV(),false); 19 | } 20 | 21 | vector getTopo(Digraph* G){ 22 | for(int v=0;vgetV();v++){ //可能是多连通分量图 23 | if(!marked[v]) 24 | dfs(G,v); 25 | } 26 | 27 | vector res; 28 | while(!reversePost.empty()){ 29 | res.push_back(reversePost.top()); 30 | reversePost.pop(); 31 | } 32 | return res; 33 | } 34 | 35 | void dfs(Digraph* G,int v){ 36 | marked[v] = true; 37 | for(int w:G->getadj(v)){ 38 | if(!marked[w]) 39 | dfs(G,w); 40 | } 41 | reversePost.push(v); 42 | } 43 | 44 | //****************************关于加权Weighted 有向图的重载 45 | DFSTopo(EdgeWeightedDigraph* G){ 46 | marked.resize(G->getV(),false); 47 | } 48 | 49 | vector getTopo(EdgeWeightedDigraph* G){ 50 | for(int v=0;vgetV();v++){ //可能是多连通分量图 51 | if(!marked[v]) 52 | dfs(G,v); 53 | } 54 | 55 | vector res; 56 | while(!reversePost.empty()){ 57 | res.push_back(reversePost.top()); 58 | reversePost.pop(); 59 | } 60 | return res; 61 | } 62 | 63 | void dfs(EdgeWeightedDigraph* G,int v){ 64 | marked[v] = true; 65 | for(DiEdge e:G->getadj(v)){ 66 | if(!marked[e.to()]) 67 | dfs(G,e.to()); 68 | } 69 | reversePost.push(v); 70 | } 71 | }; 72 | #endif // DFSTOPO_H_INCLUDED 73 | -------------------------------------------------------------------------------- /4_Graphs/DiEdge.h: -------------------------------------------------------------------------------- 1 | #ifndef DIEDGE_H_INCLUDED 2 | #define DIEDGE_H_INCLUDED 3 | #include "func.h" 4 | /* 5 | 区别于无向边,v->w == v,w具有固定的含义 6 | API from v to w 7 | */ 8 | class DiEdge{ 9 | private: 10 | int v; 11 | int w; 12 | double weight; 13 | 14 | public: 15 | DiEdge() 16 | :v(0),w(0),weight(0.0){} 17 | DiEdge(int v,int w,double weight) 18 | :v(v),w(w),weight(weight){} 19 | int from()const { return v;} 20 | int to()const {return w;} 21 | double getWeight()const {return weight;} //const成员函数 不改变类对象的内部数据 22 | 23 | friend bool operator<(const DiEdge& a,const DiEdge& b); 24 | friend bool operator>(const DiEdge& a,const DiEdge& b); 25 | friend bool operator==(const DiEdge& a,const DiEdge& b); 26 | friend bool operator!=(const DiEdge& a,const DiEdge& b); 27 | 28 | }; 29 | 30 | bool operator<(const DiEdge& a,const DiEdge& b){ 31 | return a.getWeight() < b.getWeight(); 32 | } 33 | bool operator>(const DiEdge& a,const DiEdge& b){ 34 | return a.getWeight() > b.getWeight(); 35 | } 36 | bool operator==(const DiEdge& a,const DiEdge& b){ 37 | return a.getWeight()==b.getWeight() && a.from()==b.from() && a.to()==b.to(); 38 | } 39 | 40 | bool operator!=(const DiEdge& a,const DiEdge& b){ 41 | return a.getWeight()!=b.getWeight() || a.from()!=b.from() || a.to()!=b.to(); 42 | } 43 | 44 | #endif // DIEDGE_H_INCLUDED 45 | -------------------------------------------------------------------------------- /4_Graphs/Digraph.h: -------------------------------------------------------------------------------- 1 | #ifndef DIGRAPH_H_INCLUDED 2 | #define DIGRAPH_H_INCLUDED 3 | #include "func.h" 4 | 5 | class Digraph{ 6 | private: 7 | int V; 8 | int E; 9 | vector> adj; //邻接链表 10 | void addEdge(int v,int w){ 11 | adj[v].push_back(w); //区别于无向图 12 | } 13 | public: 14 | Digraph(int v):V(v),E(0){adj.resize(v,vector());}; 15 | Digraph(string file){ 16 | std::ifstream infile(file); 17 | string tmp; 18 | int lineNum = 0; 19 | while(std::getline(infile,tmp)){ 20 | std::istringstream iss(tmp); 21 | int v1,v2; 22 | if(lineNum==0) {iss>>V; adj.resize(V,vector());} 23 | else if(lineNum==1) iss>>E; 24 | else { 25 | iss>>v1>>v2; 26 | addEdge(v1,v2); 27 | } 28 | lineNum++; 29 | } 30 | }; 31 | int getV(){return V;} 32 | int getE(){return E;} 33 | int degree(int v){return adj[v].size();} 34 | vector getadj(int v){return adj[v];} 35 | 36 | //反转图 37 | Digraph* reverseG(){ 38 | Digraph* revG = new Digraph(V); 39 | for(int v=0;vaddEdge(w,v); 42 | } 43 | return revG; 44 | } 45 | 46 | }; 47 | 48 | #endif // DIGRAPH_H_INCLUDED 49 | -------------------------------------------------------------------------------- /4_Graphs/DijkstraSP.h: -------------------------------------------------------------------------------- 1 | #ifndef DIJKSTRASP_H_INCLUDED 2 | #define DIJKSTRASP_H_INCLUDED 3 | #include"DiEdge.h" 4 | #include"EdgeWeightedDigraph.h" 5 | /* 6 | 非负权重 有向图 7 | 类似于即时的prim算法 8 | 1.将dist[Start]=0,其他distTo[]初始化为无穷大 9 | 2.重复将distTo[]中最小非树节点V =>relax(G,V) 10 | 3.直到所有顶点都在树或所有非树顶点distTo无限大 11 | */ 12 | 13 | class DijkstraSP{ 14 | private: 15 | vector edgeTo; 16 | vector distTo; 17 | map minPQ; //非树节点vertex和distTo 18 | int getPQmin(){ 19 | double minval = std::numeric_limits::max(); 20 | int key = 0; 21 | for(map::iterator iter=minPQ.begin();iter!=minPQ.end();iter++){ 22 | if(iter->second < minval){ 23 | key = iter->first; 24 | minval = iter->second; 25 | } 26 | } 27 | return key; 28 | } 29 | void erasePQ(int v){ 30 | map::iterator it = minPQ.find(v); 31 | minPQ.erase(it); 32 | } 33 | 34 | //relax 松弛API 35 | void relax(EdgeWeightedDigraph* G,int v){ 36 | for(DiEdge e:G->getadj(v)){ 37 | int v=e.from(); 38 | int w=e.to(); 39 | //w到s的距离更新 40 | if(distTo[v]+e.getWeight() < distTo[w]){ 41 | distTo[w]= distTo[v]+e.getWeight(); 42 | edgeTo[w]=e; 43 | minPQ[w]=distTo[w]; //update or insert 44 | } 45 | } 46 | } 47 | 48 | public: 49 | DijkstraSP(EdgeWeightedDigraph* G,int s){ 50 | edgeTo.resize(G->getV()); 51 | distTo.resize(G->getV(),std::numeric_limits::max()); 52 | } 53 | void getSP(EdgeWeightedDigraph* G,int s){ 54 | distTo[s]=0.0; 55 | minPQ[s]=distTo[s]; 56 | while(!minPQ.empty()){ 57 | int v = getPQmin(); 58 | erasePQ(v); 59 | relax(G,v); 60 | } 61 | } 62 | 63 | //其他API 64 | double getdistTo(int v){return distTo[v];} 65 | bool hasPathTo(int v){return distTo[v]::max();} 66 | vector pathTo(int v){ 67 | vector pathRes; 68 | stack path; 69 | if(!hasPathTo(v)) return vector(); 70 | for(DiEdge e=edgeTo[v]; e!=DiEdge();e=edgeTo[e.from()]) 71 | path.push(e); 72 | while(!path.empty()){ 73 | DiEdge e = path.top(); 74 | path.pop(); 75 | pathRes.push_back(e); 76 | } 77 | return pathRes; //未包含起点 78 | } 79 | }; 80 | #endif // DIJKSTRASP_H_INCLUDED 81 | -------------------------------------------------------------------------------- /4_Graphs/DirectedGraph_test.cpp: -------------------------------------------------------------------------------- 1 | #include"Digraph.h" 2 | #include"DFSDirectedCycle.h" 3 | #include"DFSTopo.h" 4 | 5 | int main(){ 6 | Digraph* G = new Digraph("./data/tinyDAG.txt"); //tinyDAG无环有向图 7 | 8 | //基础测试 9 | cout<getE()<getV()<degree(0)<hasCycle(G)<getTopo(G)) 27 | cout<(const Edge& a,const Edge& b); 34 | friend bool operator==(const Edge& a,const Edge& b); 35 | 36 | }; 37 | 38 | bool operator<(const Edge& a,const Edge& b){ 39 | return a.getWeight() < b.getWeight(); 40 | } 41 | bool operator>(const Edge& a,const Edge& b){ 42 | return a.getWeight() > b.getWeight(); 43 | } 44 | bool operator==(const Edge& a,const Edge& b){ 45 | return a.getWeight() == b.getWeight(); 46 | } 47 | 48 | #endif // EDGE_H_INCLUDED 49 | -------------------------------------------------------------------------------- /4_Graphs/EdgeWeightedDigraph.h: -------------------------------------------------------------------------------- 1 | #ifndef EDGEWEIGHTEDDIGRAPH_H_INCLUDED 2 | #define EDGEWEIGHTEDDIGRAPH_H_INCLUDED 3 | #include"DiEdge.h" 4 | /* 5 | 加权 有向图的定义 6 | */ 7 | class EdgeWeightedDigraph{ 8 | private: 9 | int V; 10 | int E; 11 | vector> adj; 12 | void addEdge(int v,int w,double weight){ 13 | DiEdge tmp(v,w,weight); 14 | adj[v].push_back(tmp); 15 | } 16 | public: 17 | EdgeWeightedDigraph(string file){ 18 | std::ifstream infile(file); 19 | string tmp; 20 | int lineNum = 0; 21 | while(std::getline(infile,tmp)){ 22 | std::istringstream iss(tmp); 23 | int v1,v2; 24 | double weight; 25 | if(lineNum==0) {iss>>V; adj.resize(V,vector());} 26 | else if(lineNum==1) iss>>E; 27 | else { 28 | iss>>v1>>v2>>weight; 29 | addEdge(v1,v2,weight); 30 | } 31 | lineNum++; 32 | } 33 | } 34 | int getV(){return V;} 35 | int getE(){return E;} 36 | int degree(int v){return adj[v].size();} 37 | vector getadj(int v){ return adj[v];} 38 | set getAllEdges(){ 39 | set allEdges; 40 | for(vector tmp:adj){ 41 | for(DiEdge e:tmp){ 42 | allEdges.insert(e); 43 | } 44 | } 45 | return allEdges; 46 | } 47 | }; 48 | 49 | 50 | #endif // EDGEWEIGHTEDDIGRAPH_H_INCLUDED 51 | -------------------------------------------------------------------------------- /4_Graphs/EdgeWeightedGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef EDGEWEIGHTEDGRAPH_H_INCLUDED 2 | #define EDGEWEIGHTEDGRAPH_H_INCLUDED 3 | #include"func.h" 4 | #include"Edge.h" 5 | /* 6 | 实现带带权重的无向图 7 | */ 8 | class EdgeWeightedGraph{ 9 | private: 10 | int V; 11 | int E; 12 | vector> adj; 13 | void addEdge(int v,int w,double weight){ 14 | Edge tmp(v,w,weight); 15 | adj[v].push_back(tmp); 16 | adj[w].push_back(tmp); 17 | } 18 | public: 19 | EdgeWeightedGraph(string file){ 20 | std::ifstream infile(file); 21 | string tmp; 22 | int lineNum = 0; 23 | while(std::getline(infile,tmp)){ 24 | std::istringstream iss(tmp); 25 | int v1,v2; 26 | double weight; 27 | if(lineNum==0) {iss>>V; adj.resize(V,vector());} 28 | else if(lineNum==1) iss>>E; 29 | else { 30 | iss>>v1>>v2>>weight; 31 | addEdge(v1,v2,weight); 32 | } 33 | lineNum++; 34 | } 35 | } 36 | int getV(){return V;} 37 | int getE(){return E;} 38 | int degree(int v){return adj[v].size();} 39 | vector getadj(int v){ return adj[v];} 40 | set getAllEdges(){ 41 | set allEdges; 42 | for(vector tmp:adj){ 43 | for(Edge e:tmp){ 44 | allEdges.insert(e); 45 | } 46 | } 47 | return allEdges; 48 | } 49 | }; 50 | 51 | 52 | #endif // EDGEWEIGHTEDGRAPH_H_INCLUDED 53 | -------------------------------------------------------------------------------- /4_Graphs/Graph.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPH_H_INCLUDED 2 | #define GRAPH_H_INCLUDED 3 | 4 | #include "func.h" 5 | class Graph{ 6 | private: 7 | int V; 8 | int E; 9 | vector> adj; //邻接链表 10 | void addEdge(int v,int w){ 11 | adj[v].push_back(w); 12 | adj[w].push_back(v); 13 | } 14 | public: 15 | Graph(int v):V(v),E(0){adj.resize(v,vector());}; 16 | Graph(string file){ 17 | std::ifstream infile(file); 18 | string tmp; 19 | int lineNum = 0; 20 | while(std::getline(infile,tmp)){ 21 | std::istringstream iss(tmp); 22 | int v1,v2; 23 | if(lineNum==0) {iss>>V; adj.resize(V,vector());} 24 | else if(lineNum==1) iss>>E; 25 | else { 26 | iss>>v1>>v2; 27 | addEdge(v1,v2); 28 | } 29 | lineNum++; 30 | } 31 | }; 32 | int getV(){return V;} 33 | int getE(){return E;} 34 | int degree(int v){return adj[v].size();} 35 | vector getadj(int v){return adj[v];} 36 | 37 | }; 38 | 39 | 40 | #endif // GRAPH_H_INCLUDED 41 | -------------------------------------------------------------------------------- /4_Graphs/KruskalMST.h: -------------------------------------------------------------------------------- 1 | #ifndef KRUSKALMST_H_INCLUDED 2 | #define KRUSKALMST_H_INCLUDED 3 | #include"EdgeWeightedGraph.h" 4 | #include"UnionFind.h" 5 | /* 6 | 克鲁斯卡尔 7 | idea: 不断从所有边中寻找最小值,要求不能构成环路(不在同一个连通集) 8 | note: 相同于不断合并不同的连通分量 9 | note: unionFind数据结构 10 | */ 11 | 12 | class KruskalMST{ 13 | private: 14 | queue result; 15 | double totalWeight; 16 | priority_queue,std::greater> minpq; //初始加入所有边 17 | 18 | public: 19 | KruskalMST(EdgeWeightedGraph* G) 20 | :totalWeight(0.0){ 21 | UnionFind* uf = new UnionFind(G->getV()); 22 | for(Edge e:G->getAllEdges()) 23 | minpq.push(e); 24 | 25 | //生成MST 26 | while(!minpq.empty() && result.size()getV()-1){ 27 | Edge e = minpq.top(); 28 | minpq.pop(); 29 | int v=e.either(); int w=e.other(v); 30 | 31 | //已经在同一个连通集合 32 | if(uf->connected(v,w)) continue; 33 | else{ 34 | uf->unionV(v,w); 35 | result.push(e); 36 | totalWeight += e.getWeight(); 37 | } 38 | } 39 | } 40 | queue getRes(){ return result;} 41 | double getWeight(){return totalWeight;} 42 | 43 | }; 44 | 45 | #endif // KRUSKALMST_H_INCLUDED 46 | -------------------------------------------------------------------------------- /4_Graphs/LazyPrimMST.h: -------------------------------------------------------------------------------- 1 | #ifndef LAZYPRIMMST_H_INCLUDED 2 | #define LAZYPRIMMST_H_INCLUDED 3 | 4 | #include "EdgeWeightedGraph.h" 5 | 6 | /* 7 | 延时删除的prim最小生成树 8 | pre: 图是连通 9 | idea: 随机起点 + 可到达边的最小值加入tree 10 | note: 删除无效边(可达边的两个节点都已经标记) 11 | */ 12 | 13 | class LazyPrimMST{ 14 | private: 15 | queue mst; 16 | double totalWeight; 17 | vector marked; 18 | priority_queue,std::greater> minpq; 19 | 20 | public: 21 | LazyPrimMST(EdgeWeightedGraph* G):totalWeight(0.0){ 22 | marked.resize(G->getV(),false); 23 | } 24 | 25 | queue getMST(EdgeWeightedGraph* G){ 26 | visit(G,0); 27 | while(!minpq.empty()){ 28 | Edge e = minpq.top(); 29 | minpq.pop(); 30 | int v = e.either(); 31 | int w = e.other(v); 32 | if(marked[v] && marked[w]) continue; 33 | //加入最小生成树 34 | mst.push(e); 35 | totalWeight += e.getWeight(); 36 | //visit新顶点 37 | if(!marked[v]) visit(G,v); 38 | else visit(G,w); 39 | } 40 | return mst; 41 | } 42 | 43 | //节点v所有可达边 44 | void visit(EdgeWeightedGraph* G,int v){ 45 | marked[v]=true; 46 | for(Edge e : G->getadj(v)){ 47 | int w = e.other(v); 48 | if(!marked[w]) 49 | minpq.push(e); 50 | } 51 | } 52 | 53 | double getWeight(){ return totalWeight;} 54 | 55 | }; 56 | 57 | #endif // LAZYPRIMMST_H_INCLUDED 58 | -------------------------------------------------------------------------------- /4_Graphs/MinTree_test.cpp: -------------------------------------------------------------------------------- 1 | #include"EdgeWeightedGraph.h" 2 | #include"LazyPrimMST.h" 3 | #include"PrimMST.h" 4 | #include"KruskalMST.h" 5 | 6 | int main(){ 7 | EdgeWeightedGraph* G = new EdgeWeightedGraph("./data/tinyEWG.txt"); //tinyDAG无环有向图 8 | 9 | //基础测试 10 | cout<getE()<getV()<degree(0)< res = mst->getMST(G); 19 | while(!res.empty()){ 20 | Edge e = res.front(); 21 | res.pop(); 22 | cout<实现,保存待遍历的横切边 16 | 17 | 相比较于Lazy模式 indexPQ中的可达边数量是常数级别 18 | */ 19 | 20 | class PrimMST{ 21 | private: 22 | vector edgeTo; 23 | vector distTo; 24 | vector marked; 25 | map indexPQ; 26 | double totalWeight; 27 | 28 | //indexPQ min_val对应的顶点 29 | int getPQmin(){ 30 | double minval = std::numeric_limits::max(); 31 | int key = 0; 32 | for(map::iterator iter=indexPQ.begin();iter!=indexPQ.end();iter++){ 33 | if(iter->second < minval){ 34 | key = iter->first; 35 | minval = iter->second; 36 | } 37 | } 38 | return key; 39 | } 40 | void erasePQ(int v){ 41 | map::iterator it = indexPQ.find(v); 42 | indexPQ.erase(it); 43 | } 44 | 45 | public: 46 | PrimMST(EdgeWeightedGraph* G):totalWeight(0.0){ 47 | edgeTo.resize(G->getV()); //reserve并不会真实开辟空间 48 | distTo.resize(G->getV(),std::numeric_limits::max()); 49 | marked.resize(G->getV(),false); 50 | } 51 | 52 | vector getMST(EdgeWeightedGraph* G){ 53 | distTo[0]=0.0; 54 | indexPQ[0]=0.0; 55 | while(!indexPQ.empty()){ 56 | int v = getPQmin(); //相比较于Lazy模式 indexPQ中的可达边数量是常数级别 57 | totalWeight += indexPQ[v]; 58 | erasePQ(v); 59 | visit(G,v); //最近节点加入树中 60 | } 61 | return edgeTo; 62 | } 63 | 64 | //节点v所有可达边 65 | void visit(EdgeWeightedGraph* G,int v){ 66 | marked[v]=true; 67 | for(Edge e: G->getadj(v)){ 68 | int w = e.other(v); 69 | if(marked[w]) continue; 70 | else if(e.getWeight() >= distTo[w]) continue; 71 | else{ 72 | edgeTo[w] = e; 73 | // cout< getEdgeTo(){ return edgeTo;} 82 | 83 | }; 84 | 85 | #endif // PRIMMST_H_INCLUDED 86 | -------------------------------------------------------------------------------- /4_Graphs/README.md: -------------------------------------------------------------------------------- 1 | 代码链接: 2 | xxxxxxxxxxxx 3 | 4 | # 无向图 5 | Graph.h 实现图的API 邻接链表保存边 6 | DFS BFS的核心代码 7 | >应用 8 | 连通性||单点路径 DFS or BFS 9 | 单点最短路径 BFS 10 | 其它: 11 | 1.连通分量个数 DFS 12 | 2.检测环 DFS 13 | 3.双色问题 DFS 14 | 15 | # 有向图 16 | Digraph.h 实现图的API 邻接链表保存边 17 | >应用 18 | 单点可达性||单点有向路径 DFS orBFS 19 | 单点最短路径 BFS 20 | 其它: 21 | 1.有向环检测 DFS 22 | 2.拓扑排序 DFS+stack 23 | 24 | # 最小生成树 25 | Edge.h 实现有权重边的API 26 | EdgeWeightedGraph.h 实现图的API 27 | >prim 普里姆算法 28 | 所有可达边中选择最小边加入Tree(注意跳过失效边) 29 | 1.延时更新 30 | marked[] 记录顶点已在最小树上 31 | priority_queue记录有效的可达边 32 | lazyPrimMST.h 33 | 2.即时更新 34 | distTo[w]记录w到最小树的距离,跳过Edge.Weight > distTo[w]的顶点 35 | map_indexMin_queue 记录有效横切边 (常数空间大小) 36 | 37 | >kruskal 克鲁斯卡尔算法 38 | 所有边的最小值加入Tree(跳过v,w在同一个连通集的边,即新加入的边不构成环路) 39 | 终止条件: 40 | 所有边都遍历完 或者 MST的边数==G的顶点数目-1 41 | UnionFind数据结构 42 | UF判断Edge 的v,w顶点,从而跳过或者union(v,w) 43 | 44 | # 最短路径 45 | 加权 有向图 46 | DiEdge.h 实现有权重,有方向边的API 47 | EdgeWeightedDigraph.h 实现图的API 48 | >Dijkstra 算法 49 | 前提: 边的权重必须为正 50 | 由起点开始,按照最小distTo[]顺序,relax松弛所有顶点 51 | 终止条件: map map_indexMin_queue为空 52 | 53 | > 拓扑排序 54 | 前提: 无环图 55 | 线性时间解决问题=> 按照topo顺序relax顶点 56 | 拓展: 如何计算最长路径?变换符号 或者取权重相反数 57 | 关键路径定义: 限制优先级问题得到有向图,计算最长路径 58 | 59 | > Bellman-Ford 算法 60 | >基于队列 61 | 前提: 不存在负权重的环 62 | 任意顺序relax顶点,重复V轮 63 | 优化: 一轮意味着执行一次relax? 只有relax才可能导致distTo的变化 64 | queue fifo保存即将被放松的顶点 65 | bool[] 判断顶点是否已经存在于queue 66 | 67 | 应用: 金融套汇问题 =》 换汇的乘积转换为ln求和 =》寻找负权重的环 ==》获利 68 | -------------------------------------------------------------------------------- /4_Graphs/ShortestPath_test.cpp: -------------------------------------------------------------------------------- 1 | #include"DijkstraSP.h" 2 | #include"TopoLongestPath.h" 3 | #include"BellmanFordSP.h" 4 | 5 | int main(){ 6 | EdgeWeightedDigraph* G = new EdgeWeightedDigraph("./data/tinyEWD.txt"); //tinyDAG无环有向图 7 | 8 | //基础测试 9 | cout<getE()<getV()<degree(0)<getSP(G,startV); 19 | cout<<"hasPathTo endVertex="<hasPathTo(endV)<pathTo(endV)){ 22 | cout<getTopoLP(G,startV); 35 | totalW=0.0; 36 | for(DiEdge e:topoLP->pathTo(endV)){ 37 | cout<getBellmanSP(G,startV); 54 | totalW=0.0; 55 | for(DiEdge e:bSP->pathTo(endV)){ 56 | cout< distTo; 21 | vector edgeTo; 22 | void relax(EdgeWeightedDigraph* G,int v){ 23 | for(DiEdge e:G->getadj(v)){ 24 | int w = e.to(); 25 | if(distTo[w] < distTo[v]+e.getWeight()){ //注意符号方向 26 | distTo[w] = distTo[v]+e.getWeight(); 27 | edgeTo[w]=e; 28 | } 29 | } 30 | } 31 | 32 | public: 33 | TopoLP(EdgeWeightedDigraph* G){ 34 | edgeTo.resize(G->getV()); 35 | distTo.resize(G->getV(),std::numeric_limits::min()); //double最小值 36 | } 37 | void getTopoLP(EdgeWeightedDigraph* G,int s){ 38 | distTo[s]=0.0; 39 | DFSTopo* topo_order = new DFSTopo(G); 40 | for(int v:topo_order->getTopo(G)) 41 | relax(G,v); 42 | } 43 | 44 | //其他API 45 | double getdistTo(int v){return distTo[v];} 46 | bool hasPathTo(int v){return distTo[v] > std::numeric_limits::min();} 47 | vector pathTo(int v){ 48 | vector pathRes; 49 | stack path; 50 | if(!hasPathTo(v)) return vector(); 51 | for(DiEdge e=edgeTo[v]; e!=DiEdge();e=edgeTo[e.from()]) 52 | path.push(e); 53 | while(!path.empty()){ 54 | DiEdge e = path.top(); 55 | path.pop(); 56 | pathRes.push_back(e); 57 | } 58 | return pathRes; //未包含起点 59 | } 60 | }; 61 | 62 | #endif // TOPOSHORTESTPATH_H_INCLUDED 63 | -------------------------------------------------------------------------------- /4_Graphs/UndirectedGraph_test.cpp: -------------------------------------------------------------------------------- 1 | #include"Graph.h" 2 | #include"DFSCC.h" 3 | #include"BFSPath.h" 4 | 5 | int initG(){ 6 | std::ifstream infile("./data/tinyG.txt"); 7 | string tmp; 8 | int E,V; 9 | int lineNum = 0; 10 | while(std::getline(infile,tmp)){ 11 | std::istringstream iss(tmp); 12 | int v1,v2; 13 | if(lineNum==0) iss>>E; 14 | else if(lineNum==1) iss>>V; 15 | else iss>>v1>>v2; 16 | lineNum++; 17 | } 18 | } 19 | int main(){ 20 | Graph* G = new Graph("./data/tinyG.txt"); 21 | 22 | //基础测试 23 | cout<getE()<getV()<degree(0)<getSetNum(G)< path; 43 | bfs->bfs(G,0); 44 | bfs->pathTo(path,0,3); 45 | while(!path.empty()){ 46 | cout< parent; 12 | vector sz; 13 | int unionCount; 14 | public: 15 | UnionFind(int vertexNum) 16 | :unionCount(vertexNum){ 17 | parent.resize(vertexNum); 18 | sz.resize(vertexNum,1); 19 | for(int i=0;i& freq){ 23 | priority_queue,std::greater> minPQ; 24 | for(int i=0;i0) 26 | minPQ.push(new Node(i,freq[i],NULL,NULL)); 27 | while(minPQ.size()>=2){ 28 | Node* left = minPQ.top(); 29 | minPQ.pop(); 30 | Node* right = minPQ.top(); 31 | minPQ.pop(); 32 | Node* parent = new Node('\0',left->freq+right->freq, 33 | left,right); 34 | minPQ.push(parent); 35 | } 36 | Node* root = minPQ.top(); 37 | minPQ.pop(); 38 | return root; 39 | } 40 | void buildCode(vector& st,Node* root,string s){ 41 | if(!root->isLeaf()){ 42 | buildCode(st,root->left,s+"0"); 43 | buildCode(st,root->right,s+"1"); 44 | }else{ 45 | st[(int)root->getVal()]=s; 46 | } 47 | 48 | } 49 | 50 | public: 51 | vector st; 52 | Huffman(){st.resize(R,"");} 53 | int getR(){return R;} 54 | 55 | void compress(string s){ 56 | //1.统计字符频率 57 | vector freq(R,0); 58 | for(char c:s) 59 | freq[c]++; 60 | 61 | //2.构建huffman trie tree 62 | Node* root = buildTrie(freq); 63 | 64 | //3.构建编译表 65 | buildCode(st,root,""); 66 | } 67 | /* encode compress 68 | 前提: 已经得到Huffman编译表 69 | 这里简单的将"|"作为分隔符 70 | */ 71 | string encodeStr(string str){ 72 | string ans=""; 73 | for(char c:str) 74 | ans += st[c]+"|"; 75 | return ans; 76 | } 77 | 78 | }; 79 | 80 | 81 | #endif // HUFFMAN_H_INCLUDED 82 | -------------------------------------------------------------------------------- /5_Strings/Huffman_test.cpp: -------------------------------------------------------------------------------- 1 | #include"Huffman.h" 2 | 3 | int main(){ 4 | string test = "ABRACADABRA!"; 5 | cout<<"test string= "<compress(test); 9 | cout<<"after compressing:"<encodeStr(test)<getR();i++) 15 | if(hf->st[i]!="") 16 | cout<<(char)i<<" "<st[i]<& a,int i,int j){ 22 | string tmp = a[i]; 23 | a[i]=a[j]; 24 | a[j]=tmp; 25 | } 26 | //高位优先形式 对dth位置字符三向切分 27 | void quick3string(vector& a,int lo,int hi,int d){ 28 | if(lo>= hi) return; 29 | int lt=lo; 30 | int gt=hi; 31 | int i=lo+1; 32 | int v=charAt(a[lo],d); 33 | while(i<=gt){ 34 | int tmp = charAt(a[i],d); 35 | if(tmp < v) swap(a,lt++,i++); 36 | else if(tmp > v) swap(a,i,gt--); 37 | else i++; 38 | } 39 | 40 | //a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]. 41 | quick3string(a,lo,lt-1,d); 42 | if(v>=0) quick3string(a,lt,gt,d+1); 43 | quick3string(a,gt+1,hi,d); 44 | } 45 | public: 46 | void vectorStrSort(vector& a){ 47 | quick3string(a,0,a.size()-1,0); 48 | } 49 | }; 50 | 51 | #endif // QUICK3STRING_H_INCLUDED 52 | -------------------------------------------------------------------------------- /5_Strings/Quick3String_test.cpp: -------------------------------------------------------------------------------- 1 | #include"Quick3string.h" 2 | /* 3 | 字符串数组排序 4 | 5 | LGD or MGD or quick3string 适用情况 P471 6 | 当字符串具有公共前缀时 三向快速排序更合适 7 | quick3string 更加通用 8 | 9 | note: 10 | 剩余15个字符可以使用插入排序 11 | */ 12 | 13 | 14 | int main(){ 15 | vector a; 16 | a.push_back("abb2"); 17 | a.push_back("aab1"); 18 | a.push_back("abb6"); 19 | a.push_back("abc5"); 20 | Quick3string* q3s = new Quick3string(); 21 | q3s->vectorStrSort(a); 22 | 23 | for(auto i:a) 24 | cout<低位优先 3 | 缺点: 4 | 字符串要求相同长度 5 | >高位优先 6 | > 三向快排排序 7 | 思路:高位优先的,递归排序。之间相等部分去掉首字符继续递归 8 | note: 9 | 大量具有公共前缀的字符串数组的排序 10 | 11 | //这两部分 我理解比较困难,实现复杂 12 | //我就跳过了 13 | # 单词查找树 14 | # 子串搜索 15 | 16 | # 正则表达式 17 | 18 | # 数据压缩 19 | 只讨论无损压缩 20 | >Huffman编码 21 | 已实现 22 | >LZW压缩 23 | 我没看 24 | -------------------------------------------------------------------------------- /6_Context/FlowEdge.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOWEDGE_H_INCLUDED 2 | #define FLOWEDGE_H_INCLUDED 3 | 4 | #include"func.h" 5 | /* 6 | maxFlow最大流问题 7 | 相比较无向图Edge,添加两个变量和两个API 8 | */ 9 | 10 | class FlowEdge{ 11 | private: 12 | int V; //边的起点 13 | int W; 14 | double capacity; 15 | double flow; //实际流量 16 | 17 | public: 18 | FlowEdge():V(0),W(0),capacity(0.0){} 19 | FlowEdge(int v,int w,double c) 20 | :V(v),W(w),capacity(c),flow(0.0){} 21 | 22 | //边的剩余容量 传入参数是边的enpoint 23 | double residualCapacityTo(int vertex){ 24 | if(vertex==V) return flow; //backward edge 25 | else if(vertex==W) return capacity-flow; //forward edge 26 | return (double)-1; 27 | } 28 | //增加流量 传入参数是边的终点 29 | void addResidualFlowTo(int vertex, double delta){ 30 | if(vertex==V) flow -= delta; //反向边 31 | else if(vertex==W) flow+=delta; //正向边 32 | } 33 | 34 | //其它API 35 | int from()const {return V;} 36 | int to()const {return W;} 37 | double getCapacity()const {return capacity;} 38 | double getFlow(){return flow;} 39 | int other(int vertex){ 40 | if(vertex==V) return W; 41 | if(vertex==W) return V; 42 | return -1; 43 | } 44 | void setFlow(double delta){flow += delta;} 45 | bool operator==(const FlowEdge& that){return V==that.from() && W==that.to() && capacity==that.getCapacity();} 46 | }; 47 | 48 | #endif // FLOWEDGE_H_INCLUDED 49 | -------------------------------------------------------------------------------- /6_Context/FlowFordFulkerson.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOWFORDFULKERSON_H_INCLUDED 2 | #define FLOWFORDFULKERSON_H_INCLUDED 3 | #include"FlowNetwork.h" 4 | /* 5 | Ford-Fulkerson方法 6 | 1.BFS判断剩余网络中是否存在 7 | 2.直到增广路径不存在 8 | 9 | 增广路径: 能从s到达t,路径上正向边不饱和而且反向边非零 10 | */ 11 | 12 | class FlowFordFulkerson{ 13 | private: 14 | vector marked; 15 | vector edgeTo; 16 | double totalVal; 17 | //BFS判断s到t是否存在增广路径 18 | bool hasAugmentingPath(FlowNetwork*G,int s,int t){ 19 | edgeTo.assign(G->getV(),FlowEdge()); 20 | marked.assign(G->getV(),false); 21 | queue pq; 22 | pq.push(s); 23 | marked[s]=true; 24 | 25 | while(!pq.empty() && !marked[t]){ 26 | int v = pq.front(); 27 | pq.pop(); 28 | for(FlowEdge e : G->getadj(v)){ 29 | int w = e.other(v); 30 | //v->w边存在剩余容量则是非饱和边 31 | if(e.residualCapacityTo(w)>0 && !marked[w]){ 32 | edgeTo[w]=e; 33 | marked[w]=true; 34 | pq.push(w); 35 | } 36 | } 37 | } 38 | return marked[t]; //增广路径能否遍历到t 39 | } 40 | 41 | public: 42 | FlowFordFulkerson(FlowNetwork* G){ 43 | marked.resize(G->getV(),false); 44 | edgeTo.resize(G->getV()); 45 | totalVal=0.0; 46 | } 47 | void calMaxFlow(FlowNetwork* G,int s,int t){ 48 | totalVal = 0.0; 49 | while(hasAugmentingPath(G,s,t)){ 50 | double delta = std::numeric_limits::max(); 51 | //edgeTo增广路径中的最小可增加的流量 52 | for(int v=t;v!=s;v=edgeTo[v].other(v)){ 53 | delta = std::min(delta,edgeTo[v].residualCapacityTo(v)); 54 | } 55 | //对于路径上每条边增加流量 56 | for(int v=t;v!=s;v=edgeTo[v].other(v)){ 57 | // edgeTo[v].addResidualFlowTo(v,delta); //由于java里面传递引用,需要C++稍作变化 58 | G->addResidualFlowTo(edgeTo[v],v,delta); 59 | } 60 | 61 | totalVal += delta; 62 | } 63 | } 64 | double getMaxFlow(){return totalVal;} 65 | }; 66 | 67 | #endif // FLOWFORDFULKERSON_H_INCLUDED 68 | -------------------------------------------------------------------------------- /6_Context/FlowNetwork.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOWNETWORK_H_INCLUDED 2 | #define FLOWNETWORK_H_INCLUDED 3 | #include"FlowEdge.h" 4 | /* 5 | 由FlowEdge构成的图 和无向图的结构相同 6 | */ 7 | 8 | class FlowNetwork{ 9 | private: 10 | int V; //顶点个数 11 | int E; //边的个数 12 | vector> adj; 13 | void addEdge(int v,int w,double capacity){ 14 | adj[v].push_back(FlowEdge(v,w,capacity)); 15 | adj[w].push_back(FlowEdge(v,w,capacity)); 16 | } 17 | 18 | public: 19 | FlowNetwork(int v,int e) 20 | :V(v),E(e){ 21 | adj.resize(v,vector()); 22 | } 23 | FlowNetwork(string file){ 24 | std::ifstream infile(file); 25 | string tmp; 26 | int lineNum = 0; 27 | while(std::getline(infile,tmp)){ 28 | std::istringstream iss(tmp); 29 | int v1,v2; 30 | double capacity; 31 | if(lineNum==0) {iss>>V; adj.resize(V,vector());} 32 | else if(lineNum==1) iss>>E; 33 | else { 34 | iss>>v1>>v2>>capacity; 35 | // cout< getadj(int v){return adj[v];} 46 | void addResidualFlowTo(FlowEdge& e,int v,double delta){ //传入参数V是边的endPoint 47 | for(vector& i:adj){ 48 | for(FlowEdge& j:i){ 49 | if(j==e){ 50 | if(j.from()==v) j.setFlow(-delta); //backward Edge 51 | else if(j.to()==v) j.setFlow(delta); //forward Edge 52 | } 53 | } 54 | } 55 | } 56 | }; 57 | 58 | 59 | #endif // FLOWNETWORK_H_INCLUDED 60 | -------------------------------------------------------------------------------- /6_Context/README.md: -------------------------------------------------------------------------------- 1 | # 事件驱动的粒子碰撞 2 | 3 | # B-树 4 | 查找成本很低 需要空间大 5 | 6 | # 后缀数组 7 | 字符串的子串中最长的公共前缀问题 8 | 思路: 9 | 排序的后缀数组,最长的公共前缀在相邻的位置出现 10 | 11 | # 最大流 12 | 给定有向图找出满足平衡的最大流 13 | 思路: 14 | 剩余网络中不存在从S到T的增广路径 15 | (将增广路径所有边 add最小边的可增加容量) 16 | 17 | 跳过 18 | # 归约问题 19 | # 不可解性 20 | -------------------------------------------------------------------------------- /6_Context/SuffixArray.h: -------------------------------------------------------------------------------- 1 | #ifndef SUFFIXARRAY_H_INCLUDED 2 | #define SUFFIXARRAY_H_INCLUDED 3 | #include"func.h" 4 | #include"Quick3String.h" 5 | //连续字符 子字符串 6 | //非连续字符 子序列 7 | 8 | /* 9 | 问题: string至少重复两次的最长子串 10 | 后缀数组 11 | idea: sorted 后缀数组最长重复子串在相邻位置 12 | 13 | API: 14 | i 已排序的后缀数组的元素序号 15 | 1.select(i) 已排序的后缀数组第i元素 16 | 2.index(i) select(i)在原有的后缀数组序号 17 | 3.lcp(i) select(i)和select(i-1)的最长公共前缀长度 18 | 4.rank(string key) 小于key的字符串的数量 19 | */ 20 | 21 | class SuffixArray{ 22 | private: 23 | vector suffixes; 24 | int N; 25 | int lcp(string str1,string str2){ //两个字符串的最长公共前缀 26 | int len = std::min(str1.size(),str2.size()); 27 | for(int i=0;ivectorStrSort(suffixes); 41 | } 42 | int lcp(int i){ 43 | return lcp(suffixes[i],suffixes[i-1]); 44 | } 45 | //不断比较相邻的两个字符串的公共前缀长度 46 | string getLRS(){ 47 | string longReaptedStr=""; 48 | for(int i=1;i<(int)suffixes.size();i++){ 49 | int len = lcp(i); 50 | //更新 lrs 51 | if((int)longReaptedStr.size() < len) 52 | longReaptedStr = suffixes[i].substr(0,len); 53 | } 54 | return longReaptedStr; 55 | } 56 | 57 | int rankSuffix(string key){ 58 | //二分查找 59 | int lo=0; 60 | int hi=N-1; 61 | while(lo <= hi){ 62 | int mid=lo+(hi-lo)/2; 63 | if(key == suffixes[mid]) 64 | return mid; 65 | else if(key < suffixes[mid]) 66 | hi = mid-1; 67 | else 68 | lo = mid+1; 69 | } 70 | return lo; 71 | } 72 | 73 | //其它API 74 | vector getSuffix(){ return suffixes;} 75 | int length(){return N;} 76 | string select(int i){return suffixes[i];} 77 | int index(int i){return N-select(i).size();} 78 | 79 | }; 80 | 81 | #endif // SUFFIXARRAY_H_INCLUDED 82 | -------------------------------------------------------------------------------- /6_Context/SuffixArray_test.cpp: -------------------------------------------------------------------------------- 1 | #include"SuffixArray.h" 2 | 3 | int main(){ 4 | string test = "aacaagtttacaagc"; 5 | string longReaptedStr = ""; 6 | SuffixArray* sfa = new SuffixArray(test); 7 | 8 | // for(auto i : sfa->getSuffix()) 9 | // cout<getLRS()< test={5,4,-1,2,7}; 11 | //2. 调用算法 12 | Insertion::insort(test); 13 | for(auto i:test) 14 | cout< 背包,队列,栈 22 | > 连通集 UnionFind.h 23 | 24 | *排序* 25 | > 初级排序 Insertion.h 26 | > 归并排序 27 | > 三向快速排序 Quick3way.h 28 | > 优先队列 HeapSort.h 29 | 30 | *查找* 31 | > 符号表 32 | > 二叉树 BinarySearchTree.h 33 | > 平衡二叉树 RedBlackTree.h 34 | > 散列表 35 | 36 | *图* 37 | > 无向图 Edge.h Graph.h 38 | 1.图连通集数量 DFSCC.h 39 | 2.单点最短路径 BFSPath.h 40 | > 有向图 DiEdge.h DiGraph.h 41 | 1.环路判断 DFSDirectedCycle.h 42 | 2.拓扑排序 DFSTopo.h 43 | > 最小生成树 DiEdge.h EdgeWeightedGraph.h 44 | 1.延时Prim算法 LazyPrimMST.h 45 | 2.即时Prim算法 PrimMST.h 46 | 3.Kruskal算法 KruskalMST.h 47 | >最短路径 DiEdge.h EdgeWeightedDiGraph.h 48 | 1.Dijkstra算法 DijkstraSP.h 49 | 2.无环图Topo最长路径 TopoLongestPath.h 50 | 3.Bellman-Ford算法 BellmanFordSP.h 51 | 52 | *字符串* 53 | > 字符串数组排序 Quick3String.h 54 | > 单词查找树 55 | > 子串查找 56 | > 正则表达式 57 | > 数据压缩 Huffman.h 58 | 59 | *背景* 60 | > 粒子碰撞 61 | > B-树 62 | > 后缀数组 SuffixArray.h 63 | > 网络最大流问题 FlowEdge.h FlowNetWork.h FlowFordFulkerson.h 64 | > 归约问题 65 | > 不可解性 66 | 67 | # 引用 68 | *Algorithm 4th Edition* 69 | Author: Robert SedgeWick and Kevin Wayne 70 | [Website:](https://algs4.cs.princeton.edu/home/) https://algs4.cs.princeton.edu/home/ 71 | -------------------------------------------------------------------------------- /func.h: -------------------------------------------------------------------------------- 1 | #ifndef __FUNC_H__ 2 | #define __FUNC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | using std::cout; 21 | using std::endl; 22 | using std::string; 23 | using std::stack; 24 | using std::vector; 25 | using std::set; 26 | using std::multiset; 27 | using std::map; 28 | using std::stringstream; 29 | using std::unordered_map; 30 | using std::queue; 31 | using std::priority_queue; 32 | #endif // __FUNC__ 33 | --------------------------------------------------------------------------------