├── CMakeLists.txt ├── README.md ├── img └── wechat.jpg └── 玩转儿数据结构 ├── array ├── array.cpp └── array.h ├── avl └── AVL.h ├── binarySearch ├── BinarySearch.cpp └── floor_ceil_BinarySearch.cpp ├── bst ├── BST.cpp ├── BST.h └── SequenceST.h ├── file ├── FileOps.h ├── communist.txt └── pride-and-prejudice.txt ├── hash ├── hahshMain.cpp ├── hash.h ├── hashMain_v2.cpp └── hash_v2.h ├── heap ├── 347_local.cpp ├── 347topKFrequent.cpp ├── PriorityQueue.h ├── README.md ├── heap.cpp └── heap.h ├── interface.h ├── linklist ├── 203ListNode.cpp ├── LinkedList.cpp └── LinkedList.h ├── queue ├── ArrayQueue.h ├── LinkedListQueue.h └── loopQueue.h ├── rbtree ├── rb_tree.h └── rbmain.cpp ├── recursion ├── 203ListNode.cpp ├── recursion.cpp └── recursion.png ├── segmenttree ├── 303NumArray.cpp ├── 307NumArray.cpp ├── README.md ├── segment.cpp └── segment.h ├── set_map ├── 804uniqueMorseRepresentations.cpp ├── BSTMap.h ├── BSTSet.h ├── LinkedListMap.h ├── LinkedListSet.h ├── SeqMap.h └── SeqSet.h ├── stack ├── 20isValid.cpp ├── ArrayStack.h └── LinkedListStack.h ├── test └── Tmain.cpp ├── trie ├── 211WordDictionary.cpp ├── 677MapSum.cpp ├── README.md ├── trie.cpp └── trie.h └── unionfind ├── README.md ├── unionfind.cpp └── unionfind.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(alg) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread") 6 | 7 | add_executable(array 玩转儿数据结构/array/array.cpp) 8 | add_executable(Tmain 玩转儿数据结构/test/Tmain.cpp) 9 | add_executable(trie 玩转儿数据结构/trie/trie.cpp) 10 | add_executable(677MapSum 玩转儿数据结构/trie/677MapSum.cpp) 11 | add_executable(211WordDictionary 玩转儿数据结构/trie/211WordDictionary.cpp) 12 | add_executable(203ListNode 玩转儿数据结构/linklist/203ListNode.cpp) 13 | add_executable(recursion 玩转儿数据结构/recursion/recursion.cpp) 14 | add_executable(BST 玩转儿数据结构/bst/BST.cpp) 15 | add_executable(hahshMain 玩转儿数据结构/hash/hahshMain.cpp) 16 | add_executable(347_local 玩转儿数据结构/heap/347_local.cpp) 17 | add_executable(347topKFrequent 玩转儿数据结构/heap/347topKFrequent.cpp) 18 | add_executable(heap 玩转儿数据结构/heap/heap.cpp) 19 | add_executable(LinkedList 玩转儿数据结构/linklist/LinkedList.cpp) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 0.导语 2 | 3 | 本仓库学习自波波老师的慕课网课程《玩转儿数据结构》,由于官方为JAVA版本,但是本人用的C++,因此将自己的C++笔记放到下面。 4 | 5 | 课程链接: 6 | 7 | > https://coding.imooc.com/class/207.html 8 | 9 | 后面将更新波波老师的其他课程学习笔记。 10 | 11 | 编写的程序采用C++,如果觉得自己C++需要提高,可以看我的另一个仓库:《C++那些事》。 12 | 13 | > https://github.com/Light-City/CPlusPlusThings 14 | 15 | 内容包括了基础与进阶,等等! 16 | 17 | ## 0.开发环境 18 | 19 | 开发环境**Ubuntu18.04+Clion** 20 | 21 | > 如何运行你的程序? 22 | 23 | 添加cpp文件到CmakeLists.txt中,示例: 24 | 25 | ``` 26 | add_executable(LinkedList 玩转儿数据结构/linklist/LinkedList.cpp) 27 | ``` 28 | 29 | ## 1.玩转数据结构 从入门到进阶C++版 30 | 31 | - 动态数组 32 | 33 | - [动态数组实现](./玩转儿数据结构/array/array.h) 34 | - [动态数组测试](./玩转儿数据结构/array/array.cpp) 35 | 36 | 学习要点:动态数组的增删改查、时间复杂度、防止复杂度震荡策略。 37 | 38 | - 栈和队列 39 | 40 | - 栈 41 | 42 | - [栈的公共接口](./玩转儿数据结构/interface.h) 43 | - [基于底层为动态数组的栈实现](./玩转儿数据结构/stack/ArrayStack.h) 44 | - [基于底层为链表的栈实现](./玩转儿数据结构/stack/LinkedListStack.h) 45 | - [栈的测试](./玩转儿数据结构/test/Tamin.cpp) 46 | - [LeetCode20题](./玩转儿数据结构/stack/20isValid.cpp) 47 | 48 | 学习要点:使用组合方案来完成栈的底层数据结构为数组,定义栈的入栈与出队策略。 49 | 50 | - 队列 51 | 52 | - [队列的公共接口](./玩转儿数据结构/interface.h) 53 | - [基于底层为动态数组的队列实现](./玩转儿数据结构/queue/ArrayQueue.h) 54 | - [基于底层为动态数组的循环队实现](./玩转儿数据结构/queue/loopQueue.h/) 55 | - [基于底层为链表的队列实现](./玩转儿数据结构/stack/LinkedListQueue.h) 56 | - [队列的测试](./玩转儿数据结构/test/Tamin.cpp) 57 | 58 | 学习要点:多种底层实现的效率对比,接口的定义,定义队列的入队与出队策略。 59 | 60 | - 链表 61 | 62 | - [链表的实现](./玩转儿数据结构/linklist/LinkedList.h) 63 | - [链表栈实现](./玩转儿数据结构/stack/LinkedListStack.h) 64 | - [链表队列实现](./玩转儿数据结构/stack/LinkedListQueue.h) 65 | - [链表、链表栈、链表队列实现](./玩转儿数据结构/linklist/LinkedList.cpp) 66 | - [LeetCode203题不带与带dummyHead两种实现](./玩转儿数据结构/linklist/203ListNode.cpp) 67 | - [LeetCode203题递归实现](./玩转儿数据结构/recursion/203ListNode.cpp) 68 | - [求和递归实现](./玩转儿数据结构/recursion/recursion.cpp) 69 | 70 | 学习要点:链表内部节点结构定义、dummyHead使用、时间复杂度分析、链表栈与链表队列实现。z掌握递归的宏观与微观、如何对递归进行测试。 71 | 72 | - 二分搜索树 73 | 74 | - [二分搜索树实现](./玩转儿数据结构/bst/BST.h) 75 | 76 | - [二分搜索树测试](./玩转儿数据结构/bst/BST.cpp) 77 | 78 | - 补充 79 | - [顺序查找表实现](./玩转儿数据结构/bst/SequenceST.h) 80 | - [二分查找法实现](./玩转儿数据结构/binarySearch/BinarySearch.cpp) 81 | - [基于floor与ceil的二分查找法实现](./玩转儿数据结构/binarySearch/floor_ceil_BinarySearch.cpp) 82 | 83 | 84 | 85 | 学习要点:掌握二分搜索树的结构、四种遍历方式的递归与非递归,bst树中最大与最小节点,删除节点原则,拓展二分查找法与基于floo、ceil的实现,当bst树退化为链表的时候对应的顺序查找表实现,顺序查找表与二分搜索树的效率对比。 86 | 87 | - 集合与映射 88 | 89 | - 集合 90 | 91 | - [集合接口](./玩转儿数据结构/interface.h) 92 | - [基于底层为二分搜索树的集合](./玩转儿数据结构/set_map/BSTSet.h) 93 | - [基于底层为链表的集合](./玩转儿数据结构/set_map/LinkedListSet.h) 94 | - [LeetCode804问题](./玩转儿数据结构/set_map/804uniqueMorseRepresentations.cpp) 95 | - 拓展 96 | - [基于底层为顺序查找表的集合](./玩转儿数据结构/set_map/SeqSet.h) 97 | 98 | 学习要点:集合接口定义、二分搜索树与链表集合的效率对比。 99 | 100 | - 映射 101 | 102 | - [映射接口](./玩转儿数据结构/interface.h) 103 | - [基于底层为二分搜索树的映射](./玩转儿数据结构/set_map/BSTMap.h) 104 | - [基于底层为链表的映射](./玩转儿数据结构/set_map/LinkedListSet.h) 105 | - [LeetCode804问题](./玩转儿数据结构/set_map/804uniqueMorseRepresentations.cpp) 106 | - 拓展 107 | - [基于底层为顺序查找表的映射](./玩转儿数据结构/set_map/LinkedListMap.h) 108 | 109 | 学习要点:映射接口定义、二分搜索树与链表映射的效率对比。学会什么时候用映射,什么时候用集合。 110 | 111 | - 优先队列和堆 112 | 113 | - [基于动态数组的大顶堆实现](./玩转儿数据结构/heap/heap.h) 114 | - [基于底层为大顶堆的优先队列实现](./玩转儿数据结构/heap/PriorityQueue.h) 115 | - [大顶堆与优先队列测试](./玩转儿数据结构/heap/heap.cpp) 116 | - [使用C++ STL的优先队列解LeetCode347题](./玩转儿数据结构/347topKFrequent.cpp) 117 | - [使用我们自己的优先队列解LeetCode347题](./玩转儿数据结构/347_local.cpp) 118 | 119 | 学习要点:堆的sift up与sift down、heapify、堆与优先队列的关系、如何使用STL的大顶堆与小顶堆、如何使用自己的优先队列解题。 120 | 121 | - 线段树 122 | 123 | - [基于动态数组的线段树实现](./玩转儿数据结构/segmenttree/segment.h) 124 | - [线段树测试](./玩转儿数据结构/segmenttree/segment.cpp) 125 | - [LeetCode303题](./玩转儿数据结构/segmenttree/303NumArray.cpp) 126 | - [LeetCode307题](./玩转儿数据结构/segmenttree/307NumArray.cpp) 127 | 128 | 学习要点:掌握线段树的概念与应用,经典应用区间更新查询等,学会使用动态数组作为线段树的底层数据结构,掌握开辟多大空间存储。掌握其不是完全二叉树也不是满二叉树,但是平衡二叉树,依然可以用数组表示,看做满二叉树,后面不存在的节点在数组中用空来表示即可。 129 | 130 | - 字典树 131 | 132 | - [字典树的实现](./玩转儿数据结构/trie/trie.h) 133 | - [LeetCode211题](./玩转儿数据结构/trie/211WordDictionary.cpp) 134 | - [LeetCode677题](./玩转儿数据结构/trie/677MapSum.cpp) 135 | 136 | 学习要点:掌握字典树节点定义,学会使用自己的字典树解题。 137 | 138 | - 并查集 139 | 140 | - [基于动态数组的并查集六种实现](./玩转儿数据结构/unionfind/unionfind.h) 141 | - [并查集测试](./玩转儿数据结构/unionfind/unionfind.cpp) 142 | 143 | 学习要点:quickfind、基于树高度优化的并查集、基于树的大小(只是当前父亲节点+孩子节点总数)优化、基于rank(树的深度)的优化、路径压缩1、路径压缩2。 144 | 145 | - 平衡树AVL 146 | 147 | - [AVL实现](./玩转儿数据结构/avl/AVL.h) 148 | - [AVL测试](./玩转儿数据结构/test/Tmain.cpp) 149 | 150 | 学习要点:左旋转、右旋转、平衡因子维护等。 151 | 152 | - 红黑树 153 | 154 | - [红黑树实现](./玩转儿数据结构/rbtree/rb_tree.h) 155 | - [红黑树测试](./玩转儿数据结构/rbtree/rbmain.cpp) 156 | 157 | 学习要点:红黑树节点颜色标记、左旋转、右旋转、颜色翻转、插入节点颜色调整。 158 | 159 | - 哈希表 160 | 161 | - [简单的哈希表](./玩转儿数据结构/hash/hash.h) 162 | - [简单的哈希表测试](./玩转儿数据结构/hash/hashMain.cpp) 163 | - [素数哈希函数的哈希表](./玩转儿数据结构/hash/hash_v2.h) 164 | - [素数哈希函数的哈希表测试](./玩转儿数据结构/hash/hashMain_v2.cpp) 165 | 166 | 学习要点:哈希表动态扩容、哈希函数定义等。 167 | 168 | 169 | ## 2.其他 170 | 171 | 待更新。。。 172 | 173 | ## 关于作者 174 | 175 | 个人公众号:【guangcity】 176 | 177 | 178 | 179 | ![wechat](./img/wechat.jpg) 180 | 181 | 个人博客:http://light-city.club/ 182 | 183 | QQ:455954986 184 | -------------------------------------------------------------------------------- /img/wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Light-City/algPratice/6d8e37673549845d8d4e5ab8a05780bc77013ce7/img/wechat.jpg -------------------------------------------------------------------------------- /玩转儿数据结构/array/array.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-31. 3 | // 4 | 5 | #include "array.h" 6 | 7 | class Student { 8 | private: 9 | string name; 10 | int score; 11 | public: 12 | Student(string name = "", int score = 0) { 13 | this->name = name; 14 | this->score = score; 15 | } 16 | 17 | friend ostream &operator<<(ostream &out, Student &student) { 18 | out << "name : " << student.name << ", " << " score : " << student.score; 19 | return out; 20 | } 21 | 22 | bool operator==(const Student &student) { 23 | return this->name == student.name && this->score == student.score; 24 | } 25 | }; 26 | 27 | class A { 28 | private: 29 | string name; 30 | int age; 31 | 32 | void init(string name, int age) { 33 | this->name = name; 34 | this->age = age; 35 | } 36 | 37 | public: 38 | A(string name, int age) { 39 | init(name, age); 40 | } 41 | 42 | A() { 43 | init("bob",20); 44 | } 45 | 46 | void print() { 47 | cout << name << " " << age << endl; 48 | } 49 | // ... 50 | // ... 51 | }; 52 | 53 | 54 | // 测试文件 55 | int main() { 56 | Array array; 57 | 58 | for (int i = 0; i < 10; i++) array.addLast(i); 59 | cout << array; 60 | 61 | array.add(1, 100); 62 | cout << array; 63 | 64 | array.addFirst(-1); 65 | cout << array; 66 | 67 | cout << array.get(5) << endl; 68 | array.set(0, 10); 69 | cout << array.get(0) << endl; 70 | cout << array; 71 | 72 | cout << array.contains(11) << endl; 73 | 74 | cout << array.find(8) << endl; // index=10 75 | 76 | array.remove(10); 77 | cout << array.find(8) << endl; // not found 78 | cout << array; 79 | array.removeFirst(); 80 | cout << array; 81 | array.removeLast(); 82 | cout << array; 83 | array.removeElement(100); 84 | cout << array; 85 | 86 | 87 | Array *array1 = new Array(20); 88 | array1->addLast(Student("Alice", 100)); 89 | array1->addLast(Student("Bob", 66)); 90 | array1->addLast(Student("Charlie", 88)); 91 | cout << *array1; 92 | array1->removeElement(Student("Bob", 66)); 93 | cout << *array1; 94 | // array1->~Array(); 95 | delete array1; 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /玩转儿数据结构/array/array.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-31. 3 | // 4 | 5 | #ifndef ALG_ARRAY_H 6 | #define ALG_ARRAY_H 7 | 8 | 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | 15 | // 动态数组 16 | template 17 | class Array { 18 | private: 19 | T *data; 20 | int size; 21 | int capacity; 22 | 23 | void resize(int newCapacity) { 24 | T *newData = new T[newCapacity]; 25 | for (int i = 0; i < size; i++) { 26 | newData[i] = data[i]; 27 | } 28 | data = newData; 29 | capacity = newCapacity; 30 | } 31 | 32 | void init(int capacity) { 33 | this->data = new T[capacity]; 34 | this->size = 0; 35 | this->capacity = capacity; 36 | } 37 | 38 | public: 39 | 40 | Array(int capacity) { 41 | init(capacity); 42 | } 43 | 44 | Array() { 45 | // this->Array(5); error!!! 46 | // new(this)Array(5); 47 | init(5); 48 | } 49 | 50 | ~Array() { 51 | delete[]data; 52 | size=0; 53 | capacity=0; 54 | cout << "deconstruct\n"; 55 | } 56 | 57 | int getSize() { 58 | return size; 59 | } 60 | 61 | int getCapacity() { 62 | return capacity; 63 | } 64 | 65 | bool isEmpty() { 66 | return size == 0; 67 | } 68 | 69 | // add O(n) 70 | void add(int index, T e) { 71 | assert(index >= 0 && index <= size); 72 | if (size == capacity) { 73 | resize(2 * capacity); // 均摊复杂度O(1) 74 | } 75 | for (int i = size - 1; i >= index; i--) { 76 | data[i + 1] = data[i]; 77 | } 78 | data[index] = e; 79 | size++; 80 | } 81 | 82 | // addfirst O(n) 83 | void addFirst(T e) { 84 | add(0, e); 85 | } 86 | 87 | // addlast O(1) 88 | void addLast(T e) { 89 | add(size, e); 90 | } 91 | 92 | // get O(1) 93 | T get(int index) { 94 | assert(index >= 0 && index < size); 95 | return data[index]; 96 | } 97 | 98 | // set O(1) 99 | void set(int index, T e) { 100 | assert(index >= 0 && index < size); 101 | data[index] = e; 102 | } 103 | 104 | // contains O(n) 105 | bool contains(T e) { 106 | for (int i = 0; i < size; i++) 107 | if (data[i] == e) return true; 108 | return false; 109 | } 110 | 111 | // O(n) 112 | int find(T e) { 113 | for (int i = 0; i < size; ++i) { 114 | if (data[i] == e) { 115 | return i; 116 | } 117 | } 118 | return -1; 119 | } 120 | 121 | // O(n) 122 | T remove(int index) { 123 | assert(index >= 0 && index < size); 124 | T ret = data[index]; 125 | for (int i = index + 1; i < size; ++i) { 126 | data[i - 1] = data[i]; 127 | } 128 | size--; 129 | if (size == capacity / 4 && capacity / 2 != 0) resize(capacity / 2); // 防止复杂度震荡 lazy 130 | return ret; 131 | } 132 | 133 | // O(n) 134 | T removeFirst() { 135 | return remove(0); 136 | } 137 | 138 | // O(1) 139 | T removeLast() { 140 | return remove(size - 1); 141 | } 142 | 143 | // O(n) 144 | void removeElement(T e) { 145 | int index = find(e); 146 | if (index != -1) { 147 | remove(index); 148 | } 149 | } 150 | 151 | // O(1) 152 | T getFirst() { 153 | return get(0); 154 | } 155 | 156 | // O(1) 157 | T getLast() { 158 | return get(size - 1); 159 | } 160 | 161 | 162 | // 打印输出 163 | friend ostream &operator<<(ostream &out, Array &array) { 164 | out << "Array: size = " << array.getSize() << ", capacity = " << array.getCapacity() << endl; 165 | out << "["; 166 | for (int i = 0; i < array.size; i++) { 167 | out << array.data[i]; 168 | if (i != array.size - 1) 169 | out << ", "; 170 | } 171 | out << "]" << endl; 172 | return out; 173 | } 174 | }; 175 | 176 | 177 | #endif //ALG_ARRAY_H 178 | -------------------------------------------------------------------------------- /玩转儿数据结构/binarySearch/BinarySearch.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-9-2. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | /** 12 | * 非递归查找 13 | * 二分查找法 14 | * 在有序数组arr中,查找target 15 | * 如果查找到target 返回相应的索引index 16 | * 如果没有查找到target,返回-1 17 | * @tparam T 18 | */ 19 | template 20 | int binarySearch(T arr[], int n, T target) { 21 | 22 | // 在arr[l...r]之中查找target 23 | int l = 0, r = n - 1; 24 | while (l <= r) { 25 | int mid = l + (r - l) / 2; 26 | if (arr[mid] == target) return mid; 27 | // 在arr[l...mid-1]查找target 28 | else if (target < arr[mid]) r = mid - 1; 29 | // 在arr[mid+1...r]查找target 30 | else if (target > arr[mid]) l = mid + 1; 31 | } 32 | return -1; 33 | } 34 | template 35 | int __binarySearch(T arr[], int l, int r, T target) { 36 | if(l>r) return -1; 37 | 38 | int mid = l + (r - l) / 2; 39 | if (arr[mid] == target) return mid; 40 | else if (target < arr[mid]) __binarySearch(arr, l, mid - 1, target); 41 | else if (target > arr[mid]) __binarySearch(arr, mid+1, r, target); 42 | } 43 | /** 44 | * 递归查找 45 | * @tparam T 46 | * @param arr 47 | * @param l 48 | * @param r 49 | * @param target 50 | * @return 51 | */ 52 | template 53 | int binarySearch1(T arr[], int n,T target) { 54 | return __binarySearch(arr,0,n-1,target); 55 | } 56 | 57 | int main() { 58 | 59 | int n = 1000000; 60 | int* a = new int[n]; 61 | for( int i = 0 ; i < n ; i ++ ) 62 | a[i] = i; 63 | 64 | // 测试非递归二分查找法 65 | clock_t startTime = clock(); 66 | 67 | // 对于我们的待查找数组[0...N) 68 | // 对[0...N)区间的数值使用二分查找,最终结果应该就是数字本身 69 | // 对[N...2*N)区间的数值使用二分查找,因为这些数字不在arr中,结果为-1 70 | for( int i = 0 ; i < 2*n ; i ++ ){ 71 | int v = binarySearch(a, n, i); 72 | if( i < n ) 73 | assert( v == i ); 74 | else 75 | assert( v == -1 ); 76 | } 77 | clock_t endTime = clock(); 78 | cout << "Binary Search (Without Recursion): " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"< 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | 14 | // 二分查找法, 在有序数组arr中, 查找target 15 | // 如果找到target, 返回第一个target相应的索引index 16 | // 如果没有找到target, 返回比target小的最大值相应的索引, 如果这个最大值有多个, 返回最大索引 17 | // 如果这个target比整个数组的最小元素值还要小, 则不存在这个target的floor值, 返回-1 18 | /** 19 | * 当存在大量重复的元素时,floor找的是第一个。 20 | * 当不存在指定的元素时,floor是比其小最大的一个。 21 | * @tparam T 22 | * @param arr 23 | * @param n 24 | * @param target 25 | * @return 26 | */ 27 | template 28 | int floor(T arr[], int n, T target){ 29 | 30 | assert( n >= 0 ); 31 | 32 | // 寻找比target小的最大索引 33 | int l = -1, r = n-1; 34 | while( l < r ){ 35 | // 使用向上取整避免死循环 36 | int mid = l + (r-l+1)/2; 37 | if( arr[mid] >= target ) 38 | r = mid - 1; 39 | else 40 | l = mid; 41 | } 42 | 43 | assert( l == r ); 44 | 45 | // 如果该索引+1就是target本身, 该索引+1即为返回值 46 | if( l + 1 < n && arr[l+1] == target ) 47 | return l + 1; 48 | 49 | // 否则, 该索引即为返回值 50 | return l; 51 | } 52 | 53 | 54 | 55 | 56 | // 二分查找法, 在有序数组arr中, 查找target 57 | // 如果找到target, 返回最后一个target相应的索引index 58 | // 如果没有找到target, 返回比target大的最小值相应的索引, 如果这个最小值有多个, 返回最小的索引 59 | // 如果这个target比整个数组的最大元素值还要大, 则不存在这个target的ceil值, 返回整个数组元素个数n 60 | /** 61 | * 当存在大量重复的元素时,ceil找的是第一个。 62 | * 当不存在指定的元素时,ceil是比其大最小的一个。 63 | * @tparam T 64 | * @param arr 65 | * @param n 66 | * @param target 67 | * @return 68 | */ 69 | template 70 | int ceil(T arr[], int n, T target){ 71 | 72 | assert( n >= 0 ); 73 | 74 | // 寻找比target大的最小索引值 75 | int l = 0, r = n; 76 | while( l < r ){ 77 | // 使用普通的向下取整即可避免死循环 78 | int mid = l + (r-l)/2; 79 | if( arr[mid] <= target ) 80 | l = mid + 1; 81 | else // arr[mid] > target 82 | r = mid; 83 | } 84 | 85 | assert( l == r ); 86 | 87 | // 如果该索引-1就是target本身, 该索引+1即为返回值 88 | if( r - 1 >= 0 && arr[r-1] == target ) 89 | return r-1; 90 | 91 | // 否则, 该索引即为返回值 92 | return r; 93 | } 94 | 95 | class Solution { 96 | public: 97 | int ceil(vector& nums, int n,int target) { 98 | if (nums.size() == 0) return -1; 99 | int left = 0, right = n-1; 100 | 101 | while (left <= right) { 102 | int mid =left+ (right-left) / 2; 103 | if (nums[mid] == target) { 104 | left = mid + 1; // 注意 105 | } else if (nums[mid] < target) { 106 | left = mid + 1; 107 | } else if (nums[mid] > target) { 108 | right = mid-1; 109 | } 110 | } 111 | 112 | if(right<0) return 0; // 或者写if(left==0) return -1; 如果right<0,那么此时nums中所有元素均大于target 113 | return nums[right] == target ? right : right+1; 114 | } 115 | }; 116 | 117 | // 测试我们用二分查找法实现的floor和ceil两个函数 118 | // 请仔细观察在我们的测试用例中,有若干的重复元素,对于这些重复元素,floor和ceil计算结果的区别:) 119 | int main(){ 120 | 121 | int a[] = {1, 1, 1, 2, 2, 2, 2, 2, 4, 4, 5, 5, 5, 6, 6, 6}; 122 | int n = sizeof(a)/sizeof(int); 123 | cout<= 0 && ceilIndex < n ) 130 | cout<<"The value is "< nums= {1, 1, 1, 2, 2, 2, 2, 2, 4, 4, 5, 5, 5, 6, 6, 6}; 136 | for( int i = 0 ; i <= 10 ; i ++ ){ 137 | int ceilIndex =Solution().ceil(nums,n,i); 138 | cout<<"the ceil index of "<= 0 && ceilIndex < n ) 140 | cout<<"The value is "< bst; 20 | for(int i = 0 ; i < N ; i ++ ) 21 | bst.insert(i, i); 22 | 23 | // 测试前驱算法, 除了数字0没有前驱, 每个数字x的前驱应该为x-1 24 | for(int i = 0 ; i < N ; i ++){ 25 | if( i == 0 ){ 26 | assert(bst.predecessor(i) == NULL); 27 | cout << "The predesessor of 0 is NULL" << endl; 28 | } 29 | else{ 30 | assert(bst.predecessor(i)->key == i-1); 31 | cout << "The predesessor of " << i << " is " << i-1 << endl; 32 | } 33 | } 34 | 35 | cout<key == i+1); 45 | cout << "The successor of " << i << " is " << i+1 << endl; 46 | } 47 | } 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /玩转儿数据结构/bst/BST.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-18. 3 | // 4 | 5 | #include 6 | #include 7 | #include "SequenceST.h" 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template 14 | class BST { 15 | /** 16 | * 封装到私有,让外界不知道具体实现 17 | */ 18 | private: 19 | struct Node { 20 | Key key; 21 | Value value; 22 | Node *left; 23 | Node *right; 24 | 25 | Node(Key key, Value value) { 26 | this->key = key; 27 | this->value = value; 28 | this->left = this->right = NULL; 29 | } 30 | 31 | Node(Node *node) { 32 | this->key = node->key; 33 | this->value = node->value; 34 | this->left = node->left; 35 | this->right = node->right; 36 | } 37 | }; 38 | 39 | Node *root; 40 | int count; 41 | public: 42 | BST() { 43 | root = NULL; 44 | count = 0; 45 | } 46 | 47 | ~BST() { 48 | destroy(root); 49 | } 50 | 51 | int size() { 52 | return count; 53 | } 54 | 55 | bool isEmpty() { 56 | return count == 0; 57 | // return root==0; 58 | } 59 | 60 | void insert(Key key, Value value) { 61 | root = insert(root, key, value); 62 | } 63 | 64 | bool contain(Key key) { 65 | return contain(root, key); 66 | } 67 | 68 | Value *search(Key key) { 69 | bool f = contain(key); 70 | return search(root, key); 71 | } 72 | 73 | void set(Key key, Value value) { 74 | Node *node = Search(root, key); 75 | if (node) 76 | node->value = value; 77 | } 78 | 79 | private: 80 | enum Tag { 81 | visit, print 82 | }; 83 | 84 | struct Command { 85 | Tag tag; 86 | Node *node; 87 | 88 | Command(Tag t, Node *n) : tag(t), node(n) {} 89 | }; 90 | 91 | public: 92 | vector> _preOrder() { 93 | vector> res; 94 | if (root == NULL) return res; 95 | stack stack; 96 | stack.push(Command(visit, root)); 97 | while (!stack.empty()) { 98 | Command command = stack.top(); 99 | stack.pop(); 100 | if (command.tag == print) 101 | res.push_back(make_pair(command.node->key, command.node->value)); 102 | else { 103 | if (command.node->right) 104 | stack.push(Command(visit, command.node->right)); 105 | if (command.node->left) 106 | stack.push(Command(visit, command.node->left)); 107 | stack.push(Command(print, command.node)); 108 | } 109 | } 110 | return res; 111 | } 112 | 113 | vector> preOrder() { 114 | vector> res; 115 | preOrder(root, res); 116 | return res; 117 | } 118 | 119 | vector> _inOrder() { 120 | vector> res; 121 | if (root == NULL) return res; 122 | stack stack; 123 | stack.push(Command(visit, root)); 124 | while (!stack.empty()) { 125 | Command command = stack.top(); 126 | stack.pop(); 127 | if (command.tag == print) 128 | res.push_back(make_pair(command.node->key, command.node->value)); 129 | else { 130 | if (command.node->right) 131 | stack.push(Command(visit, command.node->right)); 132 | stack.push(Command(print, command.node)); 133 | if (command.node->left) 134 | stack.push(Command(visit, command.node->left)); 135 | } 136 | } 137 | return res; 138 | } 139 | 140 | vector> inOrder() { 141 | vector> res; 142 | inOrder(root, res); 143 | return res; 144 | } 145 | 146 | vector> _postOrder() { 147 | vector> res; 148 | if (root == NULL) return res; 149 | stack stack; 150 | stack.push(Command(visit, root)); 151 | while (!stack.empty()) { 152 | Command command = stack.top(); 153 | stack.pop(); 154 | if (command.tag == print) 155 | res.push_back(make_pair(command.node->key, command.node->value)); 156 | else { 157 | stack.push(Command(print, command.node)); 158 | if (command.node->right) 159 | stack.push(Command(visit, command.node->right)); 160 | if (command.node->left) 161 | stack.push(Command(visit, command.node->left)); 162 | } 163 | } 164 | return res; 165 | } 166 | 167 | vector> postOrder() { 168 | vector> res; 169 | postOrder(root, res); 170 | return res; 171 | } 172 | 173 | vector> levelOrder() { 174 | vector> res; 175 | queue q; 176 | q.push(root); 177 | while (!q.empty()) { 178 | Node *node = q.front(); 179 | q.pop(); 180 | res.push_back(make_pair(node->key, node->value)); 181 | if (node->left) q.push(node->left); 182 | if (node->right) q.push(node->right); 183 | } 184 | return res; 185 | } 186 | 187 | // 向左找,为最小 188 | // 向右找,为最大 189 | Key minimum() { 190 | assert(count != 0); 191 | Node *minNode = minimum(root); 192 | return minNode->key; 193 | } 194 | 195 | Key maximum() { 196 | assert(count != 0); 197 | Node *maxNode = maximum(root); 198 | return maxNode->key; 199 | } 200 | 201 | void removeMin() { 202 | if (root) 203 | root = removeMin(root); 204 | } 205 | 206 | void removeMax() { 207 | if (root) 208 | root = removeMax(root); 209 | } 210 | 211 | Value *remove(Key key) { 212 | root = remove(root, key); 213 | // root = deleteNode(root, key); 214 | // root = deleteNode1(root, key); 215 | return &root->value; 216 | } 217 | 218 | Node *predecessor(Key key) { 219 | return predecessor(root, key); 220 | } 221 | 222 | Node *successor(Key key) { 223 | return successor(root, key); 224 | } 225 | 226 | Node *ceil(Key key) { 227 | // 空树或给定的key超过树中最大的key 228 | if (count == 0 || key > maximum()) return NULL; 229 | return ceil(root, key); 230 | } 231 | 232 | Node *floor(Key key) { 233 | // 空树或给定的key超过树中最大的key 234 | if (count == 0 || key < minimum()) return NULL; 235 | return floor(root, key); 236 | } 237 | 238 | private: 239 | /** 240 | * 递归插入 241 | * @param node 242 | * @param key 243 | * @param value 244 | * @return 245 | */ 246 | Node *insert(Node *node, Key key, Value value) { 247 | if (node == NULL) { 248 | count++; 249 | return new Node(key, value); 250 | } 251 | 252 | if (key == node->key) 253 | node->value = value; 254 | else if (key < node->key) 255 | node->left = insert(node->left, key, value); 256 | else 257 | node->right = insert(node->right, key, value); 258 | return node; 259 | } 260 | 261 | /** 262 | * 非递归插入 263 | * @param node 264 | * @param key 265 | * @param value 266 | * @return 267 | */ 268 | Node *Non_Recursion_InsertNode(Node *node, Key key, Value value) { 269 | if (node == NULL) { 270 | node = new Node(key, value); 271 | count++; 272 | return node; 273 | } 274 | Node *pre = node; 275 | Node *cur = node; 276 | 277 | while (cur) { 278 | pre = cur; 279 | if (key == pre->key) { 280 | pre->value = value; 281 | return node; 282 | } else if (key < pre->key) 283 | cur = cur->left; 284 | else 285 | cur = cur->right; 286 | } 287 | if (key < pre->key) 288 | pre->left = new Node(key, value); 289 | else 290 | pre->right = new Node(key, value); 291 | count++; 292 | return node; 293 | } 294 | 295 | /** 296 | * 递归查找key是否存在 297 | * @param node 298 | * @param key 299 | * @return 300 | */ 301 | bool contain(Node *node, Key key) { 302 | if (node == NULL) return false; 303 | if (key == node->key) return true; 304 | else if (key < node->key) 305 | return contain(node->left, key); 306 | else 307 | return contain(node->right, key); 308 | } 309 | 310 | /** 311 | * 非递归查找key是否存在 312 | * @param node 313 | * @param key 314 | * @return 315 | */ 316 | bool Non_Recursion_Contain(Node *node, Key key) { 317 | if (node == NULL) { 318 | return false; 319 | } 320 | Node *cur = node; 321 | 322 | while (cur) { 323 | if (key == node->key) { 324 | return true; 325 | } else if (key < node->key) 326 | cur = cur->left; 327 | else 328 | cur = cur->right; 329 | } 330 | return false; 331 | } 332 | 333 | Value *search(Node *node, Key key) { 334 | if (node == NULL) return NULL; 335 | 336 | if (key == node->key) return &node->value; 337 | else if (key < node->key) 338 | return search(node->left, key); 339 | else 340 | return search(node->right, key); 341 | } 342 | 343 | 344 | Node *Search(Node *node, Key key) { 345 | if (node == NULL) return NULL; 346 | 347 | if (key == node->key) return node; 348 | else if (key < node->key) 349 | return Search(node->left, key); 350 | else 351 | return Search(node->right, key); 352 | } 353 | 354 | void preOrder(Node *node, vector> &res) { 355 | if (node) { 356 | res.push_back(make_pair(node->key, node->value)); 357 | preOrder(node->left, res); 358 | preOrder(node->right, res); 359 | } 360 | } 361 | 362 | void inOrder(Node *node, vector> &res) { 363 | if (node) { 364 | inOrder(node->left, res); 365 | res.push_back(make_pair(node->key, node->value)); 366 | inOrder(node->right, res); 367 | } 368 | } 369 | 370 | void postOrder(Node *node, vector> &res) { 371 | if (node) { 372 | postOrder(node->left, res); 373 | postOrder(node->right, res); 374 | res.push_back(make_pair(node->key, node->value)); 375 | } 376 | } 377 | 378 | void destroy(Node *node) { 379 | if (node) { 380 | destroy(node->left); 381 | destroy(node->right); 382 | delete node; 383 | count--; 384 | } 385 | } 386 | 387 | Node *minimum(Node *node) { 388 | if (node->left == NULL) return node; 389 | return minimum(node->left); 390 | } 391 | 392 | // 非递归 393 | Node *minimum1(Node *node) { 394 | Node *currentNode = node; 395 | if (currentNode == NULL) 396 | return NULL; 397 | 398 | while (currentNode->left != NULL) { 399 | currentNode = currentNode->left; 400 | } 401 | return currentNode; 402 | } 403 | 404 | Node *maximum(Node *node) { 405 | if (node->right == NULL) return node; 406 | return maximum(node->right); 407 | } 408 | 409 | // 非递归 410 | Node *maximum1(Node *node) { 411 | Node *currentNode = node; 412 | if (currentNode == NULL) 413 | return NULL; 414 | 415 | while (currentNode->right != NULL) { 416 | currentNode = currentNode->right; 417 | } 418 | return currentNode; 419 | } 420 | 421 | Node *removeMin(Node *node) { 422 | if (node->left == NULL) { 423 | Node *rightNode = node->right; 424 | delete node; 425 | count--; 426 | return rightNode; 427 | } 428 | node->left = removeMin(node->left); 429 | return node; 430 | } 431 | 432 | // 非递归 返回curNode->right节点 433 | Node *removeMin1(Node *node) { 434 | Node *root = node; 435 | Node *currentNode = node, *p = node; 436 | Node *parentNode = node; 437 | // 空 438 | if (currentNode == NULL) 439 | return NULL; 440 | // 迭代 441 | while (currentNode->left != NULL) { 442 | parentNode = currentNode; 443 | currentNode = currentNode->left; 444 | } 445 | // 传递进来的左孩子本身就为空 446 | if (currentNode == parentNode) { 447 | Node *tmp = currentNode->right; 448 | delete currentNode; // 此时的currentNode为最大节点 449 | count--; 450 | return tmp; 451 | } 452 | // 传递进来的左孩子本身不为空,而是通过迭代到最小节点 453 | parentNode->left = currentNode->right; 454 | // 删除掉currentNode 455 | delete currentNode; // 此时的currentNode为最小节点 456 | count--; 457 | return p; 458 | } 459 | 460 | Node *removeMax(Node *node) { 461 | if (node->right == NULL) { 462 | Node *leftNode = node->left; 463 | delete node; 464 | count--; 465 | return leftNode; 466 | } 467 | node->right = removeMax(node->right); 468 | return node; 469 | } 470 | 471 | // 非递归 472 | Node *removeMax1(Node *node) { 473 | Node *currentNode = node, *p = node; 474 | Node *parentNode = node; 475 | if (currentNode == NULL) 476 | return currentNode; 477 | 478 | while (currentNode->right != NULL) { 479 | parentNode = currentNode; 480 | currentNode = currentNode->right; 481 | } 482 | if (currentNode == parentNode) { 483 | Node *tmp = currentNode->left; 484 | delete currentNode; // 此时的currentNode为最大节点 485 | count--; 486 | return tmp; 487 | } 488 | parentNode->right = currentNode->left; 489 | delete currentNode; // 此时的currentNode为最大节点 490 | count--; 491 | return p; 492 | } 493 | 494 | /** 495 | * 删除节点 496 | * @param node 497 | * @param key 498 | * @return 499 | */ 500 | Node *remove(Node *node, Key key) { 501 | if (node == NULL) return NULL; 502 | // 左孩子查找 503 | if (key < node->key) { 504 | node->left = remove(node->left, key); 505 | return node; 506 | // 右孩子查找 507 | } else if (key > node->key) { 508 | node->right = remove(node->right, key); 509 | return node; 510 | // 查找到了key 511 | } else { // key == node->key 512 | // 左孩子为空,就直接以右孩子取缔 513 | if (node->left == NULL) { // 左孩子为空包含两部分(左孩子为空与左右孩子均为空) 514 | Node *rightNode = node->right; 515 | delete node; 516 | count--; 517 | return rightNode; 518 | } 519 | // 右孩子为空,就直接以左孩子取缔 520 | if (node->right == NULL) { 521 | Node *leftNode = node->left; 522 | delete node; 523 | count--; 524 | return leftNode; 525 | } 526 | // 左右孩子均不为空,取右孩子子树中最小或取左孩子子树中最大 527 | // node->left!=NULL && node->right!=NULL 528 | // 右孩子子树中最小方法 529 | Node *successor = new Node( 530 | minimum(node->right)); // 在removeMin中将最小节点删除了,后面再次访问successor会为NULL,所以此时需要重新new 分配内存 531 | count++; 532 | successor->right = removeMin(node->right); 533 | successor->left = node->left; 534 | delete node; 535 | count--; 536 | 537 | 538 | // 左孩子子树中最大方法 539 | /** 540 | Node *successor = new Node(maximum(node->left)); 541 | count++; 542 | successor->left= removeMin(node->left); 543 | successor->right= node->right; 544 | delete node; 545 | count--; 546 | */ 547 | return successor; 548 | } 549 | } 550 | 551 | // 以左侧最大取代非递归删除 552 | Node *deleteNode(Node *root, Key key) { 553 | if (root == NULL) return NULL; 554 | Node *currentNode = root; 555 | Node *parentNode = root; 556 | 557 | //定位到要删除的key 的父节点,以及当前元素 558 | while (currentNode != NULL && currentNode->key != key) { 559 | parentNode = currentNode; 560 | if (currentNode->key > key) { 561 | currentNode = currentNode->left; 562 | } else { 563 | currentNode = currentNode->right; 564 | } 565 | 566 | } 567 | // 表示没找到key,直接返回结果 568 | if (currentNode == NULL) return root; 569 | // 表示与key相等的是根节点,根节点直接处理,不需要保存父节点 570 | if (parentNode == currentNode) { 571 | // 左分支为空,以右分支取缔 572 | if (currentNode->left == NULL) { 573 | Node *tmp = currentNode->right; 574 | delete currentNode; 575 | count--; 576 | return tmp; 577 | } 578 | // 右分支为空,以左分支取缔 579 | if (currentNode->right == NULL) { 580 | Node *tmp = currentNode->left; 581 | delete currentNode; 582 | count--; 583 | return tmp; 584 | } 585 | // 取左分支最大节点取代当前节点,并删除当前节点 586 | Node *delnode = new Node(maximum1(currentNode->left)); 587 | delnode->left = removeMax1(currentNode->left); 588 | delnode->right = currentNode->right; 589 | delete currentNode; 590 | count--; 591 | return delnode; 592 | } 593 | // key不是根节点,需要判断父节点与当前节点的关系,有可能是右分支,也可能是左分支 594 | 595 | // 左分支关系 596 | if (parentNode->left == currentNode) { 597 | if (currentNode->left == NULL) { 598 | parentNode->left = currentNode->right; 599 | delete currentNode; 600 | count--; 601 | return root; 602 | } 603 | if (currentNode->right == NULL) { 604 | parentNode->left = currentNode->left; 605 | delete currentNode; 606 | count--; 607 | return root; 608 | } 609 | Node *delnode = new Node(maximum1(currentNode->left)); 610 | count++; 611 | delnode->left = removeMax(currentNode->left); 612 | delnode->right = currentNode->right; 613 | // 父节点左孩子更新为左边最大的节点 614 | parentNode->left = delnode; 615 | delete currentNode; 616 | count--; 617 | return root; 618 | } 619 | // 右分支关系 620 | if (parentNode->right == currentNode) { 621 | if (currentNode->left == NULL) { 622 | parentNode->right = currentNode->right; 623 | delete currentNode; 624 | count--; 625 | return root; 626 | } 627 | if (currentNode->right == NULL) { 628 | parentNode->right = currentNode->left; 629 | delete currentNode; 630 | count--; 631 | return root; 632 | } 633 | Node *delnode = new Node(maximum1(currentNode->left)); 634 | count++; 635 | delnode->left = removeMax1(currentNode->left); 636 | delnode->right = currentNode->right; 637 | // 父节点右孩子更新为左边最大的节点 638 | parentNode->right = delnode; 639 | delete currentNode; 640 | count--; 641 | return root; 642 | } 643 | return root; 644 | } 645 | 646 | // 以右侧最小取代非递归删除 647 | Node *deleteNode1(Node *root, Key key) { 648 | if (root == NULL) return NULL; 649 | Node *currentNode = root; 650 | Node *parentNode = root; 651 | 652 | //定位到要删除的key 的父节点,以及当前元素 653 | while (currentNode != NULL && currentNode->key != key) { 654 | parentNode = currentNode; 655 | if (currentNode->key > key) { 656 | currentNode = currentNode->left; 657 | } else { 658 | currentNode = currentNode->right; 659 | } 660 | 661 | } 662 | 663 | if (currentNode == NULL) return root; 664 | // 根节点处理 665 | if (parentNode == currentNode) { 666 | if (currentNode->left == NULL) { 667 | Node *tmp = currentNode->right; 668 | delete currentNode; 669 | return tmp; 670 | } 671 | if (currentNode->right == NULL) { 672 | Node *tmp = currentNode->left; 673 | delete currentNode; 674 | return tmp; 675 | } 676 | Node *delnode = new Node(minimum1(currentNode->right)); 677 | delnode->right = removeMin1(currentNode->right); 678 | delnode->left = currentNode->left; 679 | delete currentNode; 680 | return delnode; 681 | } 682 | if (parentNode->left == currentNode) { 683 | 684 | if (currentNode->left == NULL) { 685 | parentNode->left = currentNode->right; 686 | delete currentNode; 687 | return root; 688 | } 689 | if (currentNode->right == NULL) { 690 | parentNode->left = currentNode->left; 691 | delete currentNode; 692 | return root; 693 | } 694 | Node *delnode = new Node(minimum1(currentNode->right)); 695 | delnode->right = removeMin1(currentNode->right); 696 | delnode->left = currentNode->left; 697 | parentNode->left = delnode; 698 | delete currentNode; 699 | return root; 700 | } 701 | if (parentNode->right == currentNode) { 702 | if (currentNode->left == NULL) { 703 | parentNode->right = currentNode->right; 704 | delete currentNode; 705 | return root; 706 | } 707 | if (currentNode->right == NULL) { 708 | parentNode->right = currentNode->left; 709 | delete currentNode; 710 | return root; 711 | } 712 | Node *delnode = new Node(minimum1(currentNode->right)); 713 | delnode->right = removeMin1(currentNode->right); 714 | delnode->left = currentNode->left; 715 | parentNode->right = delnode; 716 | delete currentNode; 717 | return root; 718 | } 719 | return root; 720 | } 721 | 722 | /** 723 | * 在node为根的二叉搜索树中,寻找key的祖先中,比key小的最大值所在节点.递归算法 724 | * 算法调用前已保证key存在在以node为根的二叉树中 725 | * @param node 726 | * @param key 727 | * @return 728 | */ 729 | Node *predecessorFromAncestor(Node *node, Key key) { 730 | if (node->key == key) 731 | return NULL; 732 | if (key < node->key) { // 我们目标是找比key小的最大key,如果比node的key小就应该在它的左子树中查找 733 | return predecessorFromAncestor(node->left, key); 734 | } else { // 此时的key小于node的key在右子树中查找 735 | assert(key > node->key); 736 | /** 737 | * 如果当前节点小于key,则当前节点有可能是比key小的最大值 738 | * 向右继续搜索,将结果存储到tmpNode中 739 | */ 740 | Node *tmpNode = predecessorFromAncestor(node->right, key); 741 | if (tmpNode) 742 | return tmpNode; 743 | else 744 | // 如果tmpNode为空,则当前节点即为结果 745 | return node; 746 | } 747 | } 748 | 749 | Node *predecessor(Node *root, Key key) { 750 | 751 | Node *node = Search(root, key); 752 | // 如果key所在的节点不存在, 则key没有前驱, 返回NULL 753 | if (node == NULL) 754 | return NULL; 755 | 756 | // 如果key所在的节点左子树不为空,则其左子树的最大值为key的前驱 757 | if (node->left != NULL) 758 | return maximum(node->left); 759 | 760 | // 否则, key的前驱在从根节点到key的路径上, 在这个路径上寻找到比key小的最大值, 即为key的前驱 761 | Node *preNode = predecessorFromAncestor(root, key); 762 | return preNode == NULL ? NULL : preNode; 763 | } 764 | 765 | Node *_predecessorFromAncestor(Node *node, Key key) { 766 | Node *firstRParent = NULL; 767 | while (node) { 768 | if (node->key == key) { 769 | return firstRParent; 770 | } 771 | if (node->key > key) { 772 | node = node->left; 773 | } else if (node->key < key) { 774 | firstRParent = node; //出现右拐点 775 | node = node->right; 776 | } 777 | } 778 | return firstRParent; 779 | } 780 | 781 | 782 | /** 783 | * 找到目标为key的节点 784 | * 寻找key的父节点 785 | * 寻找距离key节点最近的右拐节点 786 | * @param node 787 | * @param key 788 | * @param parent 789 | * @param pRParent 790 | * @return 791 | */ 792 | Node *getTargetNodeRParent(Node *node, Key key, Node *&parent, Node *&firstRParent) { 793 | while (node) { 794 | if (node->key == key) { 795 | return node; 796 | } 797 | parent = node; 798 | if (node->key > key) { 799 | node = node->left; 800 | } else if (node->key < key) { 801 | firstRParent = node; //出现右拐点 802 | node = node->right; 803 | } 804 | } 805 | return NULL; 806 | } 807 | 808 | /** 809 | * 找到目标为key的节点 810 | * 寻找key的父节点 811 | * 寻找距离key节点最近的左拐节点 812 | * @param node 813 | * @param key 814 | * @param parent 815 | * @param pRParent 816 | * @return 817 | */ 818 | Node *getTargetNodeLParent(Node *node, Key key, Node *&parent, Node *&firstLParent) { 819 | while (node) { 820 | if (node->key == key) { 821 | return node; 822 | } 823 | parent = node; 824 | if (node->key > key) { 825 | firstLParent = node; //出现左拐点 826 | node = node->left; 827 | } else if (node->key < key) { 828 | node = node->right; 829 | } 830 | } 831 | return NULL; 832 | } 833 | // 非递归 查找对应节点的前继节点 834 | /** 835 | * (1)当前节点左孩子不为空,查找左孩子最大 836 | * (2)当前节点左孩子为空,判断当前节点与其父节点关系,若为右孩子,返回父节点 837 | * 若为左孩子.向上找,直到当前节点为某一节点的右分支,则返回某节点. 838 | * 这里分为两种数据结构: 839 | * 第一:带父节点的结构 直接使用父节点向上找 840 | * 第二:不带父节点结构 需要自上向下保存最后一个有右分支的节点(且目标节点在右分支) 841 | * @param node 842 | * @param key 843 | * @return 844 | */ 845 | Node *predecessor1(Node *node, Key key) { 846 | if (node == NULL) return NULL; 847 | Node *parent = NULL; 848 | Node *firstRParent = NULL; 849 | Node *targetNode = getTargetNodeRParent(root, key, parent, firstRParent); 850 | if (targetNode == NULL) return NULL; // 没有查找到目标为key的节点 851 | if (targetNode->left) return maximum(targetNode->left); // 有左子树,寻找左子树中最大节点 852 | if (parent == NULL || parent && firstRParent == NULL) return NULL; // 父亲节点为空或者没有右拐点说明无前驱节点 853 | if (targetNode == parent->right) return parent; // 当前节点为父亲节点的右孩子,直接返回父亲节点 854 | else 855 | return firstRParent; // 当前节点为父亲节点的左孩子,直接返回从上到下搜索的最后一个右拐点 856 | } 857 | 858 | /** 859 | * 在node为根的二叉搜索树中,寻找key的祖先中,比key大的最小值所在节点.递归算法 860 | * 算法调用前已保证key存在在以node为根的二叉树中 861 | * @param node 862 | * @param key 863 | * @return 864 | */ 865 | Node *successorFromAncestor(Node *node, Key key) { 866 | if (node->key == key) 867 | return NULL; 868 | if (key > node->key) { // 我们目标是找比key大的最小key,如果比node的key大就应该在它的右子树中查找 869 | return successorFromAncestor(node->right, key); 870 | } else { // 此时的key小于node的key在左子书中查找 871 | assert(key < node->key); 872 | /** 873 | * 如果当前节点大于key,则当前节点有可能是比key大的最小值 874 | * 向左继续搜索,将结果存储到tmpNode中 875 | */ 876 | Node *tmpNode = successorFromAncestor(node->left, key); 877 | if (tmpNode) 878 | return tmpNode; 879 | else 880 | // 如果tmpNode为空,则当前节点即为结果 881 | return node; 882 | } 883 | } 884 | 885 | Node *_successorFromAncestor(Node *node, Key key) { 886 | Node *firstLParent = NULL; 887 | while (node) { 888 | if (node->key == key) { 889 | return firstLParent; 890 | } 891 | if (node->key < key) { 892 | node = node->right; 893 | } else if (node->key > key) { 894 | firstLParent = node; //出现右拐点 895 | node = node->left; 896 | } 897 | } 898 | return firstLParent; 899 | } 900 | 901 | // 查找key的后继, 递归算法 902 | // 如果不存在key的后继(key不存在, 或者key是整棵二叉树中的最大值), 则返回NULL 903 | Node *successor(Node *root, Key key) { 904 | 905 | Node *node = Search(root, key); 906 | // 如果key所在的节点不存在, 则key没有前驱, 返回NULL 907 | if (node == NULL) 908 | return NULL; 909 | 910 | // 如果key所在的节点右子树不为空,则其右子树的最小值为key的后继 911 | if (node->right != NULL) 912 | return minimum(node->right); 913 | 914 | // 否则, key的后继在从根节点到key的路径上, 在这个路径上寻找到比key大的最小值, 即为key的后继 915 | Node *sucNode = successorFromAncestor(root, key); 916 | return sucNode == NULL ? NULL : sucNode; 917 | } 918 | 919 | // 非递归 查找对应节点的后继节点 920 | Node *successor1(Node *node, Key key) { 921 | if (node == NULL) return NULL; 922 | Node *parent = NULL; 923 | Node *firstLParent = NULL; 924 | Node *targetNode = getTargetNodeLParent(root, key, parent, firstLParent); 925 | if (targetNode == NULL) return NULL; // 没有查找到目标哦为key的节点 926 | if (targetNode->right) return minimum(targetNode->right); // 有右子树,寻找右子树中最小节点 927 | if (parent == NULL || parent && firstLParent == NULL) return NULL; // 父亲节点为空或者没有左拐点说明无后继节点 928 | if (targetNode == parent->left) return parent; // 当前节点为父亲节点的左孩子,直接返回父亲节点 929 | else 930 | return firstLParent; //当前节点为父亲节点的右孩子,直接返回从上到下搜索的最后一个左拐点 931 | } 932 | 933 | //============================================================ 934 | /** 935 | * 拓展:带父节点数据结构 936 | */ 937 | //============================================================ 938 | /** 939 | * 带父节点数据结构,查找前驱节点,直接使用父节点向上找 940 | * @param node 941 | * @param key 942 | * @return 943 | */ 944 | Node *predecessor2(Node *node, Key key) { 945 | if (node->left) { 946 | return maximum(node->left); 947 | } 948 | Node *parent = node->parent; 949 | // 自下向上查找 950 | while (parent != NULL && node != parent->right) { 951 | node = parent; 952 | parent = node->parent; 953 | } 954 | return parent; 955 | } 956 | 957 | /** 958 | * 带父节点数据结构,直接后继节点,直接使用父节点向上找 959 | */ 960 | Node *successor2(Node *node, Key key) { 961 | if (node->right) { 962 | return minimum(node->right); 963 | } 964 | Node *parent = node->parent; 965 | while (parent != NULL && node != node->left) { 966 | node = parent; 967 | parent = node->parent; 968 | } 969 | return parent; 970 | } 971 | //============================================================ 972 | /** 973 | * 拓展结束 974 | */ 975 | //============================================================ 976 | 977 | 978 | /** 979 | * 地板 980 | * 在以node为根的二叉搜索树中,寻找key的floor值所处的节点,递归算法 981 | * @param root 982 | * @param key 983 | * @return 984 | */ 985 | Node *floor(Node *root, Key key) { 986 | if (root == NULL) return NULL; 987 | 988 | // 如果node的key值和要寻找的key值相等 989 | // 则node 本身就是key的floor节点 990 | if (key == root->key) return root; 991 | // 如果node的key比要寻找的key大 992 | // 则要寻找的key的floor节点一定在node的左边子树中 993 | if (root->key > key) return floor(root->left, key); 994 | // 如果node的key小于要寻找的key 995 | // 则node有可能是key的floor节点,也有可能不是(存在比node->key大但小于key的其余节点) 996 | // 则要尝试向node的右子树寻找一下 997 | Node *tmpNode = floor(root->right, key); 998 | if (tmpNode) return tmpNode; 999 | return root; 1000 | } 1001 | 1002 | /** 1003 | * 天花板 1004 | * 在以node为根的二叉搜索树中,寻找key的ceil值所处的节点,递归算法 1005 | * @param root 1006 | * @param key 1007 | * @return 1008 | */ 1009 | Node *ceil(Node *root, Key key) { 1010 | if (root == NULL) return NULL; 1011 | 1012 | // 如果node的key值和要寻找的key值相等 1013 | // 则node 本身就是key的ceil节点 1014 | if (key == root->key) return root; 1015 | // 如果node的key比要寻找的key小,则要寻找的key的ceil节点一定在node的右边子树中 1016 | if (root->key < key) return ceil(root->right, key); 1017 | // 如果node的key大于要寻找的key 1018 | // 则node有可能是key的ceil节点,也有可能不是(存在比node->key小但大于key的其余节点) 1019 | // 则要尝试向node的左子树寻找一下 1020 | Node *tmpNode = ceil(root->left, key); 1021 | if (tmpNode) return tmpNode; 1022 | return root; 1023 | } 1024 | }; 1025 | 1026 | void shuffle(int arr[], int n) { 1027 | srand(time(NULL)); 1028 | for (int i = n - 1; i >= 0; i--) { 1029 | int x = rand() % (i + 1); 1030 | swap(arr[i], arr[x]); 1031 | } 1032 | } 1033 | 1034 | -------------------------------------------------------------------------------- /玩转儿数据结构/bst/SequenceST.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-9-2. 3 | // 4 | 5 | #ifndef ALG_SEQUENCEST_H 6 | #define ALG_SEQUENCEST_H 7 | 8 | #include 9 | #include 10 | #include "../interface.h" 11 | 12 | using namespace std; 13 | 14 | // 顺序查找表实现 15 | template 16 | 17 | class SequenceST { 18 | private: 19 | struct Node { 20 | Key key; 21 | Value value; 22 | Node *next; 23 | 24 | Node(Key key, Value value) { 25 | this->key = key; 26 | this->value = value; 27 | this->next = NULL; 28 | } 29 | }; 30 | 31 | Node *head; // 表头 32 | int count; // 顺序查找表中的节点数 33 | public: 34 | // 构造函数 35 | SequenceST() { 36 | head = NULL; 37 | count = 0; 38 | } 39 | 40 | // 析构函数 41 | ~SequenceST() { 42 | while (head) { 43 | Node *node = head; 44 | head = head->next; 45 | delete node; 46 | count--; 47 | } 48 | assert(head == NULL && count == 0); 49 | } 50 | 51 | int size() { 52 | return count; 53 | } 54 | 55 | bool isEmpty() { 56 | return count == 0; 57 | } 58 | 59 | void insert(Key key, Value value) { 60 | Node *node = head; 61 | while (node) { 62 | if (key == node->key) { 63 | node->value = value; 64 | return; 65 | } 66 | node = node->next; 67 | } 68 | Node *newNode = new Node(key, value); 69 | newNode->next = head; 70 | head = newNode; 71 | count++; 72 | } 73 | 74 | void set(Key key, Value value) { 75 | Node *node = head; 76 | while (node) { 77 | if (key == node->key) { 78 | node->value = value; 79 | return; 80 | } 81 | node = node->next; 82 | } 83 | } 84 | 85 | bool contain(Key key) { 86 | Node *node = head; 87 | while (node) { 88 | if (key == node->key) 89 | return true; 90 | node = node->next; 91 | } 92 | return false; 93 | } 94 | 95 | Value *search(Key key) { 96 | Node *node = head; 97 | while (node) { 98 | if (key == node->key) 99 | return &node->value; 100 | node = node->next; 101 | } 102 | return NULL; 103 | } 104 | 105 | Value *remove(Key key) { 106 | if (head == NULL) return nullptr; 107 | 108 | // 第一个节点就满足删除节点条件,保留后继节点并删除当前节点 109 | if (key == head->key) { 110 | Node *delNode = head; 111 | head = head->next; 112 | count--; 113 | return &delNode->value; 114 | } 115 | 116 | Node *node = head; 117 | while (node->next && node->next->key != key) { 118 | node = node->next; 119 | } 120 | if (node->next) { 121 | Node *delNode = node->next; 122 | node->next = delNode->next; 123 | count--; 124 | return &delNode->value; 125 | } 126 | } 127 | }; 128 | 129 | 130 | 131 | 132 | 133 | 134 | #endif //ALG_SEQUENCEST_H 135 | -------------------------------------------------------------------------------- /玩转儿数据结构/file/FileOps.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-9-2. 3 | // 4 | 5 | #ifndef ALG_FILEOPS_H 6 | #define ALG_FILEOPS_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | using namespace std; 15 | 16 | // 文件相关操作 17 | namespace FileOps{ 18 | 19 | // 字符串s从start位置开始返回第一个字母位置对应的index 20 | int firstCharacterIndex(const string& s, int start){ 21 | for( int i = start ; i < s.length() ; i ++ ) 22 | if( isalpha(s[i]) ) 23 | return i; 24 | return s.length(); 25 | } 26 | 27 | // 将字符串s中的所有字母转换成小写之后返回 28 | string lowerS( const string& s){ 29 | 30 | string ret = ""; 31 | for( int i = 0 ; i < s.length() ; i ++ ) 32 | ret += tolower(s[i]); 33 | return ret; 34 | } 35 | 36 | // 读取文件名称为filename中的内容,并将其中包含的所有词语放进words中 37 | bool readFile(const string& filename, vector &words){ 38 | 39 | // 文件读取 40 | string line; 41 | string contents = ""; 42 | ifstream file(filename); 43 | if( file.is_open() ){ 44 | while( getline(file, line)) 45 | contents += ( line + "\n" ); 46 | file.close(); 47 | } 48 | else{ 49 | cout<<"Can not open "< 7 | 8 | 9 | int main() { 10 | 11 | vector words{"java", "c++", "c", "c++", "c#", "python", "ruby", "python", 12 | "c", "c", "c++", "java", "c++", "rust", "python"}; 13 | HashTable ht(1); 14 | for (string word : words) { 15 | if (ht.contains(word)) { 16 | ht.set(word, ht.get(word) + 1); 17 | } else { 18 | ht.add(word, 1); 19 | } 20 | } 21 | cout< 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | template 11 | class HashTable { 12 | private: 13 | const static int upperTol = 3; 14 | const static int lowerTol = 1; 15 | const static int initCapacity = 1; 16 | map **hashtable; 17 | int M; 18 | int size; 19 | 20 | 21 | public: 22 | /** 23 | * 传参构造 24 | * @param M 25 | */ 26 | HashTable(int M) : M(M), size(0) { 27 | // 这里的括号是为了初始化为0,这就可以不用写下面的代码,当然在后面add之类的操作,就不需要动态分配内存. 28 | // this->hashtable = new map *[M](); 29 | this->hashtable = new map *[M]; 30 | for (int i = 0; i < M; i++) { 31 | this->hashtable[i] = new map; 32 | } 33 | } 34 | 35 | /** 36 | * 默认构造 37 | */ 38 | HashTable() { 39 | HashTable(initCapacity); 40 | } 41 | 42 | /** 43 | * 析构函数,释放内存 44 | */ 45 | ~HashTable() { 46 | free(M); 47 | } 48 | 49 | 50 | public: 51 | /** 52 | * 获取哈希表元素个数 53 | * @return 54 | */ 55 | int getSize() { 56 | return size; 57 | } 58 | 59 | /** 60 | * 添加新元素 61 | * @param key 62 | * @param value 63 | */ 64 | void add(Key key, Value value) { 65 | // 拉链法出来的map如果为空,就动态分配一个map,然后进行插入 66 | // 如果key不存在就看内存是否存在,不存在,就分配,存在就插入 67 | if (hashtable[hashFunc(key)] == NULL || hashtable[hashFunc(key)]->count(key) == 0) { 68 | if (hashtable[hashFunc(key)] == NULL) 69 | hashtable[hashFunc(key)] = new map; 70 | hashtable[hashFunc(key)]->insert(make_pair(key, value)); 71 | size++; 72 | if (size >= maxCapacity()) 73 | resize(2 * M); 74 | } else { 75 | // 否则,修改value. 76 | hashtable[hashFunc(key)]->erase(key); 77 | hashtable[hashFunc(key)]->insert(make_pair(key, value)); 78 | } 79 | } 80 | 81 | 82 | /** 83 | * 移除Key 84 | * @param key 85 | * @return 0 success -1 fail 86 | */ 87 | Value remove(Key key) { 88 | Value ret = -1; 89 | // 是否包含key,若包含key,则直接删除 90 | if (contains(key)) { 91 | hashtable[hashFunc(key)]->erase(key); 92 | size--; 93 | // if (size == 0) delete hashtable[hashFunc(key)]; // 可以添加这行来动态减少内存 94 | ret = 0; 95 | // initCapacity 保证不会越界 96 | if (size < minCapacity() && M / 2 >= initCapacity) resize(M / 2); 97 | } 98 | return ret; 99 | } 100 | 101 | /** 102 | * 重设value 103 | * @param key 104 | * @param value 105 | */ 106 | void set(Key key, Value value) { 107 | // key不存在 108 | if (!contains(key)) 109 | throw "key not exists!"; 110 | // 修改value 111 | hashtable[hashFunc(key)]->erase(key); 112 | hashtable[hashFunc(key)]->insert(make_pair(key, value)); 113 | } 114 | 115 | /** 116 | * 是否包含key 117 | * @param key 118 | * @return 119 | */ 120 | bool contains(Key key) { 121 | return hashtable[hashFunc(key)] == NULL || this->hashtable[hashFunc(key)]->count(key) == 0 ? false : true; 122 | } 123 | 124 | /** 125 | * 获取key对应的value 126 | * @param key 127 | * @return 128 | */ 129 | Value get(Key key) { 130 | if (contains(key)) 131 | return hashtable[hashFunc(key)]->at(key); 132 | return 0; 133 | } 134 | 135 | /** 136 | * 最大容量 137 | * @return 138 | */ 139 | Value maxCapacity() { 140 | return M * upperTol; 141 | } 142 | 143 | /** 144 | * 最小容量 145 | * @return 146 | */ 147 | Value minCapacity() { 148 | return M * lowerTol; 149 | } 150 | 151 | private: 152 | /** 153 | * 哈希函数 154 | * @param key 155 | * @return 156 | */ 157 | int hashFunc(Key key) { 158 | std::hash h; 159 | return (h(key) & 0x7fffffff) % M; 160 | } 161 | 162 | template 163 | // 重载<<操作符 164 | friend ostream &operator<<(ostream &out, HashTable &hashTable); 165 | 166 | /** 167 | * 打印hash表中所有数据 168 | */ 169 | void print() { 170 | string res = "{"; 171 | for (int i = 0; i < this->M; i++) 172 | if (this->hashtable[i]) 173 | for (auto m:*(this->hashtable[i])) 174 | res += m.first + ":" + to_string(m.second) + ","; 175 | res.replace(res.size() - 1, string::npos, "}"); 176 | cout << res << endl; 177 | } 178 | 179 | /** 180 | * 动态调整内存,保证时间复杂度O(1)查找 181 | * 把扩容后的操作,平摊到前面每次操作,时间复杂度O(2),那就是O(1)了 182 | * @param newM 183 | */ 184 | void resize(int newM) { 185 | cout << "resize " << newM << endl; 186 | map **newHashTable = new map *[newM]; 187 | for (int i = 0; i < newM; i++) { 188 | newHashTable[i] = new map; 189 | } 190 | int oldM = M; 191 | this->M = newM; 192 | for (int i = 0; i < oldM; i++) { 193 | map m = *(hashtable[i]); 194 | for (auto p:m) 195 | newHashTable[hashFunc(p.first)]->insert(make_pair(p.first, p.second)); 196 | } 197 | 198 | free(oldM); 199 | this->hashtable = newHashTable; 200 | } 201 | 202 | private: 203 | /** 204 | * 释放内存 205 | * @param M 206 | */ 207 | void free(int M) { 208 | for (int i = 0; i < M; i++) { 209 | if (hashtable[i]) 210 | delete hashtable[i]; 211 | } 212 | delete[]hashtable; 213 | } 214 | }; 215 | 216 | template 217 | ostream &operator<<(ostream &out, HashTable &hashTable) { 218 | hashTable.print(); 219 | return out; 220 | } 221 | 222 | /** 223 | * 哈希函数的设计原则: 224 | * 1.一致性:如果a==b,则hashFunc(a)=o=hashFunc(b) 225 | * 2.高效性:计算高效简便 226 | * 3.均匀性:哈希值均匀分布 227 | */ 228 | // (hashcode(k1) & 0x7fffffff)%M 229 | // f为7个一个f有4个1那么就是28个1,,7有3个1,,总共31个1 230 | // 而最高位第32位表示正负,故上述取&后,变为正数。 231 | -------------------------------------------------------------------------------- /玩转儿数据结构/hash/hashMain_v2.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-20. 3 | // 4 | 5 | #include "hash_v2.h" 6 | #include 7 | #include 8 | 9 | 10 | enum { _S_n_primes = sizeof(unsigned long) != 8 ? 256 : 256 + 48 }; 11 | int main() { 12 | 13 | vector words{"java", "c++", "c", "c++", "c#", "python", "ruby", "python", 14 | "c", "c", "c++", "java", "c++", "rust", "python"}; 15 | HashTable ht; 16 | for (string word : words) { 17 | if (ht.contains(word)) { 18 | ht.set(word, ht.get(word) + 1); 19 | } else { 20 | ht.add(word, 1); 21 | } 22 | } 23 | cout<erase(key); 121 | hashtable[hashFunc(key)]->insert(make_pair(key, value)); 122 | } 123 | 124 | /** 125 | * 是否包含key 126 | * @param key 127 | * @return 128 | */ 129 | bool contains(Key key) { 130 | return hashtable[hashFunc(key)] == NULL || this->hashtable[hashFunc(key)]->count(key) == 0 ? false : true; 131 | } 132 | 133 | /** 134 | * 获取key对应的value 135 | * @param key 136 | * @return 137 | */ 138 | Value get(Key key) { 139 | if (contains(key)) 140 | return hashtable[hashFunc(key)]->at(key); 141 | return 0; 142 | } 143 | 144 | /** 145 | * 最大容量 146 | * @return 147 | */ 148 | Value maxCapacity() { 149 | return M * upperTol; 150 | } 151 | 152 | /** 153 | * 最小容量 154 | * @return 155 | */ 156 | Value minCapacity() { 157 | return M * lowerTol; 158 | } 159 | 160 | private: 161 | /** 162 | * 哈希函数 163 | * @param key 164 | * @return 165 | */ 166 | int hashFunc(Key key) { 167 | std::hash h; 168 | return (h(key) & 0x7fffffff) % M; 169 | } 170 | 171 | template 172 | // 重载<<操作符 173 | friend ostream &operator<<(ostream &out, HashTable &hashTable); 174 | 175 | /** 176 | * 打印hash表中所有数据 177 | */ 178 | void print() { 179 | string res = "{"; 180 | for (int i = 0; i < this->M; i++) 181 | if (this->hashtable[i]) 182 | for (auto m:*(this->hashtable[i])) 183 | res += m.first + ":" + to_string(m.second) + ","; 184 | res.replace(res.size() - 1, string::npos, "}"); 185 | cout << res << endl; 186 | } 187 | 188 | /** 189 | * 动态调整内存,保证时间复杂度O(1)查找 190 | * 把扩容后的操作,平摊到前面每次操作,时间复杂度O(2),那就是O(1)了 191 | * @param newM 192 | */ 193 | void resize(int newM) { 194 | cout << "resize " << newM << endl; 195 | map **newHashTable = new map *[newM]; 196 | for (int i = 0; i < newM; i++) { 197 | newHashTable[i] = new map; 198 | } 199 | int oldM = M; 200 | this->M = newM; 201 | for (int i = 0; i < oldM; i++) { 202 | map m = *(hashtable[i]); 203 | for (auto p:m) 204 | newHashTable[hashFunc(p.first)]->insert(make_pair(p.first, p.second)); 205 | } 206 | 207 | free(oldM); 208 | this->hashtable = newHashTable; 209 | } 210 | 211 | private: 212 | /** 213 | * 释放内存 214 | * @param M 215 | */ 216 | void free(int M) { 217 | for (int i = 0; i < M; i++) { 218 | if (hashtable[i]) 219 | delete hashtable[i]; 220 | } 221 | delete[]hashtable; 222 | } 223 | }; 224 | 225 | template 226 | ostream &operator<<(ostream &out, HashTable &hashTable) { 227 | hashTable.print(); 228 | return out; 229 | } 230 | 231 | /** 232 | * 哈希函数的设计原则: 233 | * 1.一致性:如果a==b,则hashFunc(a)=o=hashFunc(b) 234 | * 2.高效性:计算高效简便 235 | * 3.均匀性:哈希值均匀分布 236 | */ 237 | // (hashcode(k1) & 0x7fffffff)%M 238 | // f为7个一个f有4个1那么就是28个1,,7有3个1,,总共31个1 239 | // 而最高位第32位表示正负,故上述取&后,变为正数。 240 | -------------------------------------------------------------------------------- /玩转儿数据结构/heap/347_local.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-30. 3 | // 4 | 5 | 6 | 7 | // 使用自己的Priority_Queue 8 | #include 9 | #include 10 | #include 11 | #include "PriorityQueue.h" 12 | // C++ 默认的优先队列采用vector作为底层容器,且默认为大顶堆,传递进去的是less,比较的时候是根据第二个参数判别 13 | using namespace std; 14 | 15 | class Freq { 16 | public: 17 | int e, freq; 18 | 19 | Freq(int key, int frequence) : e(key), freq(frequence) {} 20 | 21 | 22 | // 比较大小都是相对的,由我们来定,我们底层是一个大顶堆,而实际上我们需要一个小顶堆,那么我们可以重载元素(例如这里放进队列的是个Freq)操作符,将>里面操作变为<,<操作符变为>内容,就完成了类似小顶堆的功能。 23 | bool operator<(const Freq &another) { 24 | if (this->freq < another.freq) { 25 | return false; 26 | } else { 27 | return true; 28 | } 29 | } 30 | 31 | bool operator>(const Freq &another) { 32 | if (this->freq > another.freq) { 33 | return false; 34 | } else { 35 | return true; 36 | } 37 | } 38 | }; 39 | 40 | class Solution { 41 | public: 42 | 43 | // 使用自己的Priority_Queue 44 | 45 | vector topKFrequent(vector &nums, int k) { 46 | unordered_map map; 47 | for (auto num:nums) map[num]++; 48 | 49 | PriorityQueue *pq = new PriorityQueue; 50 | for (auto m:map) { 51 | Freq f(m.first, m.second); 52 | if (pq->getSize() < k) pq->enqueue(f); 53 | else if (m.second > pq->getFront().freq) { 54 | pq->dequeue(); 55 | pq->enqueue(f); 56 | } 57 | } 58 | vector res; 59 | while (!pq->isEmpty()) { 60 | res.push_back(pq->getFront().e); 61 | pq->dequeue(); 62 | } 63 | delete pq; 64 | return res; 65 | } 66 | 67 | }; 68 | 69 | 70 | int main() { 71 | vector nums = {1, 1, 1, 2, 2, 3}; 72 | int k = 2; 73 | vector res = Solution().topKFrequent(nums, k); 74 | for (auto i:res) cout << i << endl; 75 | int i = 1; 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /玩转儿数据结构/heap/347topKFrequent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-30. 3 | // 4 | 5 | // 使用STL的priorityqueue 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "PriorityQueue.h" 12 | // C++ 默认的优先队列采用vector作为底层容器,且默认为大顶堆,传递进去的是less,比较的时候是根据第二个参数判别 13 | using namespace std; 14 | 15 | class Freq { 16 | public: 17 | int e, freq; 18 | 19 | Freq(int key, int frequence) : e(key), freq(frequence) {} 20 | bool operator<(const Freq &f) const{ // 必须加const 21 | return this->freq > f.freq; 22 | } 23 | 24 | }; 25 | 26 | // less < 重载 27 | //inline bool operator<(const Freq &f1, const Freq &f2) { 28 | // return f1.freq > f2.freq; 29 | //} 30 | // 31 | // greater > 重载 32 | inline bool operator>(const Freq &f1, const Freq &f2) { 33 | return f1.freq > f2.freq; 34 | } 35 | 36 | struct cmp { 37 | bool operator()(Freq a, Freq b) { 38 | return a.freq > b.freq; 39 | } 40 | }; 41 | // c++ 11语法 42 | template using minHeap=priority_queue, cmp>; 43 | class Solution { 44 | public: 45 | 46 | // 使用STL的priority_queue 47 | vector topKFrequent(vector &nums, int k) { 48 | unordered_map map; 49 | for (auto num:nums) map[num]++; 50 | 51 | // greater 为a>b 实际上是看b 那就是每次放入队列中是教小的元素 52 | 53 | // priority_queue> *pq = new priority_queue>; 54 | // priority_queue, greater> *pq = new priority_queue, greater>; 55 | minHeap *pq=new minHeap; 56 | for (auto m:map) { 57 | Freq f(m.first, m.second); 58 | if (pq->size() < k) pq->push(f); 59 | else if (m.second > pq->top().freq) { 60 | pq->pop(); 61 | pq->push(f); 62 | } 63 | } 64 | vector res; 65 | while (!pq->empty()) { 66 | res.push_back(pq->top().e); 67 | pq->pop(); 68 | } 69 | delete pq; 70 | return res; 71 | } 72 | }; 73 | 74 | 75 | int main() { 76 | vector nums = {1, 1, 1, 2, 2, 3}; 77 | int k = 2; 78 | vector res = Solution().topKFrequent(nums, k); 79 | for (auto i:res) cout << i << endl; 80 | 81 | 82 | priority_queue pq(nums.begin(),nums.end()); 83 | 84 | while(!pq.empty()) { 85 | cout< 12 | class PriorityQueue : BaseQueue { 13 | private: 14 | MaxHeap maxHeap; 15 | public: 16 | int getSize() override { 17 | return maxHeap.size(); 18 | } 19 | 20 | void enqueue(T value) override { 21 | maxHeap.add(value); 22 | } 23 | 24 | T getFront() override { 25 | return maxHeap.findMax(); 26 | } 27 | 28 | T dequeue() override { 29 | return maxHeap.extractMax(); 30 | } 31 | 32 | bool isEmpty() override { 33 | return maxHeap.isEmpty(); 34 | } 35 | 36 | 37 | }; 38 | 39 | #endif //ALG_PRIORITYQUEUE_H 40 | -------------------------------------------------------------------------------- /玩转儿数据结构/heap/README.md: -------------------------------------------------------------------------------- 1 | priority_queue 优先队列默认构建的是大顶堆 2 | 3 | 为何priority_queue采用的less作为大顶堆? 4 | 5 | (1) push方法先调用vector的push方法,然后调用push_heap,最后调用__push_heap,最后这个函数中使用比较器,从最后一个非叶子节点开始向上查找,直到找到比插入的元素大于等于的位置,就把这个元素放在那个位置上。 6 | 很明显,这个是构建大顶堆的sift up过程。 7 | (2) pop方法调用pop_heap,再调用__pop_heap,然后取第一个元素将其放到后面,然后调用__adjust_heap恢复堆不变,最后调用一下vector的pop_back,刚才放到最后的那个元素给弹出去,也就是最大的元素。 8 | 9 | 对比pop与push是另个完全相反的过程。 10 | - 对于pop是先取第一个元素放到最后再pop_back出去,此时弹出的是最大元素。 11 | - 对于push是先把元素给push_back进去,然后开始维护堆,把大的元素给sift up。 12 | 13 | 因此底层采用的less为大顶堆。 14 | 15 | 小顶堆构建四种方法(准确的三种,最后一种不算) 16 | 17 | (1)直接重载less的小于操作符 18 | 19 | 20 | ```cpp 21 | class Freq { 22 | public: 23 | int e, freq; 24 | 25 | Freq(int key, int frequence) : e(key), freq(frequence) {} 26 | 27 | }; 28 | // 全局重载 注意参数必须为const xxx& 29 | inline bool operator<(const Freq &f1, const Freq &f2) { 30 | return f1.freq > f2.freq; 31 | } 32 | ``` 33 | 34 | 调用处为: 35 | 36 | ```cpp 37 | priority_queue> *pq = new priority_queue>; 38 | // 等价于 39 | priority_queue,less> *pq = new priority_queue,less>; 40 | ``` 41 | 42 | (2)重载greater的大于操作符 43 | 44 | ```cpp 45 | // 全局重载 注意参数必须为const xxx& 46 | inline bool operator>(const Freq &f1, const Freq &f2) { 47 | return f1.freq > f2.freq; 48 | } 49 | priority_queue,greater> *pq = new priority_queue,greater>; 50 | ``` 51 | 52 | 53 | 54 | (3)仿函数 55 | 56 | ```cpp 57 | struct cmp { 58 | bool operator()(Freq a, Freq b) { 59 | return a.freq > b.freq; 60 | } 61 | }; 62 | ``` 63 | 调用: 64 | ```cpp 65 | priority_queue, cmp> *pq = new priority_queue, cmp>; 66 | ``` 67 | 68 | 69 | (4)利用using构建全局的大顶堆或小顶堆 70 | 71 | ```cpp 72 | template using minHeap=priority_queue, cmp>; 73 | int main() { 74 | minHeap *pq=new minHeap; 75 | // do something 76 | return 0; 77 | } 78 | ``` 79 | 80 | -------------------------------------------------------------------------------- /玩转儿数据结构/heap/heap.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-29. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "heap.h" 9 | #include "PriorityQueue.h" 10 | 11 | double testHeap(const vector &testData, bool isHeapify) { 12 | time_t startTime = clock(); 13 | MaxHeap *maxHeap; 14 | if (isHeapify) 15 | maxHeap = new MaxHeap(testData); 16 | else { 17 | maxHeap = new MaxHeap(); 18 | for (auto num:testData) 19 | maxHeap->add(num); 20 | } 21 | 22 | vector res(testData.size()); 23 | 24 | for (int i = 0; i < testData.size(); i++) { 25 | res[i] = maxHeap->extractMax(); 26 | } 27 | 28 | for (int i = 1; i < testData.size(); i++) { 29 | if (res[i - 1] < res[i]) throw "Error"; 30 | } 31 | cout << "Test MaxHeap completed." << endl; 32 | delete maxHeap; 33 | 34 | time_t endTime = clock(); 35 | return double(endTime - startTime) / CLOCKS_PER_SEC; 36 | } 37 | 38 | int main() { 39 | int n = 10000; 40 | 41 | vector testData(n); 42 | 43 | for (int i = 0; i < n; i++) { 44 | int r = rand() % (INT_MAX + 1); 45 | testData.push_back(r); 46 | } 47 | // O(nlog(n)) 48 | double time1 = testHeap(testData, false); 49 | cout << "without heapify " << time1 << " s" << endl; 50 | // O(n) 51 | double time2 = testHeap(testData, true); 52 | cout << "with heapify " << time2 << " s" << endl; 53 | PriorityQueue priorityQueue; 54 | 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /玩转儿数据结构/heap/heap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-29. 3 | // 4 | 5 | #ifndef ALG_HEAP_H 6 | #define ALG_HEAP_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | // 二叉堆是一棵完全二叉树 13 | 14 | 15 | template 16 | class MaxHeap { 17 | private: 18 | vector data; 19 | 20 | public: 21 | MaxHeap() { 22 | 23 | } 24 | 25 | MaxHeap(int capacity) { 26 | data = vector(capacity); 27 | } 28 | 29 | // heapify : 将任意数组整理成堆的形状 时间复杂度O(n) 30 | // 直接把数组看成任意完全二叉树,从最后一个非叶节点开始sift down 31 | MaxHeap(const vector &array) { 32 | data = array; 33 | T lastParent = parent(array.size() - 1); 34 | while (lastParent >= 0) { 35 | siftDown(lastParent); 36 | lastParent--; 37 | } 38 | } 39 | 40 | // 返回堆中的元素个数 41 | int size() { 42 | return data.size(); 43 | } 44 | 45 | // 返回堆是否为空 46 | bool isEmpty() { 47 | return data.empty(); 48 | } 49 | 50 | // 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引 51 | int parent(int index) { 52 | assert(index > 0); // 根节点没有父亲 53 | return (index - 1) / 2; 54 | } 55 | 56 | // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引 57 | int leftChild(int index) { 58 | return 2 * index + 1; 59 | } 60 | 61 | // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引 62 | int rightChild(int index) { 63 | return 2 * index + 2; 64 | } 65 | 66 | // 向堆中添加元素 O(log(n)) 67 | void add(T value) { 68 | data.push_back(value); 69 | siftUp(data.size() - 1); 70 | } 71 | 72 | // sift up 上浮 73 | void siftUp(int k) { 74 | while (k > 0 && data[parent(k)] < data[k]) { 75 | swap(k, parent(k)); 76 | k = parent(k); 77 | } 78 | } 79 | 80 | void swap(int i, int j) { 81 | assert(i >= 0 && i < size() && j >= 0 && j < size()); 82 | T t = data[i]; 83 | data[i] = data[j]; 84 | data[j] = t; 85 | } 86 | 87 | // 看堆中的最大元素 88 | T findMax() { 89 | assert(size() > 0); 90 | return data[0]; 91 | } 92 | 93 | // 取出堆中最大元素 O(log(n)) 94 | T extractMax() { 95 | T ret = findMax(); 96 | 97 | swap(0, data.size() - 1); 98 | data.pop_back(); 99 | siftDown(0); 100 | 101 | return ret; 102 | } 103 | 104 | void siftDown(int k) { 105 | while (leftChild(k) < data.size()) { 106 | int j = leftChild(k); 107 | if (j + 1 < data.size() && data[j + 1] > data[j]) j = rightChild(k); //j++ 108 | // data[j]是此时leftChild 和 rightChild中的最大值 109 | if (data[k] > data[j]) break; 110 | swap(k, j); 111 | k = j; 112 | } 113 | } 114 | 115 | // replace : 取出最大元素后,放入一个新元素 116 | // 实现:可以先extractMax,再add,两次O(log(n))的操作 117 | // 实现: 可以直接将堆顶元素替换以后Sift Down,一次O(log(n))的操作 118 | // 取出堆中的最大元素,并且替换成元素value 119 | T replace(T value) { 120 | T ret = findMax(); 121 | data[0] = value; 122 | siftDown(0); 123 | return ret; 124 | } 125 | 126 | 127 | }; 128 | 129 | 130 | #endif //ALG_HEAP_H 131 | -------------------------------------------------------------------------------- /玩转儿数据结构/interface.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-29. 3 | // 4 | 5 | #ifndef ALG_INTERFACE_H 6 | #define ALG_INTERFACE_H 7 | 8 | template 9 | class CommonStack { 10 | public: 11 | virtual int getSize() = 0; 12 | 13 | virtual bool isEmpty() = 0; 14 | 15 | virtual void push(T e) = 0; 16 | 17 | virtual void pop() = 0; 18 | 19 | virtual T peek() = 0; 20 | }; 21 | 22 | 23 | template 24 | class BaseQueue { 25 | public: 26 | 27 | virtual bool isEmpty() = 0; 28 | 29 | virtual int getSize() = 0; 30 | 31 | virtual void enqueue(T e) = 0; 32 | 33 | virtual T dequeue() = 0; 34 | 35 | virtual T getFront() = 0; 36 | }; 37 | 38 | template 39 | class Map { 40 | virtual void insert(Key key, Value value) = 0; 41 | 42 | virtual Value *remove(Key key) = 0; 43 | 44 | virtual bool contain(Key key) = 0; 45 | 46 | virtual Value *search(Key key) = 0; 47 | 48 | virtual void set(Key key, Value value) = 0; 49 | 50 | virtual int size() = 0; 51 | 52 | virtual bool isEmpty() = 0; 53 | }; 54 | 55 | template 56 | class Set { 57 | virtual void insert(Key key) = 0; 58 | 59 | virtual void remove(Key key) = 0; 60 | 61 | virtual bool contain(Key key) = 0; 62 | 63 | virtual int size() = 0; 64 | 65 | virtual bool isEmpty() = 0; 66 | 67 | }; 68 | 69 | 70 | #endif //ALG_INTERFACE_H 71 | -------------------------------------------------------------------------------- /玩转儿数据结构/linklist/203ListNode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | struct ListNode { 11 | int val; 12 | ListNode *next; 13 | 14 | ListNode(int x) : val(x), next(NULL) {} 15 | 16 | ListNode(const vector &array) { 17 | if (array.size() == 0) 18 | throw "array cannot be empty"; 19 | this->val = array[0]; 20 | ListNode *cur = this; 21 | for (int i=1;inext = new ListNode(array[i]); 23 | cur = cur->next; 24 | } 25 | } 26 | 27 | friend ostream &operator<<(ostream &out, ListNode &listNode) { 28 | out << "List:head "; 29 | ListNode *cur = &listNode; 30 | while (cur) { 31 | out << cur->val << "->"; 32 | cur=cur->next; 33 | } 34 | out<<"NULL"<val == val) head = head->next; 45 | 46 | ListNode *cur = head, *prev = head; 47 | while (cur) { 48 | if (cur->val == val) { 49 | prev->next = cur->next; 50 | } else { 51 | prev = cur; 52 | } 53 | cur = cur->next; 54 | } 55 | return head; 56 | } 57 | /** 58 | * 对上述简化 59 | * @param head 60 | * @param val 61 | * @return 62 | */ 63 | ListNode *removeElements1(ListNode *head, int val) { 64 | ListNode *HEAD = new ListNode(-1), *pre = HEAD; 65 | HEAD->next = head; 66 | while (pre->next) { 67 | if (pre->next->val == val) { 68 | pre->next = pre->next->next; 69 | } else { 70 | pre = pre->next; 71 | } 72 | } 73 | pre = HEAD->next; 74 | delete HEAD; 75 | return pre; 76 | } 77 | /** 78 | * 递归 79 | * @param head 80 | * @param val 81 | * @return 82 | */ 83 | ListNode *removeElements2(ListNode *head, int val) { 84 | if (head == NULL) return head; 85 | // 后面 n-1几个节点删除后的链表 head 86 | ListNode *back = removeElements2(head->next, val); 87 | // 考虑当前节点 如果当前节点是删除节点,就直接返回前面back的头 88 | if (head->val == val) 89 | return back; 90 | // 否则当前节点不需要被删除,那么就连接上,并返回当前节点即可。 91 | head->next = back; 92 | return head; 93 | } 94 | 95 | // 上述简化版 96 | ListNode *removeElements3(ListNode *head, int val) { 97 | if (head == NULL) return head; 98 | // 后面 n-1几个节点删除后的链表 head 99 | head->next = removeElements3(head->next, val); 100 | // 考虑当前节点 如果当前节点是删除节点,就直接返回前面back的头 101 | if (head->val == val) 102 | return head->next; 103 | // 否则当前节点不需要被删除,那么就连接上,并返回当前节点即可。 104 | return head; 105 | } 106 | }; 107 | 108 | 109 | int main() { 110 | vector array{1,3,5,6,8,6}; 111 | ListNode *listNode = new ListNode(array); 112 | 113 | cout<<*listNode< *linkedList = new LinkedList; 11 | 12 | for (int i = 0; i < 10; i++) { 13 | linkedList->add(i, i); 14 | } 15 | 16 | cout << linkedList->get(9) << endl; 17 | cout << linkedList->getSize() << endl; 18 | 19 | cout << *linkedList << endl; 20 | linkedList->addFirst(100); 21 | cout << *linkedList << endl; 22 | linkedList->addLast(101); 23 | cout << *linkedList << endl; 24 | cout << linkedList->contains(101) << endl; 25 | 26 | linkedList->remove(2); // index=2 delete 1 27 | cout << *linkedList << endl; 28 | 29 | linkedList->removeFirst(); 30 | cout << *linkedList << endl; 31 | 32 | linkedList->removeLast(); 33 | cout << *linkedList << endl; 34 | 35 | delete linkedList; 36 | 37 | 38 | 39 | LinkedListStack *stack = new LinkedListStack(); 40 | 41 | for (int i = 0; i < 5; i++) { 42 | stack->push(i); 43 | cout << *stack << endl; 44 | } 45 | 46 | stack->pop(); 47 | cout << *stack << endl; 48 | 49 | cout << stack->peek() << endl; 50 | 51 | delete stack; 52 | 53 | 54 | LinkedListQueue *queue= new LinkedListQueue(); 55 | 56 | for (int i = 0; i < 5; i++) { 57 | queue->enqueue(i); 58 | cout << *queue<< endl; 59 | } 60 | 61 | queue->dequeue(); 62 | cout << *queue<< endl; 63 | 64 | cout << queue->getFront() << endl; 65 | 66 | delete queue; 67 | 68 | return 0; 69 | } -------------------------------------------------------------------------------- /玩转儿数据结构/linklist/LinkedList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | 5 | #include 6 | 7 | #include "../interface.h" 8 | 9 | using namespace std; 10 | #ifndef ALG_LINKEDLIST_H 11 | #define ALG_LINKEDLIST_H 12 | 13 | template 14 | class LinkedList { 15 | private: 16 | class Node { 17 | public: 18 | T e; 19 | Node *next; 20 | 21 | Node(T e, Node *next) : e(e), next(next) {} 22 | 23 | Node(T e) : e(e), next(NULL) {} 24 | 25 | friend ostream &operator<<(ostream &out, Node &node) { 26 | out << "node value is " << node.e << endl; 27 | return out; 28 | } 29 | }; 30 | 31 | Node *dummyHead; 32 | int size; 33 | public: 34 | LinkedList() { 35 | T dummyVal; 36 | dummyHead = new Node(dummyVal); 37 | size = 0; 38 | } 39 | 40 | ~LinkedList() { 41 | Node *cur = dummyHead; 42 | while (cur) { 43 | delete cur; 44 | size--; 45 | cur = cur->next; 46 | } 47 | } 48 | 49 | int getSize() { 50 | return size; 51 | } 52 | 53 | bool isEmpty() { 54 | return size == 0; 55 | } 56 | 57 | // O(n) 58 | void add(int index, T e) { 59 | if (index < 0 || index > size) 60 | throw "add failed. Illegal index."; 61 | 62 | Node *prev = dummyHead; 63 | for (int i = 0; i < index; i++) { 64 | prev = prev->next; 65 | } 66 | // Node *node = new Node(e); 67 | // node->next = prev->next; 68 | // prev->next = node; 69 | prev->next = new Node(e, prev->next); 70 | size++; 71 | } 72 | 73 | // O(1) 74 | void addFirst(T e) { 75 | add(0, e); 76 | } 77 | 78 | // O(n) 79 | void addLast(T e) { 80 | add(size, e); 81 | } 82 | 83 | // O(n) 84 | T get(int index) { 85 | if (index < 0 || index >= size) 86 | throw "get failed.Illegal index. "; 87 | Node *cur = dummyHead->next; 88 | for (int i = 0; i < index; i++) { 89 | cur = cur->next; 90 | } 91 | return cur->e; 92 | } 93 | 94 | T getFirst() { 95 | return get(0); 96 | } 97 | 98 | T getLast() { 99 | return get(size - 1); 100 | } 101 | 102 | // O(n) 103 | bool contains(T e) { 104 | Node *cur = dummyHead->next; 105 | while (cur) { 106 | if (cur->e == e) 107 | return true; 108 | cur = cur->next; 109 | } 110 | return false; 111 | } 112 | 113 | // O(n) 114 | T remove(int index) { 115 | if (index < 0 || index >= size) 116 | throw "Remove failed.Illegal index. "; 117 | Node *prev = dummyHead; 118 | for (int i = 0; i < index; i++) { 119 | prev = prev->next; 120 | } 121 | Node *retNode = prev->next; 122 | prev->next = retNode->next; 123 | retNode->next = NULL; 124 | size--; 125 | return retNode->e; 126 | } 127 | 128 | // O(1) 129 | T removeFirst() { 130 | return remove(0); 131 | } 132 | 133 | // O(n) 134 | T removeLast() { 135 | return remove(size - 1); 136 | } 137 | 138 | void removeElement(T e) { 139 | Node *prev = dummyHead; 140 | while (prev->next) 141 | if (prev->next->e == e) { 142 | size--; 143 | prev->next = prev->next->next; 144 | } else 145 | prev = prev->next; 146 | return; 147 | } 148 | 149 | friend ostream &operator<<(ostream &out, LinkedList &linkedList) { 150 | Node *cur = linkedList.dummyHead->next; 151 | while (cur) { 152 | out << cur->e << "->"; 153 | cur = cur->next; 154 | } 155 | out << "NULL" << endl; 156 | return out; 157 | } 158 | }; 159 | 160 | #endif //ALG_LINKEDLIST_H 161 | -------------------------------------------------------------------------------- /玩转儿数据结构/queue/ArrayQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-7. 3 | // 4 | 5 | #ifndef ALG_ARRAYQUEUE_H 6 | #define ALG_ARRAYQUEUE_H 7 | 8 | 9 | #include "../array/array.h" 10 | #include 11 | 12 | // 基于动态数组的单向队列 13 | template 14 | class ArrayQueue : public BaseQueue { 15 | private: 16 | Array *array; 17 | public: 18 | ArrayQueue(int capacity) { 19 | array = new Array(capacity); 20 | } 21 | 22 | ArrayQueue() { 23 | array = new Array(); 24 | } 25 | ~ArrayQueue() { 26 | delete []array; 27 | } 28 | int getSize() { 29 | return array->getSize(); 30 | } 31 | 32 | bool isEmpty() { 33 | return array->isEmpty(); 34 | } 35 | 36 | T getCapacity() { 37 | return array->getCapacity(); 38 | } 39 | // 入队: 尾部 O(1) 40 | void enqueue(T e) { 41 | array->addLast(e); 42 | } 43 | // 出队:头部 O(n) 44 | T dequeue() { 45 | return array->removeFirst(); 46 | } 47 | 48 | T getFront() { 49 | return array->getFirst(); 50 | } 51 | 52 | friend ostream &operator<<(ostream &out, ArrayQueue &queue) { 53 | out << *(queue.array); 54 | return out; 55 | } 56 | }; 57 | 58 | 59 | #endif //ALG_ARRAYQUEUE_H 60 | -------------------------------------------------------------------------------- /玩转儿数据结构/queue/LinkedListQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | #include "../interface.h" 5 | 6 | #ifndef ALG_LINKEDLISTQUEUE_H 7 | #define ALG_LINKEDLISTQUEUE_H 8 | 9 | 10 | // 基于链表的队列 11 | // 队尾插入 队首删除 12 | template 13 | class LinkedListQueue : public BaseQueue { 14 | private: 15 | class Node { 16 | public: 17 | T e; 18 | Node *next; 19 | 20 | Node(T e, Node *next) : e(e), next(next) {} 21 | 22 | Node(T e) : e(e), next(NULL) {} 23 | 24 | friend ostream &operator<<(ostream &out, Node &node) { 25 | out << "node value is " << node.e << endl; 26 | return out; 27 | } 28 | }; 29 | 30 | Node *head; 31 | Node *tail; 32 | int size; 33 | public: 34 | LinkedListQueue() : head(NULL), tail(NULL), size(0) { 35 | 36 | } 37 | 38 | ~LinkedListQueue() { 39 | Node *cur = head; 40 | while (head) { 41 | cur = cur->next; 42 | delete cur; 43 | size--; 44 | } 45 | } 46 | 47 | bool isEmpty() { 48 | return size == 0; 49 | } 50 | 51 | int getSize() { 52 | return size; 53 | } 54 | 55 | void enqueue(T e) { 56 | if (NULL == tail) { 57 | tail = new Node(e); 58 | head = tail; 59 | } else { 60 | tail->next = new Node(e); 61 | tail = tail->next; 62 | } 63 | size++; 64 | } 65 | 66 | T dequeue() { 67 | if (isEmpty()) 68 | throw "Cannot dequeue from an empty queue."; 69 | Node *retNode = head; 70 | head = head->next; 71 | retNode->next = NULL; 72 | if (head == NULL) 73 | tail == head; 74 | size--; 75 | return retNode->e; 76 | } 77 | 78 | T getFront() { 79 | if (isEmpty()) 80 | throw "Cannot dequeue from an empty queue."; 81 | return head->e; 82 | } 83 | 84 | friend ostream &operator<<(ostream &out, LinkedListQueue &linkedListQueue) { 85 | out << "Queue:front "; 86 | Node *cur = linkedListQueue.head; 87 | while (cur != NULL) { 88 | out << cur->e << "->"; 89 | cur = cur->next; 90 | } 91 | out << "NULL tail" << endl; 92 | return out; 93 | } 94 | }; 95 | 96 | #endif //ALG_LINKEDLISTQUEUE_H 97 | -------------------------------------------------------------------------------- /玩转儿数据结构/queue/loopQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-9. 3 | // 4 | 5 | #ifndef ALG_LOOPQUEUE_H 6 | #define ALG_LOOPQUEUE_H 7 | 8 | // 基于动态数组的循环队列 9 | template 10 | class loopQueue : public BaseQueue { 11 | private: 12 | T *data; 13 | int front, tail; 14 | int size; 15 | int capacity; 16 | int total; 17 | public: 18 | loopQueue(int capacity) { 19 | this->data = new T[capacity + 1]; // 浪费了一个空间 (tail+1)%capacity=front 队满 20 | this->size = size; 21 | this->capacity = capacity; 22 | this->front = this->tail = 0; 23 | this->total = capacity + 1; 24 | } 25 | 26 | loopQueue() { 27 | this->capacity = 10; 28 | this->data = new T[capacity + 1]; // 浪费了一个空间 (tail+1)%capacity=front 队满 29 | this->size = 0; 30 | this->front = this->tail = 0; 31 | this->total = capacity + 1; 32 | } 33 | 34 | ~loopQueue() { 35 | delete []data; 36 | } 37 | 38 | T getCapacity() { 39 | return capacity; 40 | } 41 | 42 | bool isEmpty() { 43 | return front == tail; 44 | } 45 | 46 | int getSize() { 47 | return size; 48 | } 49 | 50 | void enqueue(T e) { 51 | if ((tail + 1) % total == front) { 52 | resize(getCapacity() * 2); 53 | } 54 | data[tail] = e; 55 | tail = (tail + 1) % total; 56 | size++; 57 | } 58 | 59 | void resize(int newCapacity) { 60 | T *newData = new T[newCapacity + 1]; 61 | for (int i = 0; i < size; i++) 62 | newData[i] = data[(i + front) % total]; 63 | capacity = newCapacity; 64 | total = capacity + 1; 65 | data = newData; 66 | front = 0; 67 | tail = size; 68 | } 69 | 70 | T dequeue() { 71 | if (isEmpty()) 72 | throw "Cannot dequeue from an empty queue."; 73 | T ret = data[front]; 74 | data[front] = NULL; 75 | front = (front + 1) % total; 76 | size--; 77 | if (size == getCapacity() / 4 && getCapacity() / 2 != 0) 78 | resize(getCapacity() / 2); 79 | return ret; 80 | } 81 | 82 | T getFront() { 83 | if (isEmpty()) 84 | throw "Queue is Empty."; 85 | return data[front]; 86 | } 87 | 88 | friend ostream &operator<<(ostream &out, loopQueue &lq) { 89 | out << "loopQueue: size = " << lq.getSize() << ", capacity = " << lq.getCapacity() << endl; 90 | out << "front ["; 91 | for (int i = lq.front; i != lq.tail; i = (i + 1) % lq.total) { 92 | out << lq.data[i]; 93 | if ((i + 1) % lq.total != lq.tail) 94 | out << ", "; 95 | } 96 | out << "] tail" << endl; 97 | return out; 98 | } 99 | }; 100 | 101 | #endif //ALG_LOOPQUEUE_H 102 | -------------------------------------------------------------------------------- /玩转儿数据结构/rbtree/rb_tree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-17. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | /** 12 | * 13 | * 红黑树的性质: 保持"黑平衡"的二叉树:指的是最后一个性质 严格意义上,不是平衡二叉树 最大高度:O(2logn) 14 | 每个节点或是红色的,或是黑色的。 15 | 根节点是黑色的。 16 | 每个叶节点(最后的空节点)是黑色的。 17 | 如果一个节点是红色的,则它的两个孩子节点都是黑色的。 18 | 阐述上述性质:对应到2-3树中,该红色节点的孩子要么是2节点,要么是3节点,如果是2节点,肯定为黑色,如果是3节点,肯定与3节点对应的红黑树的根节点连接,而根节点又是黑色,所以红色节点连接的孩子都是黑色节点。 19 | 黑色节点右孩子一定是黑色,道理同前面阐述。但左孩子不一定,左孩子是红色的,表示原来是3节点,如果左孩子是黑色的,表示在原来2-3树中都是2节点。 20 | 从任意一个节点到叶子节点,经过的黑色节点是一样的。 21 | 阐述上述性质:根据2-3树与红黑树的关系对比图,可以发现,红黑树中一个黑色节点对应2-3树中一整个节点(“2节点”或“3节点”)。 22 | 而2-3树是完全平衡的树,从根节点到任意路径的叶子节点,经过的节点个数都是相同的,对应红黑树中,即从任意节点到叶子节点,经过的黑色节点是一样的。 23 | 24 | * @tparam Key 25 | * @tparam Value 26 | */ 27 | 28 | template 29 | class RBTree { 30 | /** 31 | * 封装到私有,让外界不知道具体实现 32 | */ 33 | private: 34 | enum _Rb_tree_color { 35 | RED = true, 36 | BLACK = false 37 | }; 38 | private: 39 | struct Node { 40 | Key key; 41 | Value value; 42 | Node *left; 43 | Node *right; 44 | bool color; 45 | 46 | Node(Key key, Value value) { 47 | this->key = key; 48 | this->value = value; 49 | this->left = this->right = NULL; 50 | this->color = RED; // 对应的2-3树中节点融合 默认为RED 51 | } 52 | 53 | Node(Node *node) { 54 | this->key = node->key; 55 | this->value = node->value; 56 | this->left = node->left; 57 | this->right = node->right; 58 | this->color = node->color; 59 | } 60 | }; 61 | 62 | public: 63 | Node *root; 64 | int count; 65 | public: 66 | RBTree() { 67 | root = NULL; 68 | count = 0; 69 | } 70 | 71 | ~RBTree() { 72 | destroy(root); 73 | } 74 | 75 | int size() { 76 | return count; 77 | } 78 | 79 | bool isEmpty() { 80 | return count == 0; 81 | // return root==0; 82 | } 83 | 84 | // 判断节点node的颜色 85 | bool isRed(Node *node) { 86 | if (node == NULL) return BLACK; 87 | return node->color; 88 | } 89 | 90 | // 向红黑树中添加新的元素(key,value) 91 | void insert(Key key, Value value) { 92 | root = insert(root, key, value); 93 | root->color = BLACK; // 维持根节点颜色为黑色 94 | } 95 | 96 | // 是否包含key 97 | bool contain(Key key) { 98 | return contain(root, key); 99 | } 100 | 101 | // 重复key设值 102 | void set(Key key, Value newValue) { 103 | Node *node = Search(root, key); 104 | if (node == NULL) 105 | cerr << key + " doesn't exist!" << endl; 106 | node->value = newValue; 107 | 108 | } 109 | 110 | // get 获取节点 111 | Value *search(Key key) { 112 | return search(root, key); 113 | } 114 | 115 | void preOrder() { 116 | perOrder(root); 117 | } 118 | 119 | void postOrder() { 120 | postOrder(root); 121 | } 122 | 123 | void levelOrder() { 124 | queue q; 125 | q.push(root); 126 | int depth = 0; 127 | while (!q.empty()) { 128 | int total = q.size(); 129 | cout << "第" << depth << "层" << endl; 130 | while (total--) { 131 | Node *node = q.front(); 132 | q.pop(); 133 | print(node); 134 | if (node->left) q.push(node->left); 135 | if (node->right) q.push(node->right); 136 | } 137 | depth++; 138 | } 139 | } 140 | 141 | // 向左找,为最小 142 | // 向右找,为最大 143 | Key minimum() { 144 | Node *minNode = minimum(root); 145 | return minNode->key; 146 | } 147 | 148 | Key maximum() { 149 | Node *maxNode = maximum(root); 150 | return maxNode->key; 151 | } 152 | 153 | void removeMin() { 154 | if (root) 155 | root = removeMin(root); 156 | } 157 | 158 | void removeMax() { 159 | if (root) 160 | root = removeMax(root); 161 | } 162 | 163 | void remove(Key key) { 164 | root = remove(root, key); 165 | } 166 | 167 | Node *predecessor(Key key) { 168 | return predecessor(root, key); 169 | } 170 | 171 | Node *successor(Key key) { 172 | return successor(root, key); 173 | } 174 | 175 | Node *ceil(Key key) { 176 | // 空树或给定的key超过树中最大的key 177 | if (count == 0 || key > maximum()) return NULL; 178 | return ceil(root, key); 179 | } 180 | 181 | Node *floor(Key key) { 182 | // 空树或给定的key超过树中最大的key 183 | if (count == 0 || key < minimum()) return NULL; 184 | return floor(root, key); 185 | } 186 | 187 | private: 188 | 189 | // node x 190 | // / \ 左旋转 / \ 191 | // T1 x ---------> node T3 192 | // / \ / \ 193 | // T2 T3 T1 T2 194 | Node *leftRotate(Node *node) { // 对应到2-3树中向2节点添加一个新元素 195 | Node *x = node->right; 196 | // 左旋转 197 | node->right = x->left; 198 | x->left = node; 199 | 200 | x->color = node->color; 201 | node->color = RED; 202 | 203 | return x; 204 | } 205 | 206 | 207 | // node x 208 | // / \ 右旋转 / \ 209 | // x T2 --------------> y node 210 | // / \ / \ 211 | // y T1 T1 T2 212 | Node *rightRotate(Node *node) { // 对应到2-3树中向2节点添加一个新元素 213 | Node *x = node->left; 214 | // 左旋转 215 | node->left = x->right; 216 | x->right = node; 217 | 218 | x->color = node->color; 219 | node->color = RED; 220 | 221 | return x; 222 | } 223 | 224 | 225 | // 颜色翻转 226 | void flipColors(Node *node) { // 对应到2-3树中3节点添加一个新元素 右边插入 227 | node->color = RED; 228 | node->left->color = BLACK; 229 | node->right->color = BLACK; 230 | } 231 | 232 | 233 | /** 234 | * 递归插入 235 | * 向以node为根的红黑树中插入元素(key,value) 236 | * 返回插入新节点后红黑树的根 237 | * @param node 238 | * @param key 239 | * @param value 240 | * @return 241 | */ 242 | Node *insert(Node *node, Key key, Value value) { 243 | if (node == NULL) { 244 | count++; 245 | return new Node(key, value); // 默认插入红色节点 246 | } 247 | 248 | if (key == node->key) 249 | node->value = value; 250 | else if (key < node->key) 251 | node->left = insert(node->left, key, value); 252 | else 253 | node->right = insert(node->right, key, value); 254 | 255 | // 左旋转 256 | if (isRed(node->right) && !isRed(node->left)) 257 | node = leftRotate(node); 258 | 259 | // 右旋转 260 | if (isRed(node->left) && isRed(node->left->left)) 261 | node = rightRotate(node); 262 | 263 | // 颜色翻转 264 | if (isRed(node->left) && isRed(node->right)) 265 | flipColors(node); 266 | 267 | 268 | return node; 269 | } 270 | 271 | /** 272 | * 非递归插入 273 | * @param node 274 | * @param key 275 | * @param value 276 | * @return 277 | */ 278 | Node *Non_Recursion_InsertNode(Node *node, Key key, Value value) { 279 | if (node == NULL) { 280 | node = new Node(key, value); 281 | return node; 282 | } 283 | Node *pre = node; 284 | Node *cur = node; 285 | 286 | while (cur) { 287 | pre = cur; 288 | if (key == node->key) { 289 | node->value = value; 290 | return node; 291 | } else if (key < node->key) 292 | cur = cur->left; 293 | else 294 | cur = cur->right; 295 | } 296 | if (key < node->key) 297 | pre->left = new Node(key, value); 298 | else 299 | pre->right = new Node(key, value); 300 | } 301 | 302 | /** 303 | * 递归查找key是否存在 304 | * @param node 305 | * @param key 306 | * @return 307 | */ 308 | bool contain(Node *node, Key key) { 309 | if (node == NULL) return false; 310 | if (key == node->key) return true; 311 | else if (key < node->key) 312 | return contain(node->left, key); 313 | else 314 | return contain(node->right, key); 315 | } 316 | 317 | /** 318 | * 非递归查找key是否存在 319 | * @param node 320 | * @param key 321 | * @return 322 | */ 323 | bool Non_Recursion_Contain(Node *node, Key key) { 324 | if (node == NULL) { 325 | return false; 326 | } 327 | Node *cur = node; 328 | 329 | while (cur) { 330 | if (key == node->key) { 331 | return true; 332 | } else if (key < node->key) 333 | cur = cur->left; 334 | else 335 | cur = cur->right; 336 | } 337 | return false; 338 | } 339 | 340 | Value *search(Node *node, Key key) { 341 | if (node == NULL) return NULL; 342 | 343 | if (key == node->key) return &node->value; 344 | else if (key < node->key) 345 | return search(node->left, key); 346 | else 347 | return search(node->right, key); 348 | } 349 | 350 | // getNode 获取对应节点 351 | Node *Search(Node *node, Key key) { 352 | if (node == NULL) return NULL; 353 | 354 | if (key == node->key) return node; 355 | else if (key < node->key) 356 | return Search(node->left, key); 357 | else 358 | return Search(node->right, key); 359 | } 360 | 361 | void preOrder(Node *node) { 362 | if (node) { 363 | cout << node->key << endl; 364 | preOrder(node->left); 365 | preOrder(node->right); 366 | } 367 | } 368 | 369 | void print(Node *node) { 370 | string c = node->color != RED ? "黑" : "红"; 371 | cout << node->key << ":" << node->value << ":" << c << endl; 372 | } 373 | 374 | void inOrder(Node *node) { 375 | if (node) { 376 | inOrder(node->left); 377 | cout << node->key << endl; 378 | inOrder(node->right); 379 | } 380 | } 381 | 382 | void postOrder(Node *node) { 383 | if (node) { 384 | postOrder(node->left); 385 | postOrder(node->right); 386 | cout << node->key << endl; 387 | } 388 | } 389 | 390 | void destroy(Node *node) { 391 | if (node) { 392 | destroy(node->left); 393 | destroy(node->right); 394 | delete node; 395 | count--; 396 | } 397 | } 398 | 399 | Node *minimum(Node *node) { 400 | if (node->left == NULL) return node; 401 | return minimum(node->left); 402 | } 403 | 404 | // 非递归 405 | Node *minimum1(Node *node) { 406 | Node *currentNode = node; 407 | if (currentNode == NULL) 408 | return NULL; 409 | 410 | while (currentNode->left != NULL) { 411 | currentNode = currentNode->left; 412 | } 413 | return currentNode; 414 | } 415 | 416 | Node *maximum(Node *node) { 417 | if (node->right == NULL) return node; 418 | return maximum(node->right); 419 | } 420 | 421 | // 非递归 422 | Node *maximum1(Node *node) { 423 | Node *currentNode = node; 424 | if (currentNode == NULL) 425 | return NULL; 426 | 427 | while (currentNode->right != NULL) { 428 | currentNode = currentNode->right; 429 | } 430 | return currentNode; 431 | } 432 | 433 | Node *removeMin(Node *node) { 434 | if (node->left == NULL) { 435 | Node *rightNode = node->right; 436 | delete node; 437 | count--; 438 | return rightNode; 439 | } 440 | node->left = removeMin(node->left); 441 | return node; 442 | } 443 | 444 | // 非递归 返回curNode->right节点 445 | Node *removeMin1(Node *node) { 446 | Node *root = node; 447 | Node *currentNode = node, *p = node; 448 | Node *parentNode = node; 449 | // 空 450 | if (currentNode == NULL) 451 | return NULL; 452 | // 迭代 453 | while (currentNode->left != NULL) { 454 | parentNode = currentNode; 455 | currentNode = currentNode->left; 456 | } 457 | // 传递进来的左孩子本身就为空 458 | if (currentNode == parentNode) { 459 | Node *tmp = currentNode->right; 460 | delete currentNode; // 此时的currentNode为最大节点 461 | count--; 462 | return tmp; 463 | } 464 | // 传递进来的左孩子本身不为空,而是通过迭代到最小节点 465 | parentNode->left = currentNode->right; 466 | // 删除掉currentNode 467 | delete currentNode; // 此时的currentNode为最小节点 468 | count--; 469 | return p; 470 | } 471 | 472 | Node *removeMax(Node *node) { 473 | if (node->right == NULL) { 474 | Node *leftNode = node->left; 475 | delete node; 476 | count--; 477 | return leftNode; 478 | } 479 | return node; 480 | } 481 | 482 | // 非递归 483 | Node *removeMax1(Node *node) { 484 | Node *currentNode = node, *p = node; 485 | Node *parentNode = node; 486 | if (currentNode == NULL) 487 | return currentNode; 488 | 489 | while (currentNode->right != NULL) { 490 | parentNode = currentNode; 491 | currentNode = currentNode->right; 492 | } 493 | if (currentNode == parentNode) { 494 | Node *tmp = currentNode->left; 495 | delete currentNode; // 此时的currentNode为最大节点 496 | count--; 497 | return tmp; 498 | } 499 | parentNode->right = currentNode->left; 500 | delete currentNode; // 此时的currentNode为最大节点 501 | count--; 502 | return p; 503 | } 504 | 505 | /** 506 | * 删除节点 507 | * @param node 508 | * @param key 509 | * @return 510 | */ 511 | Node *remove(Node *node, Key key) { 512 | if (node == NULL) return NULL; 513 | // 左孩子查找 514 | if (key < node->key) { 515 | node->left = remove(node->left, key); 516 | return node; 517 | // 右孩子查找 518 | } else if (key > node->key) { 519 | node->right = remove(node->right, key); 520 | return node; 521 | // 查找到了key 522 | } else { // key == node->key 523 | // 左孩子为空,就直接以右孩子取缔 524 | if (node->left == NULL) { // 左孩子为空包含两部分(左孩子为空与左右孩子均为空) 525 | Node *rightNode = node->right; 526 | delete node; 527 | count--; 528 | return rightNode; 529 | } 530 | // 右孩子为空,就直接以左孩子取缔 531 | if (node->right == NULL) { 532 | Node *leftNode = node->left; 533 | delete node; 534 | count--; 535 | return leftNode; 536 | } 537 | // 左右孩子均不为空,取右孩子子树中最小或取左孩子子树中最大 538 | // node->left!=NULL && node->right!=NULL 539 | // 右孩子子树中最小方法 540 | Node *successor = new Node( 541 | minimum(node->right)); // 在removeMin中将最小节点删除了,后面再次访问successor会为NULL,所以此时需要重新new 分配内存 542 | count++; 543 | successor->right = removeMin(node->right); 544 | successor->left = node->left; 545 | delete node; 546 | count--; 547 | 548 | 549 | // 左孩子子树中最大方法 550 | /** 551 | Node *successor = new Node(maximum(node->left)); 552 | count++; 553 | successor->left= removeMin(node->left); 554 | successor->right= node->right; 555 | delete node; 556 | count--; 557 | */ 558 | return successor; 559 | } 560 | } 561 | 562 | // 以左侧最大取代非递归删除 563 | Node *deleteNode(Node *root, Key key) { 564 | if (root == NULL) return NULL; 565 | Node *currentNode = root; 566 | Node *parentNode = root; 567 | 568 | //定位到要删除的key 的父节点,以及当前元素 569 | while (currentNode != NULL && currentNode->val != key) { 570 | parentNode = currentNode; 571 | if (currentNode->key > key) { 572 | currentNode = currentNode->left; 573 | } else { 574 | currentNode = currentNode->right; 575 | } 576 | 577 | } 578 | // 表示没找到key,直接返回结果 579 | if (currentNode == NULL) return root; 580 | // 表示与key相等的是根节点,根节点直接处理,不需要保存父节点 581 | if (parentNode == currentNode) { 582 | // 左分支为空,以右分支取缔 583 | if (currentNode->left == NULL) { 584 | Node *tmp = currentNode->right; 585 | delete currentNode; 586 | count--; 587 | return tmp; 588 | } 589 | // 右分支为空,以左分支取缔 590 | if (currentNode->right == NULL) { 591 | Node *tmp = currentNode->left; 592 | delete currentNode; 593 | count--; 594 | return tmp; 595 | } 596 | // 取左分支最大节点取代当前节点,并删除当前节点 597 | Node *delnode = new Node(maximum1(currentNode->left)->val); 598 | delnode->left = removeMax1(currentNode->left); 599 | delnode->right = currentNode->right; 600 | delete currentNode; 601 | count--; 602 | return delnode; 603 | } 604 | // key不是根节点,需要判断父节点与当前节点的关系,有可能是右分支,也可能是左分支 605 | 606 | // 左分支关系 607 | if (parentNode->left == currentNode) { 608 | if (currentNode->left == NULL) { 609 | parentNode->left = currentNode->right; 610 | delete currentNode; 611 | count--; 612 | return root; 613 | } 614 | if (currentNode->right == NULL) { 615 | parentNode->left = currentNode->left; 616 | delete currentNode; 617 | count--; 618 | return root; 619 | } 620 | Node *delnode = new Node(maximum1(currentNode->left)->val); 621 | count++; 622 | delnode->left = deleteMax(currentNode->left); 623 | delnode->right = currentNode->right; 624 | // 父节点左孩子更新为左边最大的节点 625 | parentNode->left = delnode; 626 | delete currentNode; 627 | count--; 628 | return root; 629 | } 630 | // 右分支关系 631 | if (parentNode->right == currentNode) { 632 | if (currentNode->left == NULL) { 633 | parentNode->right = currentNode->right; 634 | delete currentNode; 635 | count--; 636 | return root; 637 | } 638 | if (currentNode->right == NULL) { 639 | parentNode->right = currentNode->left; 640 | delete currentNode; 641 | count--; 642 | return root; 643 | } 644 | Node *delnode = new Node(maximum1(currentNode->left)->val); 645 | count++; 646 | delnode->left = removeMax1(currentNode->left); 647 | delnode->right = currentNode->right; 648 | // 父节点右孩子更新为左边最大的节点 649 | parentNode->right = delnode; 650 | delete currentNode; 651 | count--; 652 | return root; 653 | } 654 | return root; 655 | } 656 | 657 | // 以右侧最小取代非递归删除 658 | Node *deleteNode1(Node *root, int key) { 659 | if (root == NULL) return NULL; 660 | Node *currentNode = root; 661 | Node *parentNode = root; 662 | 663 | //定位到要删除的key 的父节点,以及当前元素 664 | while (currentNode != NULL && currentNode->key != key) { 665 | parentNode = currentNode; 666 | if (currentNode->key > key) { 667 | currentNode = currentNode->left; 668 | } else { 669 | currentNode = currentNode->right; 670 | } 671 | 672 | } 673 | 674 | if (currentNode == NULL) return root; 675 | // 根节点处理 676 | if (parentNode == currentNode) { 677 | if (currentNode->left == NULL) { 678 | Node *tmp = currentNode->right; 679 | delete currentNode; 680 | return tmp; 681 | } 682 | if (currentNode->right == NULL) { 683 | Node *tmp = currentNode->left; 684 | delete currentNode; 685 | return tmp; 686 | } 687 | Node *delnode = new Node(minimum1(currentNode->right)->val); 688 | delnode->right = removeMin1(currentNode->right); 689 | delnode->left = currentNode->left; 690 | delete currentNode; 691 | return delnode; 692 | } 693 | if (parentNode->left == currentNode) { 694 | 695 | if (currentNode->left == NULL) { 696 | parentNode->left = currentNode->right; 697 | delete currentNode; 698 | return root; 699 | } 700 | if (currentNode->right == NULL) { 701 | parentNode->left = currentNode->left; 702 | delete currentNode; 703 | return root; 704 | } 705 | Node *delnode = new Node(minimum1(currentNode->right)->val); 706 | delnode->right = removeMin1(currentNode->right); 707 | delnode->left = currentNode->left; 708 | parentNode->left = delnode; 709 | delete currentNode; 710 | return root; 711 | } 712 | if (parentNode->right == currentNode) { 713 | if (currentNode->left == NULL) { 714 | parentNode->right = currentNode->right; 715 | delete currentNode; 716 | return root; 717 | } 718 | if (currentNode->right == NULL) { 719 | parentNode->right = currentNode->left; 720 | delete currentNode; 721 | return root; 722 | } 723 | Node *delnode = new Node(minimum1(currentNode->right)->val); 724 | delnode->right = removeMin1(currentNode->right); 725 | delnode->left = currentNode->left; 726 | parentNode->right = delnode; 727 | delete currentNode; 728 | return root; 729 | } 730 | return root; 731 | } 732 | 733 | /** 734 | * 在node为根的二叉搜索树中,寻找key的祖先中,比key小的最大值所在节点.递归算法 735 | * 算法调用前已保证key存在在以node为根的二叉树中 736 | * @param node 737 | * @param key 738 | * @return 739 | */ 740 | Node *predecessorFromAncestor(Node *node, Key key) { 741 | if (node->key == key) 742 | return NULL; 743 | if (key < node->key) { // 我们目标是找比key小的最大key,如果比node的key小就应该在它的左子树中查找 744 | return predecessorFromAncestor(node->left, key); 745 | } else { // 此时的key小于node的key在右子树中查找 746 | assert(key > node->key); 747 | /** 748 | * 如果当前节点小于key,则当前节点有可能是比key小的最大值 749 | * 向右继续搜索,将结果存储到tmpNode中 750 | */ 751 | Node *tmpNode = predecessorFromAncestor(node->right, key); 752 | if (tmpNode) 753 | return tmpNode; 754 | else 755 | // 如果tmpNode为空,则当前节点即为结果 756 | return node; 757 | } 758 | } 759 | 760 | Node *predecessor(Node *root, Key key) { 761 | 762 | Node *node = Search(root, key); 763 | // 如果key所在的节点不存在, 则key没有前驱, 返回NULL 764 | if (node == NULL) 765 | return NULL; 766 | 767 | // 如果key所在的节点左子树不为空,则其左子树的最大值为key的前驱 768 | if (node->left != NULL) 769 | return maximum(node->left); 770 | 771 | // 否则, key的前驱在从根节点到key的路径上, 在这个路径上寻找到比key小的最大值, 即为key的前驱 772 | Node *preNode = predecessorFromAncestor(root, key); 773 | return preNode == NULL ? NULL : preNode; 774 | } 775 | 776 | /** 777 | * 找到目标为key的节点 778 | * 寻找key的父节点 779 | * 寻找距离key节点最近的右拐节点 780 | * @param node 781 | * @param key 782 | * @param parent 783 | * @param pRParent 784 | * @return 785 | */ 786 | Node *getTargetNodeRParent(Node *node, Key key, Node *&parent, Node *&firstRParent) { 787 | while (node) { 788 | if (node->key == key) { 789 | return node; 790 | } 791 | parent = node; 792 | if (node->key > key) { 793 | node = node->left; 794 | } else if (node->key < key) { 795 | firstRParent = node; //出现右拐点 796 | node = node->right; 797 | } 798 | } 799 | return NULL; 800 | } 801 | 802 | /** 803 | * 找到目标为key的节点 804 | * 寻找key的父节点 805 | * 寻找距离key节点最近的左拐节点 806 | * @param node 807 | * @param key 808 | * @param parent 809 | * @param pRParent 810 | * @return 811 | */ 812 | Node *getTargetNodeLParent(Node *node, Key key, Node *&parent, Node *&firstLParent) { 813 | while (node) { 814 | if (node->key == key) { 815 | return node; 816 | } 817 | parent = node; 818 | if (node->key > key) { 819 | firstLParent = node; //出现左拐点 820 | node = node->left; 821 | } else if (node->key < key) { 822 | node = node->right; 823 | } 824 | } 825 | return NULL; 826 | } 827 | // 非递归 查找对应节点的前继节点 828 | /** 829 | * (1)当前节点左孩子不为空,查找左孩子最大 830 | * (2)当前节点左孩子为空,判断当前节点与其父节点关系,若为右孩子,返回父节点 831 | * 若为左孩子.向上找,直到当前节点为某一节点的右分支,则返回某节点. 832 | * 这里分为两种数据结构: 833 | * 第一:带父节点的结构 直接使用父节点向上找 834 | * 第二:不带父节点结构 需要自上向下保存最后一个有右分支的节点(且目标节点在右分支) 835 | * @param node 836 | * @param key 837 | * @return 838 | */ 839 | Node *predecessor1(Node *node, Key key) { 840 | if (node == NULL) return NULL; 841 | Node *parent = NULL; 842 | Node *firstRParent = NULL; 843 | Node *targetNode = getTargetNodeRParent(root, key, parent, firstRParent); 844 | if (targetNode == NULL) return NULL; // 没有查找到目标为key的节点 845 | if (targetNode->left) return maximum(targetNode->left); // 有左子树,寻找左子树中最大节点 846 | if (parent == NULL || parent && firstRParent == NULL) return NULL; // 父亲节点为空或者没有右拐点说明无前驱节点 847 | if (targetNode == parent->right) return parent; // 当前节点为父亲节点的右孩子,直接返回父亲节点 848 | else 849 | return firstRParent; // 当前节点为父亲节点的左孩子,直接返回从上到下搜索的最后一个右拐点 850 | } 851 | 852 | /** 853 | * 在node为根的二叉搜索树中,寻找key的祖先中,比key大的最小值所在节点.递归算法 854 | * 算法调用前已保证key存在在以node为根的二叉树中 855 | * @param node 856 | * @param key 857 | * @return 858 | */ 859 | Node *successorFromAncestor(Node *node, Key key) { 860 | if (node->key == key) 861 | return NULL; 862 | if (key > node->key) { // 我们目标是找比key大的最小key,如果比node的key大就应该在它的右子树中查找 863 | return successorFromAncestor(node->right, key); 864 | } else { // 此时的key小于node的key在左子书中查找 865 | assert(key < node->key); 866 | /** 867 | * 如果当前节点大于key,则当前节点有可能是比key大的最小值 868 | * 向左继续搜索,将结果存储到tmpNode中 869 | */ 870 | Node *tmpNode = successorFromAncestor(node->left, key); 871 | if (tmpNode) 872 | return tmpNode; 873 | else 874 | // 如果tmpNode为空,则当前节点即为结果 875 | return node; 876 | } 877 | } 878 | 879 | // 查找key的后继, 递归算法 880 | // 如果不存在key的后继(key不存在, 或者key是整棵二叉树中的最大值), 则返回NULL 881 | Node *successor(Node *root, Key key) { 882 | 883 | Node *node = Search(root, key); 884 | // 如果key所在的节点不存在, 则key没有前驱, 返回NULL 885 | if (node == NULL) 886 | return NULL; 887 | 888 | // 如果key所在的节点右子树不为空,则其右子树的最小值为key的后继 889 | if (node->right != NULL) 890 | return minimum(node->right); 891 | 892 | // 否则, key的后继在从根节点到key的路径上, 在这个路径上寻找到比key大的最小值, 即为key的后继 893 | Node *sucNode = successorFromAncestor(root, key); 894 | return sucNode == NULL ? NULL : sucNode; 895 | } 896 | 897 | // 非递归 查找对应节点的后继节点 898 | Node *successor1(Node *node, Key key) { 899 | if (node == NULL) return NULL; 900 | Node *parent = NULL; 901 | Node *firstLParent = NULL; 902 | Node *targetNode = getTargetNodeLParent(root, key, parent, firstLParent); 903 | if (targetNode == NULL) return NULL; // 没有查找到目标哦为key的节点 904 | if (targetNode->right) return minimum(targetNode->right); // 有右子树,寻找右子树中最小节点 905 | if (parent == NULL || parent && firstLParent == NULL) return NULL; // 父亲节点为空或者没有左拐点说明无后继节点 906 | if (targetNode == parent->left) return parent; // 当前节点为父亲节点的左孩子,直接返回父亲节点 907 | else 908 | return firstLParent; //当前节点为父亲节点的右孩子,直接返回从上到下搜索的最后一个左拐点 909 | } 910 | 911 | //============================================================ 912 | /** 913 | * 拓展:带父节点数据结构 914 | */ 915 | //============================================================ 916 | /** 917 | * 带父节点数据结构,查找前驱节点,直接使用父节点向上找 918 | * @param node 919 | * @param key 920 | * @return 921 | */ 922 | Node *predecessor2(Node *node, Key key) { 923 | if (node->left) { 924 | return maximum(node->left); 925 | } 926 | Node *parent = node->parent; 927 | // 自下向上查找 928 | while (parent != NULL && node != parent->right) { 929 | node = parent; 930 | parent = node->parent; 931 | } 932 | return parent; 933 | } 934 | 935 | /** 936 | * 带父节点数据结构,直接后继节点,直接使用父节点向上找 937 | */ 938 | Node *successor2(Node *node, Key key) { 939 | if (node->right) { 940 | return minimum(node->right); 941 | } 942 | Node *parent = node->parent; 943 | while (parent != NULL && node != node->left) { 944 | node = parent; 945 | parent = node->parent; 946 | } 947 | return parent; 948 | } 949 | //============================================================ 950 | /** 951 | * 拓展结束 952 | */ 953 | //============================================================ 954 | 955 | 956 | /** 957 | * 地板 958 | * 在以node为根的二叉搜索树中,寻找key的floor值所处的节点,递归算法 959 | * @param root 960 | * @param key 961 | * @return 962 | */ 963 | Node *floor(Node *root, Key key) { 964 | if (root == NULL) return NULL; 965 | 966 | // 如果node的key值和要寻找的key值相等 967 | // 则node 本身就是key的floor节点 968 | if (key == root->key) return root; 969 | // 如果node的key比要寻找的key大 970 | // 则要寻找的key的floor节点一定在node的左边子树中 971 | if (root->key > key) return ceil(root->left, key); 972 | // 如果node的key小于要寻找的key 973 | // 则node有可能是key的floor节点,也有可能不是(存在比node->key大但小于key的其余节点) 974 | // 则要尝试向node的右子树寻找一下 975 | Node *tmpNode = ceil(root->right, key); 976 | if (tmpNode) return tmpNode; 977 | return root; 978 | } 979 | 980 | /** 981 | * 天花板 982 | * 在以node为根的二叉搜索树中,寻找key的ceil值所处的节点,递归算法 983 | * @param root 984 | * @param key 985 | * @return 986 | */ 987 | Node *ceil(Node *root, Key key) { 988 | if (root == NULL) return NULL; 989 | 990 | // 如果node的key值和要寻找的key值相等 991 | // 则node 本身就是key的ceil节点 992 | if (key == root->key) return root; 993 | // 如果node的key比要寻找的key小 994 | if (root->key < key) return ceil(root->right, key); 995 | // 如果node的key大于要寻找的keyo 996 | // 则node有可能是key的ceil节点,也有可能不是(存在比node->key小但大于key的其余节点) 997 | // 则要尝试向node的左子树寻找一下 998 | Node *tmpNode = ceil(root->left, key); 999 | if (tmpNode) return tmpNode; 1000 | return root; 1001 | } 1002 | 1003 | template 1004 | friend ostream &operator<<(ostream &out, const RBTree &rbTree); 1005 | }; 1006 | 1007 | //void shuffle(int arr[], int n) { 1008 | // srand(time(NULL)); 1009 | // for (int i = n - 1; i >= 0; i--) { 1010 | // int x = rand() % (i + 1); 1011 | // swap(arr[i], arr[x]); 1012 | // } 1013 | //} 1014 | 1015 | 1016 | template 1017 | ostream &operator<<(ostream &out, const RBTree &rbTree) { 1018 | cout << "{key: " << rbTree.root->key << ", " << "value:" << rbTree.root->value << ", " << "color:" 1019 | << rbTree.root->color << ", " << "left:" << 1020 | rbTree.root->left->key << "," << "right:" << rbTree.root->right->key << "}" << endl; 1021 | return out; 1022 | } 1023 | -------------------------------------------------------------------------------- /玩转儿数据结构/rbtree/rbmain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-18. 3 | // 4 | 5 | #include "rb_tree.h" 6 | 7 | 8 | int main() { 9 | time_t startTime = clock(); 10 | RBTree *rbTree = new RBTree(); 11 | 12 | 13 | // for (vector::iterator iter = words.begin(); iter != words.end(); iter++) { 14 | // int *res = (*rbTree).search(*iter); 15 | // if (res == NULL) 16 | // (*rbTree).insert(*iter, 1); 17 | // else 18 | // (*res)++; 19 | // } 20 | // 21 | // // 我们查看unite一词的词频 22 | // if (rbTree->contain("unite")) 23 | // cout << "'unite' : " << *(rbTree->search("unite")) << endl; 24 | // else 25 | // cout << "No word 'unite' in " + filename << endl; 26 | 27 | rbTree->insert(100, "v100"); 28 | rbTree->insert(50, "v50"); 29 | rbTree->insert(150, "v150"); 30 | rbTree->insert(20, "v20"); 31 | rbTree->insert(85, "v85"); 32 | rbTree->insert(10, "v10"); 33 | rbTree->insert(15, "a15"); 34 | rbTree->insert(75, "v75"); 35 | rbTree->insert(95, "v95"); 36 | rbTree->insert(65, "v65"); 37 | rbTree->insert(76, "v76"); 38 | rbTree->insert(60, "v60"); 39 | rbTree->insert(66, "v66"); 40 | rbTree->insert(61, "v61"); 41 | 42 | rbTree->levelOrder(); 43 | time_t endTime = clock(); 44 | 45 | cout << "RBTree, time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 46 | cout << endl; 47 | 48 | 49 | delete rbTree; 50 | } -------------------------------------------------------------------------------- /玩转儿数据结构/recursion/203ListNode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | struct ListNode { 11 | int val; 12 | ListNode *next; 13 | 14 | ListNode(int x) : val(x), next(NULL) {} 15 | 16 | ListNode(const vector &array) { 17 | if (array.size() == 0) 18 | throw "array cannot be empty"; 19 | this->val = array[0]; 20 | ListNode *cur = this; 21 | for (int i=1;inext = new ListNode(array[i]); 23 | cur = cur->next; 24 | } 25 | } 26 | 27 | friend ostream &operator<<(ostream &out, ListNode &listNode) { 28 | out << "List:head "; 29 | ListNode *cur = &listNode; 30 | while (cur) { 31 | out << cur->val << "->"; 32 | cur=cur->next; 33 | } 34 | out<<"NULL"<val == val) head = head->next; 45 | 46 | ListNode *cur = head, *prev = head; 47 | while (cur) { 48 | if (cur->val == val) { 49 | prev->next = cur->next; 50 | } else { 51 | prev = cur; 52 | } 53 | cur = cur->next; 54 | } 55 | return head; 56 | } 57 | /** 58 | * 对上述简化 59 | * @param head 60 | * @param val 61 | * @return 62 | */ 63 | ListNode *removeElements1(ListNode *head, int val) { 64 | ListNode *HEAD = new ListNode(-1), *pre = HEAD; 65 | HEAD->next = head; 66 | while (pre->next) { 67 | if (pre->next->val == val) { 68 | pre->next = pre->next->next; 69 | } else { 70 | pre = pre->next; 71 | } 72 | } 73 | pre = HEAD->next; 74 | delete HEAD; 75 | return pre; 76 | } 77 | /** 78 | * 递归 79 | * @param head 80 | * @param val 81 | * @return 82 | */ 83 | ListNode *removeElements2(ListNode *head, int val) { 84 | if (head == NULL) return head; 85 | // 后面 n-1几个节点删除后的链表 head 86 | ListNode *back = removeElements2(head->next, val); 87 | // 考虑当前节点 如果当前节点是删除节点,就直接返回前面back的头 88 | if (head->val == val) 89 | return back; 90 | // 否则当前节点不需要被删除,那么就连接上,并返回当前节点即可。 91 | head->next = back; 92 | return head; 93 | } 94 | 95 | // 上述简化版 96 | ListNode *removeElements3(ListNode *head, int val) { 97 | if (head == NULL) return head; 98 | // 后面 n-1几个节点删除后的链表 head 99 | head->next = removeElements3(head->next, val); 100 | // 考虑当前节点 如果当前节点是删除节点,就直接返回前面back的头 101 | if (head->val == val) 102 | return head->next; 103 | // 否则当前节点不需要被删除,那么就连接上,并返回当前节点即可。 104 | return head; 105 | } 106 | }; 107 | 108 | 109 | int main() { 110 | vector array{1,3,5,6,8,6}; 111 | ListNode *listNode = new ListNode(array); 112 | 113 | cout<<*listNode< 6 | #include 7 | 8 | using namespace std; 9 | 10 | int mySum(const vector &vec, int index) { 11 | 12 | // 求解最基本问题 13 | if (vec.size() == index) return 0; 14 | 15 | // 把原问题转化成更小的问题 16 | int ret = 0; 17 | ret += vec[index] + mySum(vec, index + 1); 18 | // 或者return vec[index] + mySum(vec, index + 1); 19 | return ret; 20 | } 21 | 22 | 23 | 24 | int main() { 25 | vector vec{1, 2, 3, 4, 5}; 26 | cout << mySum(vec, 0) << endl; 27 | return 0; 28 | } -------------------------------------------------------------------------------- /玩转儿数据结构/recursion/recursion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Light-City/algPratice/6d8e37673549845d8d4e5ab8a05780bc77013ce7/玩转儿数据结构/recursion/recursion.png -------------------------------------------------------------------------------- /玩转儿数据结构/segmenttree/303NumArray.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-28. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | /** 11 | * 线段树解法 12 | */ 13 | class NumArray { 14 | private: 15 | vector data; 16 | vector tree; 17 | public: 18 | NumArray(vector &nums) { 19 | data = nums; 20 | tree = vector(4 * data.size()); 21 | if (data.size() > 0) 22 | buildSegmentTree(0, 0, data.size() - 1); 23 | } 24 | 25 | int sumRange(int i, int j) { 26 | assert(i >= 0 && j < data.size() && i <= j); 27 | return sumRange(0, 0, data.size() - 1, i, j); 28 | } 29 | 30 | void buildSegmentTree(int treeIndex, int l, int r) { 31 | if (l == r) { 32 | tree[treeIndex] = data[l]; 33 | return; 34 | } 35 | 36 | int mid = l + (r - l) / 2; 37 | int leftTreeIndex = getLeftChild(treeIndex); 38 | int rightTreeIndex = getRightChild(treeIndex); 39 | buildSegmentTree(leftTreeIndex, l, mid); 40 | buildSegmentTree(rightTreeIndex, mid + 1, r); 41 | 42 | tree[treeIndex] = tree[leftTreeIndex] + tree[rightTreeIndex]; 43 | } 44 | 45 | int sumRange(int treeIndex, int l, int r, int targetL, int targetR) { 46 | if (l == targetL && r == targetR) { 47 | return tree[treeIndex]; 48 | } 49 | 50 | int mid = l + (r - l) / 2; 51 | int leftTreeIndex = getLeftChild(treeIndex); 52 | int rightTreeIndex = getRightChild(treeIndex); 53 | 54 | if (targetL >= mid + 1) 55 | return sumRange(rightTreeIndex, mid + 1, r, targetL, targetR); 56 | else if (targetR <= mid) 57 | return sumRange(leftTreeIndex, l, mid, targetL, targetR); 58 | return sumRange(leftTreeIndex, l, mid, targetL, mid) + sumRange(rightTreeIndex, mid + 1, r, mid + 1, targetR); 59 | } 60 | 61 | int getLeftChild(int index) { 62 | return 2 * index + 1; 63 | } 64 | 65 | int getRightChild(int index) { 66 | return 2 * index + 2; 67 | } 68 | }; 69 | 70 | /** 71 | * Your NumArray object will be instantiated and called as such: 72 | * NumArray* obj = new NumArray(nums); 73 | * int param_1 = obj->sumRange(i,j); 74 | */ 75 | 76 | /** 77 | * dp 初始化O(n) 每次调用O(1) 78 | */ 79 | class NumArray1 { 80 | private: 81 | vector sum; // sum[i]存储前i个元素和 82 | public: 83 | NumArray1(vector &nums) { 84 | sum = vector(nums.size() + 1); 85 | sum[0] = 0; 86 | for (int i = 1; i <= nums.size(); i++) 87 | sum[i] = sum[i - 1] + nums[i - 1]; 88 | } 89 | 90 | int sumRange(int i, int j) { 91 | return sum[j + 1] - sum[i]; // [0...i...j...n-1]对应的求和sum为[1...i+1...j+1...n] 那就是sum[j+1]=sum[i] 92 | } 93 | }; 94 | 95 | /** 96 | * Your NumArray object will be instantiated and called as such: 97 | * NumArray* obj = new NumArray(nums); 98 | * int param_1 = obj->sumRange(i,j); 99 | */ 100 | -------------------------------------------------------------------------------- /玩转儿数据结构/segmenttree/307NumArray.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-28. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | /** 10 | * 使用线段树 11 | */ 12 | class NumArray { 13 | private: 14 | vector data; 15 | vector tree; 16 | public: 17 | NumArray(vector &nums) { 18 | data = nums; 19 | tree = vector(4 * data.size()); 20 | if (data.size() > 0) 21 | buildSegmentTree(0, 0, data.size() - 1); 22 | } 23 | 24 | void update(int index, int value) { 25 | if (index < 0 || index >= data.size()) 26 | throw "index is illegal"; 27 | data[index] = value; 28 | set(0, 0, data.size() - 1, index, value); 29 | } 30 | 31 | void set(int treeIndex, int l, int r, int index, int value) { 32 | if (l == r) { 33 | tree[treeIndex] = value; 34 | return; 35 | } 36 | int mid = l + (r - l) / 2; 37 | int leftTreeIndex = getLeftChild(treeIndex); 38 | int rightTreeIndex = getRightChild(treeIndex); 39 | if (index >= mid + 1) set(rightTreeIndex, mid + 1, r, index, value); 40 | else set(leftTreeIndex, l, mid, index, value); 41 | tree[treeIndex] = tree[leftTreeIndex] + tree[rightTreeIndex]; 42 | } 43 | 44 | int sumRange(int i, int j) { 45 | assert(i >= 0 && j < data.size() && i <= j); 46 | return sumRange(0, 0, data.size() - 1, i, j); 47 | } 48 | 49 | void buildSegmentTree(int treeIndex, int l, int r) { 50 | if (l == r) { 51 | tree[treeIndex] = data[l]; 52 | return; 53 | } 54 | 55 | int mid = l + (r - l) / 2; 56 | int leftTreeIndex = getLeftChild(treeIndex); 57 | int rightTreeIndex = getRightChild(treeIndex); 58 | buildSegmentTree(leftTreeIndex, l, mid); 59 | buildSegmentTree(rightTreeIndex, mid + 1, r); 60 | 61 | tree[treeIndex] = tree[leftTreeIndex] + tree[rightTreeIndex]; 62 | } 63 | 64 | int sumRange(int treeIndex, int l, int r, int targetL, int targetR) { 65 | if (l == targetL && r == targetR) { 66 | return tree[treeIndex]; 67 | } 68 | 69 | int mid = l + (r - l) / 2; 70 | int leftTreeIndex = getLeftChild(treeIndex); 71 | int rightTreeIndex = getRightChild(treeIndex); 72 | 73 | if (targetL >= mid + 1) 74 | return sumRange(rightTreeIndex, mid + 1, r, targetL, targetR); 75 | else if (targetR <= mid) 76 | return sumRange(leftTreeIndex, l, mid, targetL, targetR); 77 | return sumRange(leftTreeIndex, l, mid, targetL, mid) + sumRange(rightTreeIndex, mid + 1, r, mid + 1, targetR); 78 | } 79 | 80 | int getLeftChild(int index) { 81 | return 2 * index + 1; 82 | } 83 | 84 | int getRightChild(int index) { 85 | return 2 * index + 2; 86 | } 87 | }; 88 | 89 | class NumArray1 { 90 | private: 91 | vector sum; // sum[i]存储前i个元素和 92 | vector data; 93 | 94 | public: 95 | NumArray1(vector &nums) { 96 | data = nums; 97 | sum = vector(nums.size() + 1); 98 | sum[0] = 0; 99 | for (int i = 1; i <= nums.size(); i++) 100 | sum[i] = sum[i - 1] + nums[i - 1]; 101 | } 102 | 103 | void update(int i, int val) { 104 | data[i] = val; 105 | for (int k = i + 1; k <= data.size(); k++) 106 | sum[k] = sum[k - 1] + data[k - 1]; 107 | } 108 | 109 | int sumRange(int i, int j) { 110 | return sum[j + 1] - sum[i]; // [0...i...j...n-1]对应的求和sum为[1...i+1...j+1...n] 那就是sum[j+1]=sum[i] 111 | } 112 | }; 113 | 114 | /** 115 | * Your NumArray object will be instantiated and called as such: 116 | * NumArray* obj = new NumArray(nums); 117 | * obj->update(i,val); 118 | * int param_2 = obj->sumRange(i,j); 119 | */ 120 | 121 | -------------------------------------------------------------------------------- /玩转儿数据结构/segmenttree/README.md: -------------------------------------------------------------------------------- 1 | 最经典的线段树问题:区间染色 2 | 3 | 有一面墙,长度为n,每次选择一段墙进行染色 4 | m次操作后,我们可以看到多少种颜色? 5 | m次操作后,我们可以在[i,j]区间内看见多少种颜色? 6 | 使用数组 线段树 7 | 染色操作(更新区间) O(n) O(logn) 8 | 查询操作(查询区间) O(n) O(logn) 9 | 10 | 另一类经典问题:区间查询 11 | 基于区间的统计查询 12 | 13 | 对于给定区间,完成更新与查询 14 | 15 | 区间固定! 16 | 对于给定数组,构建线段树,每个节点为一个区间 17 | 18 | 19 | 不是完全二叉树也不是满二叉树,但是平衡二叉树,依然可以用数组表示,看做满二叉树,后面不存在的节点在数组中用空来表示即可。 20 | 21 | 22 | 如果区间有n个元素 数组表示需要有多少个节点? 23 | 24 | 0 1 25 | 1 2 26 | ... 27 | h-1 2^(h-1) 28 | 29 | 总共有2^h - 1,大约是2^h,最后一层为2^(h-1),得到一个结论:**最后一层的节点数大致等于前面所有层节点之和** 30 | 31 | 如果n=2^k 只需要2n的空间 32 | 如果n=2^k+1,叶子节点在倒数两层,只需要4n的空间 33 | 34 | 因此如果区间有n个元素 数组表示需要有4n个节点。 35 | 36 | 37 | 线段树的适用场景主要为区间内的数据变动情况。 38 | 39 | 像303号问题区间数组不可变,可以用线段树,也可不用。 40 | 像307就只能用线段树比较好解决了。 -------------------------------------------------------------------------------- /玩转儿数据结构/segmenttree/segment.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-28. 3 | // 4 | 5 | #include "segment.h" 6 | 7 | template 8 | class intMerge : public Merge { 9 | public: 10 | virtual T merge(T a, T b) { 11 | return a + b; 12 | } 13 | }; 14 | 15 | int main() { 16 | vector nums = {-2, 0, 3, -5, 2, -1}; 17 | SegmentTree> segmentTree(nums); 18 | cout << segmentTree.query(0, 5) << endl; 19 | cout << segmentTree << endl; 20 | } -------------------------------------------------------------------------------- /玩转儿数据结构/segmenttree/segment.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-28. 3 | // 4 | 5 | #ifndef ALG_SEGMENT_H 6 | #define ALG_SEGMENT_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | template 15 | class Merge { 16 | public: 17 | virtual T merge(T a, T b) = 0; 18 | }; 19 | 20 | template 21 | class SegmentTree { 22 | private: 23 | vector data; 24 | vector tree; 25 | public: 26 | SegmentTree(const vector &arr) { 27 | data = arr; 28 | tree = vector(4 * arr.size(), 0); 29 | if (data.size() > 0) 30 | buildSegmentTree(0, 0, data.size() - 1); 31 | } 32 | 33 | T get(int index) { 34 | if (index < 0 || index >= data.size()) 35 | throw "index is illegal"; 36 | return data[index]; 37 | } 38 | 39 | Merge m; 40 | 41 | // 线段树 查询操作 log(n) 42 | T query(int queryL, int queryR) { 43 | assert(queryL >= 0 && queryR < data.size() && queryL <= queryR); 44 | return query(0, 0, data.size() - 1, queryL, queryR); 45 | } 46 | 47 | // 将index位置的值,更新为value log(n) 48 | void set(int index, T value) { 49 | if (index < 0 || index >= data.size()) 50 | throw "index is illegal"; 51 | data[index] = value; 52 | set(0, 0, data.size() - 1, index, value); 53 | } 54 | 55 | private: 56 | // 返回完全二叉树的数组表示中,,一个索引表示的元素的左孩子节点的索引 57 | int leftChild(int index) { 58 | return 2 * index + 1; 59 | } 60 | 61 | // 返回完全二叉树的数组表示中,,一个索引表示的元素的右孩子节点的索引 62 | int rightChild(int index) { 63 | return 2 * index + 2; 64 | } 65 | 66 | // 在treeIndex的位置创建表示区间[l,..r]的线段树 67 | void buildSegmentTree(int treeIndex, int l, int r) { 68 | if (l == r) { 69 | tree[treeIndex] = data[l]; 70 | return; 71 | } 72 | int mid = l + (r - l) / 2; 73 | int leftTreeIndex = leftChild(treeIndex); 74 | int rightTreeIndex = rightChild(treeIndex); 75 | // [l,mid] 76 | buildSegmentTree(leftTreeIndex, l, mid); 77 | // [mid+1,r] 78 | buildSegmentTree(rightTreeIndex, mid + 1, r); 79 | 80 | tree[treeIndex] = m.merge(tree[leftTreeIndex], tree[rightTreeIndex]); // 具体merge 比如求和 81 | } 82 | 83 | void set(int treeIndex, int l, int r, int index, int value) { 84 | if (l == r) { 85 | tree[treeIndex] = value; 86 | return; 87 | } 88 | int mid = l + (r - l) / 2; 89 | int leftTreeIndex = leftChild(treeIndex); 90 | int rightTreeIndex = rightChild(treeIndex); 91 | if (index >= mid + 1) set(rightTreeIndex, mid + 1, r, index, value); 92 | else set(leftTreeIndex, l, mid, index, value); 93 | tree[treeIndex] = m.merge(tree[leftTreeIndex], tree[rightTreeIndex]); 94 | } 95 | 96 | template 97 | friend ostream &operator<<(ostream &cout, SegmentTree &segmentTree); 98 | 99 | private: 100 | // 在以treeId为根的线段树中[l...r]的范围里,搜索区间[queryL...queryR]的值 101 | T query(int treeIndex, int l, int r, int queryL, int queryR) { 102 | // 递归终止条件 103 | if (l == queryL && r == queryR) 104 | return tree[treeIndex]; 105 | 106 | int mid = l + (r - l) / 2; 107 | int leftTreeIndex = leftChild(treeIndex); 108 | int rightTreeIndex = rightChild(treeIndex); 109 | 110 | if (queryL >= mid + 1) 111 | return query(rightTreeIndex, mid + 1, r, queryL, queryR); 112 | else if (queryR <= mid) 113 | return query(leftTreeIndex, l, mid, queryL, queryR); 114 | T leftRes = query(leftTreeIndex, l, mid, queryL, mid); 115 | T rightRes = query(rightTreeIndex, mid + 1, r, mid + 1, queryR); 116 | // 如果取两边区间最大值,就掉max,做什么操作,就传什么操作的merge即可。 117 | return m.merge(leftRes, rightRes); 118 | } 119 | }; 120 | 121 | template 122 | ostream &operator<<(ostream &out, SegmentTree &segmentTree) { 123 | string res = "["; 124 | for (int i = 0; i < segmentTree.tree.size(); i++) { 125 | res += to_string(segmentTree.tree[i]); 126 | if (i != segmentTree.tree.size() - 1) 127 | res += ", "; 128 | } 129 | res += "]"; 130 | out << res << endl; 131 | 132 | return out; 133 | } 134 | 135 | #endif //ALG_SEGMENT_H 136 | -------------------------------------------------------------------------------- /玩转儿数据结构/set_map/804uniqueMorseRepresentations.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class Solution { 11 | public: 12 | int uniqueMorseRepresentations(vector &words) { 13 | 14 | vector vec{".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", 15 | "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", 16 | "--.."}; 17 | 18 | set s; 19 | 20 | for (auto str:words) { 21 | string tmp = ""; 22 | for (auto i:str) tmp += vec[i - 'a']; 23 | s.insert(tmp); 24 | } 25 | return s.size(); 26 | } 27 | }; -------------------------------------------------------------------------------- /玩转儿数据结构/set_map/BSTMap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | 5 | #ifndef ALG_BSTMAP_H 6 | #define ALG_BSTMAP_H 7 | 8 | // 有序集合 9 | template 10 | class BSTMap : public Map { 11 | private: 12 | BST bst; 13 | public: 14 | BSTMap() { 15 | 16 | } 17 | 18 | virtual int size() { 19 | return bst.size(); 20 | } 21 | 22 | virtual bool isEmpty() { 23 | return bst.isEmpty(); 24 | } 25 | 26 | virtual bool contain(Key key) { 27 | return bst.contain(key); 28 | } 29 | 30 | virtual Value *search(Key key) { 31 | return bst.search(key); 32 | } 33 | 34 | virtual void set(Key key, Value value) { 35 | bst.set(key, value); 36 | } 37 | 38 | virtual void insert(Key key, Value value) { 39 | bst.insert(key, value); 40 | } 41 | 42 | virtual Value *remove(Key key) { 43 | return bst.remove(key); 44 | } 45 | 46 | }; 47 | 48 | #endif //ALG_BSTMAP_H 49 | -------------------------------------------------------------------------------- /玩转儿数据结构/set_map/BSTSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-7. 3 | // 4 | #include "../bst/BST.h" 5 | #include "../interface.h" 6 | 7 | #ifndef ALG_BSTSET_H 8 | #define ALG_BSTSET_H 9 | 10 | // 有序集合 11 | template 12 | class BSTSet : public Set { 13 | private: 14 | BST bst; 15 | public: 16 | // O(h) h=log(n) 最差O(n) 其他一样 这样的话就得用AVL 17 | virtual void insert(Key key) override { 18 | bst.insert(key, key); 19 | } 20 | // O(h) 21 | virtual void remove(Key key) override { 22 | bst.remove(key); 23 | } 24 | 25 | // O(h) 26 | virtual bool contain(Key key) override { 27 | bst.contain(key); 28 | } 29 | 30 | virtual int size() override { 31 | bst.size(); 32 | } 33 | 34 | virtual bool isEmpty() override { 35 | bst.isEmpty(); 36 | } 37 | }; 38 | 39 | 40 | #endif //ALG_BSTSET_H 41 | -------------------------------------------------------------------------------- /玩转儿数据结构/set_map/LinkedListMap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | 5 | #ifndef ALG_LINKEDLISTMAP_H 6 | #define ALG_LINKEDLISTMAP_H 7 | 8 | template 9 | class LinkedListMap : public Map { 10 | private: 11 | class Node { 12 | public: 13 | Key key; 14 | Value value; 15 | Node *next; 16 | 17 | Node(Key key, Value value, Node *next) : key(key), value(value), next(next) {} 18 | 19 | Node() { 20 | Key key; 21 | Value value; 22 | new(this)Node(key, value, NULL); 23 | } 24 | 25 | friend ostream &operator<<(ostream &out, Node &node) { 26 | out << node.key << ":" << node.value << endl; 27 | return out; 28 | } 29 | }; 30 | 31 | Node *dummyHead; 32 | int count; 33 | public: 34 | LinkedListMap() { 35 | dummyHead = new Node(); 36 | } 37 | 38 | ~LinkedListMap() { 39 | Node *cur = dummyHead; 40 | while (cur) { 41 | delete cur; 42 | cur = cur->next; 43 | count--; 44 | } 45 | } 46 | 47 | virtual int size() { 48 | return count; 49 | } 50 | 51 | virtual bool isEmpty() { 52 | return count == 0; 53 | } 54 | 55 | 56 | virtual Node *getNode(Key key) { 57 | Node *cur = dummyHead->next; 58 | while (cur) { 59 | if (cur->key == key) 60 | return cur; 61 | cur = cur->next; 62 | } 63 | return NULL; 64 | } 65 | 66 | virtual bool contain(Key key) { 67 | return getNode(key); 68 | } 69 | 70 | virtual Value *search(Key key) { 71 | Node *node = getNode(key); 72 | return (node == NULL) ? NULL : &node->value; 73 | } 74 | 75 | virtual void insert(Key key, Value value) { 76 | Node *node = getNode(key); 77 | if (node == NULL) { 78 | dummyHead->next = new Node(key, value, dummyHead->next); // 头插法 79 | count++; 80 | } else { 81 | node->value = value; 82 | } 83 | } 84 | 85 | virtual void set(Key key, Value value) { 86 | Node *node = getNode(key); 87 | if (node == NULL) 88 | throw "Key not found "; 89 | node->value = value; 90 | } 91 | 92 | virtual Value *remove(Key key) { 93 | Node *prev = dummyHead; 94 | while (prev->next) { 95 | if (prev->next->key == key) 96 | break; 97 | prev = prev->next; 98 | } 99 | if (prev->next) { 100 | Node *delNode = prev->next; 101 | prev->next = delNode->next; 102 | delNode->next = NULL; 103 | count--; 104 | return &delNode->value; 105 | } 106 | return NULL; 107 | } 108 | }; 109 | 110 | #endif //ALG_LINKEDLISTMAP_H 111 | -------------------------------------------------------------------------------- /玩转儿数据结构/set_map/LinkedListSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | 5 | #ifndef ALG_LINKEDLISTSET_H 6 | #define ALG_LINKEDLISTSET_H 7 | 8 | #include "../linklist/LinkedList.h" 9 | 10 | template 11 | class LinkedListSet : public Set { 12 | private: 13 | LinkedList *linkedList; 14 | public: 15 | LinkedListSet() { 16 | linkedList = new LinkedList; 17 | } 18 | 19 | ~LinkedListSet() { 20 | if (linkedList) 21 | delete linkedList; 22 | } 23 | 24 | // O(n) 25 | virtual void insert(Key key) { 26 | if (!linkedList->contains(key)) linkedList->addFirst(key); 27 | } 28 | 29 | // O(n) 30 | virtual void remove(Key key) { 31 | linkedList->removeElement(key); 32 | } 33 | 34 | // O(n) 35 | virtual bool contain(Key key) { 36 | return linkedList->contains(key); 37 | } 38 | 39 | virtual int size() { 40 | return linkedList->getSize(); 41 | } 42 | 43 | virtual bool isEmpty() { 44 | return linkedList->isEmpty(); 45 | } 46 | }; 47 | 48 | #endif //ALG_LINKEDLISTSET_H 49 | -------------------------------------------------------------------------------- /玩转儿数据结构/set_map/SeqMap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-9. 3 | // 4 | 5 | #ifndef ALG_SEQMAP_H 6 | #define ALG_SEQMAP_H 7 | 8 | template 9 | class SeqMap : Map { 10 | private: 11 | SequenceST *sst; 12 | public: 13 | SeqMap() { 14 | sst = new SequenceST(); 15 | } 16 | 17 | ~SeqMap() { 18 | if (sst) { 19 | delete sst; 20 | } 21 | } 22 | 23 | void insert(Key key, Value value) override { 24 | sst->insert(key, value); 25 | } 26 | 27 | Value *remove(Key key) override { 28 | return sst->remove(key); 29 | } 30 | 31 | bool contain(Key key) override { 32 | return sst->contain(key); 33 | } 34 | 35 | Value *search(Key key) override { 36 | return sst->search(key); 37 | } 38 | 39 | void set(Key key, Value value) override { 40 | sst->set(key, value); 41 | } 42 | 43 | int size() override { 44 | return sst->size(); 45 | } 46 | 47 | bool isEmpty() override { 48 | return sst->isEmpty(); 49 | } 50 | }; 51 | 52 | #endif //ALG_SEQMAP_H 53 | -------------------------------------------------------------------------------- /玩转儿数据结构/set_map/SeqSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-9. 3 | // 4 | 5 | #ifndef ALG_SEQSET_H 6 | #define ALG_SEQSET_H 7 | 8 | template 9 | class SeqSet : Set { 10 | private: 11 | SequenceST *sst; 12 | public: 13 | SeqSet() { 14 | sst = new SequenceST(); 15 | } 16 | 17 | ~SeqSet() { 18 | if (sst) 19 | delete sst; 20 | } 21 | 22 | void insert(Key key) override { 23 | sst->insert(key, key); 24 | } 25 | 26 | void remove(Key key) override { 27 | sst->remove(key); 28 | } 29 | 30 | bool contain(Key key) override { 31 | return sst->contain(key); 32 | } 33 | 34 | 35 | int size() override { 36 | return sst->size(); 37 | } 38 | 39 | bool isEmpty() override { 40 | return sst->isEmpty(); 41 | } 42 | }; 43 | 44 | #endif //ALG_SEQSET_H 45 | -------------------------------------------------------------------------------- /玩转儿数据结构/stack/20isValid.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-8-28. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | * 通过栈顶元素获取最近的那个元素 10 | */ 11 | 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | /** 17 | * 时间复杂度:O(n) 18 | * 空间复杂度:O(n) 19 | * @param s 20 | * @return 21 | */ 22 | bool isValid(string s) { 23 | stack sta; 24 | for (int i = 0; i < s.length(); i++) { 25 | if (s[i] == '(' || s[i] == '{' || s[i] == '[') 26 | sta.push(s[i]); 27 | else if (s[i] == ')') { 28 | bool iscirok = judge(sta, s[i], '('); 29 | if (iscirok == false) return false; 30 | } else if (s[i] == '}') { 31 | bool ishuaok = judge(sta, s[i], '{'); 32 | if (ishuaok == false) return false; 33 | } else if (s[i] == ']') { 34 | bool isfangok = judge(sta, s[i], '['); 35 | if (isfangok == false) return false; 36 | } 37 | } 38 | return sta.empty() ? true : false; 39 | } 40 | 41 | bool judge(stack &sta, const char src, const char kuohao) { 42 | if (sta.empty()) 43 | return false; 44 | char topchar = sta.top(); 45 | sta.pop(); 46 | if (topchar == kuohao) 47 | return true; 48 | return false; 49 | } 50 | // 上述简化版 51 | bool isValid2(string s) { 52 | stack sta; 53 | char match; 54 | for(int i=0;i m; 76 | m['}']='{'; 77 | m[']']='['; 78 | m[')']='('; 79 | stack st; 80 | st.push('0'); 81 | for (int i = 0; i < s.length(); i++) { 82 | if (m.find(s[i])!=m.end() && m[s[i]] == st.top()) { 83 | st.pop(); 84 | continue; 85 | } 86 | if (m.find(s[i])!=m.end() && m[s[i]] != st.top()&&st.top()!='0') { 87 | return false; 88 | } 89 | 90 | st.push(s[i]); 91 | } 92 | return st.size()==1; 93 | } 94 | 95 | 96 | }; 97 | 98 | 99 | int main() { 100 | string s = "{}"; 101 | cout << Solution().isValid2(s) << endl; 102 | } -------------------------------------------------------------------------------- /玩转儿数据结构/stack/ArrayStack.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-7. 3 | // 4 | 5 | #ifndef ALG_ARRAYSTACK_H 6 | #define ALG_ARRAYSTACK_H 7 | 8 | #include "../array/array.h" 9 | #include "../interface.h" 10 | #include "../stack/ArrayStack.h" 11 | 12 | 13 | // 基于动态数组的Stack 14 | template 15 | class ArrayStack : public CommonStack { 16 | private: 17 | Array *array; 18 | public: 19 | ArrayStack(int capacity) { 20 | array = new Array(capacity); 21 | } 22 | 23 | ArrayStack() { 24 | array = new Array(); 25 | } 26 | 27 | ~ArrayStack() { 28 | delete[]array; 29 | } 30 | 31 | int getSize() { 32 | return array->getSize(); 33 | } 34 | 35 | bool isEmpty() { 36 | return array->isEmpty(); 37 | } 38 | 39 | int getCapacity() { 40 | return array->getCapacity(); 41 | } 42 | 43 | // 入栈策略:尾部添加 O(1) 44 | void push(T e) { 45 | array->addLast(e); 46 | } 47 | 48 | // 出栈策略:尾部出 O(1) 49 | void pop() { 50 | array->removeLast(); 51 | } 52 | 53 | // O(1) 54 | T peek() { 55 | return array->getLast(); 56 | } 57 | 58 | friend ostream &operator<<(ostream &out, ArrayStack &stack) { 59 | out << *(stack.array); 60 | return out; 61 | } 62 | }; 63 | 64 | 65 | #endif //ALG_ARRAYSTACK_H 66 | -------------------------------------------------------------------------------- /玩转儿数据结构/stack/LinkedListStack.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-11-8. 3 | // 4 | 5 | #ifndef ALG_LINKEDLISTSTACK_H 6 | #define ALG_LINKEDLISTSTACK_H 7 | 8 | #endif //ALG_LINKEDLISTSTACK_H 9 | 10 | // 无序集合 11 | template 12 | class LinkedListStack : public CommonStack { 13 | private: 14 | LinkedList *linkedList; 15 | public: 16 | 17 | LinkedListStack() { 18 | linkedList = new LinkedList(); 19 | } 20 | ~LinkedListStack() { 21 | delete linkedList; 22 | } 23 | int getSize() { 24 | return linkedList->getSize(); 25 | } 26 | 27 | bool isEmpty() { 28 | return linkedList->isEmpty(); 29 | } 30 | 31 | 32 | void push(T e) { 33 | linkedList->addFirst(e); 34 | } 35 | 36 | void pop() { 37 | linkedList->removeFirst(); 38 | } 39 | 40 | T peek() { 41 | return linkedList->getFirst(); 42 | } 43 | 44 | friend ostream &operator<<(ostream &out, LinkedListStack &linkedListStack) { 45 | out << *(linkedListStack.linkedList); 46 | return out; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /玩转儿数据结构/test/Tmain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-18. 3 | // 4 | 5 | 6 | 7 | #include 8 | #include "../rbtree/rb_tree.h" 9 | #include "../hash/hash.h" 10 | #include "../avl/AVL.h" 11 | #include "../file/FileOps.h" 12 | #include "../set_map/BSTSet.h" 13 | #include "../set_map/BSTMap.h" 14 | #include "../set_map/LinkedListSet.h" 15 | #include "../set_map/LinkedListMap.h" 16 | #include "../set_map/SeqMap.h" 17 | #include "../set_map/SeqSet.h" 18 | #include "../queue/ArrayQueue.h" 19 | #include "../queue/loopQueue.h" 20 | #include "../queue/LinkedListQueue.h" 21 | #include "../stack/ArrayStack.h" 22 | #include "../stack/LinkedListStack.h" 23 | #include "../linklist/LinkedList.h" 24 | 25 | using namespace std; 26 | 27 | template 28 | double testMap(T *map, string filename) { 29 | clock_t startTime = clock(); 30 | srand(66); 31 | vector words; 32 | if (FileOps::readFile(filename, words)) { 33 | std::cout << "Total words: " << words.size() << std::endl; 34 | for (string word : words) { 35 | if (map->contain(word)) { 36 | map->set(word, *(map->search(word)) + 1); 37 | } else { 38 | map->insert(word, 1); 39 | } 40 | } 41 | if (map->contain("labour")) 42 | cout << "'labour' : " << *(map->search("labour")) << endl; 43 | else 44 | cout << "No word 'labour' in " + filename << endl; 45 | map->remove("labour"); // remove返回值为树根 46 | if (map->contain("labour")) 47 | cout << "'labour' : " << *(map->search("labour")) << endl; 48 | else 49 | cout << "No word 'labour' in " + filename << endl; 50 | } 51 | clock_t endTime = clock(); 52 | return double(endTime - startTime) / CLOCKS_PER_SEC; 53 | } 54 | 55 | template 56 | double testSet(T *set, string filename) { 57 | clock_t startTime = clock(); 58 | srand(66); 59 | vector words; 60 | if (FileOps::readFile(filename, words)) { 61 | std::cout << "Total words: " << words.size() << std::endl; 62 | for (string word : words) { 63 | set->insert(word); 64 | } 65 | std::cout << "Total different words: " << set->size() << std::endl; 66 | } 67 | clock_t endTime = clock(); 68 | return double(endTime - startTime) / CLOCKS_PER_SEC; 69 | } 70 | 71 | template 72 | double testQueue(BaseQueue *q, int opCount) { 73 | clock_t startTime = clock(); 74 | for (int i = 0; i < opCount; i++) { 75 | q->enqueue(i); 76 | } 77 | for (int i = 0; i < opCount; i++) { 78 | q->dequeue(); 79 | } 80 | clock_t endTime = clock(); 81 | return double(endTime - startTime) / CLOCKS_PER_SEC; 82 | } 83 | 84 | template 85 | double testStack(CommonStack *stack, int opCount) { 86 | clock_t startTime = clock(); 87 | for (int i = 0; i < opCount; i++) { 88 | stack->push(i); 89 | } 90 | for (int i = 0; i < opCount; i++) { 91 | stack->pop(); 92 | } 93 | clock_t endTime = clock(); 94 | return double(endTime - startTime) / CLOCKS_PER_SEC; 95 | } 96 | 97 | /** 98 | * 对于完全随机的数据,普通的二分搜索树很好用! 99 | * 缺点:极端情况退化成链表(或高度不平衡) 100 | * 对于查询较多的使用情况,AVL树很好用 101 | * 红黑树牺牲了平衡性(2longn的高度) 102 | * 统计性能更优(综合增删改查所有的操作) 103 | * @return 104 | */ 105 | int main() { 106 | 107 | // 我们使用文本量更小的共产主义宣言进行试验:) 108 | string filename = "/home/light/CLionProjects/alg/算法基础/file/communist.txt"; 109 | vector words; 110 | 111 | if (FileOps::readFile(filename, words)) { 112 | 113 | cout << "There are totally " << words.size() << " words in " << filename << endl; 114 | cout << endl; 115 | 116 | // 测试1, 我们按照文本原有顺序插入进二分搜索树 117 | time_t startTime = clock(); 118 | BST *bst = new BST(); 119 | for (vector::iterator iter = words.begin(); iter != words.end(); iter++) { 120 | int *res = (*bst).search(*iter); 121 | if (res == NULL) 122 | (*bst).insert(*iter, 1); 123 | else 124 | (*res)++; 125 | } 126 | vector> res1 = bst->_postOrder(); 127 | cout << endl; 128 | vector> res2 = bst->postOrder(); 129 | if (res1 != res2) cout << "not ok" << endl; 130 | else 131 | cout << "ok" << endl; 132 | 133 | // 我们查看labour一词的词频 134 | if (bst->contain("labour")) 135 | cout << "'labour' : " << *(*bst).search("labour") << endl; 136 | else 137 | cout << "No word 'labour' in " + filename << endl; 138 | time_t endTime = clock(); 139 | 140 | cout << "BST , time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 141 | cout << endl; 142 | 143 | delete bst; 144 | 145 | 146 | // 测试2, 我们按照文本原有顺序插入顺序查找表 147 | startTime = clock(); 148 | SequenceST *sst = new SequenceST(); 149 | for (vector::iterator iter = words.begin(); iter != words.end(); iter++) { 150 | int *res = (*sst).search(*iter); 151 | if (res == NULL) 152 | (*sst).insert(*iter, 1); 153 | else 154 | (*res)++; 155 | } 156 | 157 | if (sst->contain("labour")) 158 | cout << "'labour' : " << *(*sst).search("labour") << endl; 159 | else 160 | cout << "No word 'labour' in " + filename << endl; 161 | int *value = sst->remove("labour"); 162 | cout << *value << endl; 163 | // 我们查看labour一词的词频 164 | if (sst->contain("labour")) 165 | cout << "'labour' : " << *(*sst).search("labour") << endl; 166 | else 167 | cout << "No word 'labour' in " + filename << endl; 168 | endTime = clock(); 169 | 170 | cout << "SST , time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 171 | cout << endl; 172 | 173 | delete sst; 174 | 175 | 176 | // 测试3, 我们将原文本排序后插入二分搜索树, 查看其效率 177 | startTime = clock(); 178 | BST *bst2 = new BST(); 179 | 180 | sort(words.begin(), words.end()); 181 | for (vector::iterator iter = words.begin(); iter != words.end(); iter++) { 182 | int *res = (*bst2).search(*iter); 183 | if (res == NULL) 184 | (*bst2).insert(*iter, 1); 185 | else 186 | (*res)++; 187 | } 188 | 189 | // 我们查看labour一词的词频 190 | cout << "'labour' : " << *(*bst2).search("labour") << endl; 191 | endTime = clock(); 192 | 193 | cout << "BST2 , time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 194 | cout << endl; 195 | 196 | delete bst2; 197 | 198 | 199 | 200 | // 测试1, 我们按照文本原有顺序插入进二分搜索树 201 | startTime = clock(); 202 | RBTree *rbTree = new RBTree(); 203 | 204 | for (vector::iterator iter = words.begin(); iter != words.end(); iter++) { 205 | int *res = (*rbTree).search(*iter); 206 | if (res == NULL) 207 | (*rbTree).insert(*iter, 1); 208 | else 209 | (*res)++; 210 | } 211 | 212 | // 我们查看labour一词的词频 213 | if (rbTree->contain("labour")) 214 | cout << "'labour' : " << *(rbTree->search("labour")) << endl; 215 | else 216 | cout << "No word 'labour' in " + filename << endl; 217 | // 218 | // rbTree->insert(100, "v100"); 219 | // rbTree->insert(50, "v50"); 220 | // rbTree->insert(150, "v150"); 221 | // rbTree->insert(20, "v20"); 222 | // rbTree->insert(85, "v85"); 223 | // rbTree->insert(10, "v10"); 224 | // rbTree->insert(15, "a15"); 225 | // rbTree->insert(75, "v75"); 226 | // rbTree->insert(95, "v95"); 227 | // rbTree->insert(65, "v65"); 228 | // rbTree->insert(76, "v76"); 229 | // rbTree->insert(60, "v60"); 230 | // rbTree->insert(66, "v66"); 231 | // rbTree->insert(61, "v61"); 232 | 233 | // rbTree->levelOrder(); 234 | endTime = clock(); 235 | 236 | cout << "RBTree, time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 237 | cout << endl; 238 | 239 | delete rbTree; 240 | 241 | 242 | startTime = clock(); 243 | HashTable *ht = new HashTable(words.size()); 244 | for (string word : words) { 245 | if (ht->contains(word)) { 246 | ht->set(word, ht->get(word) + 1); 247 | } else { 248 | ht->add(word, 1); 249 | } 250 | } 251 | if (ht->contains("labour")) 252 | cout << "'labour' : " << ht->get("labour") << endl; 253 | else 254 | cout << "No word 'labour' in " + filename << endl; 255 | // int ret = ht->remove("labour"); 256 | // cout << ret << endl; 257 | // cout << ht->getSize() << endl; 258 | // if (ht->contains("labour")) 259 | // cout << "'labour' : " << ht->get("labour") << endl; 260 | // else 261 | // cout << "No word 'labour' in " + filename << endl; 262 | endTime = clock(); 263 | 264 | cout << "HashTable, time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 265 | delete ht; 266 | 267 | cout << endl; 268 | startTime = clock(); 269 | AVL *avlTree = new AVL(); 270 | 271 | 272 | for (string word : words) { 273 | if (avlTree->contain(word)) { 274 | avlTree->set(word, *(avlTree->search(word)) + 1); 275 | } else { 276 | avlTree->insert(word, 1); 277 | } 278 | } 279 | if (avlTree->contain("labour")) 280 | cout << "'labour' : " << *(avlTree->search("labour")) << endl; 281 | else 282 | cout << "No word 'labour' in " + filename << endl; 283 | avlTree->remove("labour"); 284 | if (avlTree->contain("labour")) 285 | cout << "'labour' : " << *(avlTree->search("labour")) << endl; 286 | else 287 | cout << "No word 'labour' in " + filename << endl; 288 | std::cout << avlTree->isBST() << endl; 289 | std::cout << avlTree->isBalanced() << endl; 290 | endTime = clock(); 291 | cout << "avlTree, time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s." << endl; 292 | delete avlTree; 293 | cout << endl; 294 | 295 | 296 | LinkedListMap *linkedListMap = new LinkedListMap(); 297 | float linkMapTime = testMap(linkedListMap, filename); 298 | std::cout << "linkMap time : " << linkMapTime << " s " << std::endl; 299 | delete linkedListMap; 300 | 301 | cout << endl; 302 | 303 | BSTMap *bstMap = new BSTMap(); 304 | float bstMapTime = testMap(bstMap, filename); 305 | std::cout << "bstMap time : " << bstMapTime << " s " << std::endl; 306 | delete bstMap; 307 | 308 | cout << endl; 309 | 310 | 311 | SeqMap *seqMap = new SeqMap(); 312 | float seqMapTime = testMap(seqMap, filename); 313 | std::cout << "seqMap time : " << seqMapTime << " s " << std::endl; 314 | delete seqMap; 315 | 316 | cout << endl; 317 | 318 | AVLMap *avlMap = new AVLMap(); 319 | float avlMapTime = testMap(avlMap, filename); 320 | std::cout << "AVLMap time : " << avlMapTime << " s " << std::endl; 321 | delete avlMap; 322 | 323 | cout << endl; 324 | 325 | 326 | BSTSet *bstSet = new BSTSet(); 327 | double time1 = testSet(bstSet, filename); 328 | std::cout << "BstSet time : " << time1 << " s " << std::endl; 329 | delete bstSet; 330 | 331 | cout << endl; 332 | 333 | LinkedListSet *linkedListSet = new LinkedListSet(); 334 | double time2 = testSet(linkedListSet, filename); 335 | std::cout << "LinkedListSet time : " << time2 << " s " << std::endl; 336 | delete linkedListSet; 337 | 338 | cout << endl; 339 | 340 | SeqSet *seqSet = new SeqSet(); 341 | double time3 = testSet(seqSet, filename); 342 | std::cout << "SeqSet time : " << time3 << " s " << std::endl; 343 | delete seqSet; 344 | 345 | cout << endl; 346 | 347 | AVLSet *avlSet = new AVLSet(); 348 | double time4 = testSet(avlSet, filename); 349 | std::cout << "AVLSet time : " << time4 << " s " << std::endl; 350 | 351 | delete avlSet; 352 | 353 | 354 | cout << endl; 355 | 356 | BaseQueue *queue = new ArrayQueue(); 357 | BaseQueue *lq = new loopQueue(); 358 | BaseQueue *linkq = new LinkedListQueue(); 359 | int opCount = 100000; 360 | cout << "queue time " << endl; 361 | cout << testQueue(queue, opCount) << endl; 362 | cout << "loopQueue time " << endl; 363 | cout << testQueue(lq, opCount) << endl; 364 | cout << "LinkedListQueue time " << endl; 365 | cout << testQueue(linkq, opCount) << endl; 366 | delete queue; 367 | delete lq; 368 | delete linkq; 369 | 370 | cout << endl; 371 | 372 | CommonStack *stack = new ArrayStack(); 373 | LinkedListStack *linkedListStack = new LinkedListStack(); 374 | cout << "array stack time " << endl; 375 | cout << testStack(stack, opCount) << endl; 376 | cout << "linkedList stack time " << endl; 377 | cout << testStack(linkedListStack, opCount) << endl; 378 | delete stack; 379 | delete linkedListStack; 380 | } 381 | vector a = {1, 23}; 382 | vector b = {2, 23}; 383 | return 0; 384 | } -------------------------------------------------------------------------------- /玩转儿数据结构/trie/211WordDictionary.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-25. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class WordDictionary { 11 | private: 12 | struct Node { // Node节点并不需要存储当前字符是谁 13 | bool isWord = false; 14 | map next; 15 | }; 16 | Node *root; 17 | public: 18 | /** Initialize your data structure here. */ 19 | WordDictionary() { 20 | root = new Node(); 21 | } 22 | 23 | ~WordDictionary() { 24 | destroy(root); 25 | } 26 | 27 | void destroy(Node *node) { 28 | if (node) { 29 | for (auto each:node->next) 30 | delete each.second; 31 | delete node; 32 | } 33 | } 34 | 35 | /** Adds a word into the data structure. */ 36 | void addWord(string word) { 37 | Node *cur = root; 38 | for (int i = 0; i < word.size(); i++) { 39 | char c = word[i]; 40 | if (cur->next.count(c) == 0) 41 | cur->next.insert(make_pair(c, new Node())); 42 | cur = cur->next.at(c); 43 | } 44 | cur->isWord = true; 45 | } 46 | 47 | /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */ 48 | bool search(string word) { 49 | return match(root, word, 0); 50 | } 51 | 52 | private: 53 | bool match(Node *node, string word, int index) { 54 | if (index == word.size()) 55 | return node->isWord; 56 | char c = word[index]; 57 | if (c != '.') { 58 | if (node->next.count(c) == 0) return false; 59 | return match(node->next.at(c), word, index + 1); 60 | } else { 61 | for (auto x:node->next) 62 | if (match(node->next.at(x.first), word, index + 1)) 63 | return true; 64 | return false; 65 | } 66 | } 67 | }; 68 | 69 | /** 70 | * Your WordDictionary object will be instantiated and called as such: 71 | * WordDictionary* obj = new WordDictionary(); 72 | * obj->addWord(word); 73 | * bool param_2 = obj->search(word); 74 | */ -------------------------------------------------------------------------------- /玩转儿数据结构/trie/677MapSum.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-25. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class MapSum { 10 | private: 11 | struct Node { // Node节点并不需要存储当前字符是谁 12 | int value = 0; // key所对应的value 13 | map next; 14 | }; 15 | Node *root; 16 | public: 17 | /** Initialize your data structure here. */ 18 | MapSum() { 19 | root = new Node(); 20 | } 21 | 22 | ~MapSum() { 23 | destroy(root); 24 | } 25 | 26 | void destroy(Node *node) { 27 | if (node) { 28 | for (auto each:node->next) 29 | delete each.second; 30 | delete node; 31 | } 32 | } 33 | 34 | void insert(string key, int val) { 35 | Node *cur = root; 36 | for (int i = 0; i < key.size(); i++) { 37 | char c = key[i]; 38 | if (cur->next.count(c) == 0) 39 | cur->next.insert(make_pair(c, new Node())); 40 | cur = cur->next.at(c); 41 | } 42 | cur->value = val; 43 | } 44 | 45 | /** 46 | * 先查找到prefix最后一个char的位置,再从这个char开始递归求和。 47 | * @param prefix 48 | * @return 49 | */ 50 | int sum(string prefix) { 51 | Node *cur = root; 52 | for (int i = 0; i < prefix.size(); i++) { 53 | char c = prefix[i]; 54 | if (cur->next.count(c) == 0) return 0; 55 | cur = cur->next.at(c); 56 | } 57 | return _sum(cur); 58 | } 59 | 60 | private: 61 | int _sum(Node *node) { 62 | int res = node->value; 63 | for (auto x:node->next) 64 | res += _sum(x.second); 65 | return res; 66 | } 67 | }; 68 | 69 | /** 70 | * Your MapSum object will be instantiated and called as such: 71 | * MapSum* obj = new MapSum(); 72 | * obj->insert(key,val); 73 | * int param_2 = obj->sum(prefix); 74 | */ -------------------------------------------------------------------------------- /玩转儿数据结构/trie/README.md: -------------------------------------------------------------------------------- 1 | Trie 多叉树 2 | 查询每个条目的时间复杂度 3 | 和字典中一共有多少条目无关! 4 | 时间复杂度为O(w) 5 | w为查询单词的长度! 6 | 大多数单词的长度小于10 -------------------------------------------------------------------------------- /玩转儿数据结构/trie/trie.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-25. 3 | // 4 | 5 | 6 | #include "trie.h" 7 | 8 | int main() { 9 | Trie *trie=new Trie(); 10 | trie->_add("deer"); 11 | trie->_add("door"); 12 | trie->_add("dog"); 13 | trie->_add("panda"); 14 | trie->_add("pan"); 15 | trie->_add("pan"); 16 | cout<getSize()<getVal("pan")<contain("pan")<_contain("door")<isPrefix("pan")<_isPrefix("pan")<isPrefix("pag")<_isPrefix("pag")<remove("deer"); 29 | cout<_contain("deer")<_contain("dog")<_contain("door")<getSize()<remove("door"); 35 | cout<_contain("door")<_contain("dog")<getSize()<remove("pan"); 41 | cout<_contain("pan")<_contain("panda")<getSize()<remove("panda"); 46 | cout<_contain("panda")<_contain("pan")<getSize()< 9 | #include 10 | using namespace std; 11 | 12 | 13 | // 最大问题:空间 14 | class Trie { 15 | private: 16 | struct Node { // Node节点并不需要存储当前字符是谁 17 | int value = 0; // 当前节点的词频 18 | bool isWord = false; 19 | map next; 20 | }; 21 | Node *root; 22 | int size; 23 | public: 24 | Trie() { 25 | root = new Node(); 26 | size = 0; 27 | } 28 | 29 | ~Trie() { 30 | destroy(root); 31 | } 32 | void destroy(Node *node) { 33 | if (node) { 34 | for(auto each:node->next) 35 | delete each.second; 36 | delete node; 37 | } 38 | } 39 | // 获取 Trie中存储的单词数量 40 | int getSize() { 41 | return size; 42 | } 43 | 44 | // 获取单词的词频 45 | int getVal(string word) { 46 | Node *cur = root; 47 | for (int i = 0; i < word.size(); i++) { 48 | char c = word[i]; 49 | if (cur->next.count(c) == 0) return 0; 50 | cur = cur->next.at(c); 51 | } 52 | return cur->value; 53 | } 54 | 55 | // 非递归 56 | // 添加新的单词word 57 | void add(string word) { 58 | Node *cur = root; 59 | for (int i = 0; i < word.size(); i++) { 60 | char c = word[i]; 61 | if (cur->next.count(c) == 0) 62 | cur->next.insert(make_pair(c, new Node())); 63 | cur = cur->next.at(c); 64 | } 65 | if (cur->isWord == false) { // 添加的是个新单词 66 | cur->isWord = true; 67 | cur->value = 1; 68 | size++; 69 | } else { // 之前单词存在 70 | cur->value++; 71 | } 72 | } 73 | 74 | // 递归添加 75 | void _add(string word) { 76 | add(word, 0, root); 77 | } 78 | 79 | 80 | // 非递归 是否包含word 81 | bool contain(string word) { 82 | Node *cur = root; 83 | for (int i = 0; i < word.size(); i++) { 84 | char c = word[i]; 85 | // not found 86 | if (cur->next.count(c) == 0) return false; 87 | cur = cur->next.at(c); 88 | } 89 | return cur->isWord; // 比如trie树中有pandas 这个单词,但要查pan这个单词,此时应该返回cur->isWord,而不是true。 90 | } 91 | 92 | // 递归 是否包含word 93 | bool _contain(string word) { 94 | return contain(word, 0, root); 95 | } 96 | 97 | // 查询是否在Trie中有单词以prefix为前缀 98 | bool isPrefix(string prefix) { 99 | Node *cur = root; 100 | for (int i = 0; i < prefix.size(); i++) { 101 | char c = prefix[i]; 102 | // not found 103 | if (cur->next.count(c) == 0) return false; 104 | cur = cur->next.at(c); 105 | } 106 | return true; 107 | } 108 | 109 | // 非递归查询是否在Trie中有单词以prefix为前缀 110 | bool _isPrefix(string prefix) { 111 | return isPrefix(prefix, 0, root); 112 | } 113 | 114 | void remove(string word) { 115 | Node *cur = root; 116 | for (int i = 0; i < word.size(); i++) { 117 | char c = word[i]; 118 | if (cur->next.count(c) == 0) return; 119 | cur = cur->next.at(c); 120 | } 121 | // 到达删除被删除单词的最后一个字符 122 | if (cur->next.size() == 0) { // 后面无节点,则自底向上删除 123 | __del(word, 0, root); 124 | } else { // 后面有节点,直接标记当前节点不是单词即可 125 | cur->isWord = false; 126 | } 127 | size--; 128 | //恢复flag,否则只能删除1次,不能够连续删除! 129 | islast= false; 130 | isstop=false; 131 | } 132 | 133 | bool islast = false; // 是否自底向上 134 | bool isstop = false; // 是否停止向上删除 135 | private: 136 | void __del(string word, int index, Node *node) { 137 | char c = word[index]; 138 | if (word.size() - 1 == index) { 139 | islast = true; 140 | free(node->next.at(c)); 141 | node->next.erase(c); 142 | return; 143 | } 144 | if (!isstop && islast) { 145 | if (node->next.size() >= 2 || node->isWord == true) 146 | isstop = true; 147 | free(node->next.at(c)); 148 | node->next.erase(c); 149 | } 150 | __del(word, index + 1, node->next.at(c)); 151 | } 152 | 153 | 154 | // 添加word 155 | void add(string word, int index, Node *node) { 156 | Node *cur = node; 157 | if (index == word.size()) { 158 | if (cur->isWord == false) { // 添加的是个新单词 159 | cur->value = 1; 160 | cur->isWord = true; 161 | size++; 162 | } else { 163 | cur->value++; 164 | } 165 | return; 166 | } 167 | char c = word[index]; 168 | if (cur->next.count(c) == 0) 169 | cur->next.insert(make_pair(c, new Node())); 170 | add(word, index + 1, node->next.at(c)); 171 | return; 172 | } 173 | 174 | // 是否包含word 175 | bool contain(string word, int index, Node *node) { 176 | Node *cur = node; 177 | if (index == word.size()) 178 | return cur->isWord; 179 | char c = word[index]; 180 | if (cur->next.count(c) == 0) 181 | return false; 182 | return contain(word, index + 1, node->next.at(c)); 183 | } 184 | 185 | // 是否包含前缀 186 | bool isPrefix(string word, int index, Node *node) { 187 | Node *cur = node; 188 | if (index == word.size()) 189 | return true; 190 | char c = word[index]; 191 | if (cur->next.count(c) == 0) 192 | return false; 193 | return isPrefix(word, index + 1, node->next.at(c)); 194 | } 195 | }; 196 | 197 | 198 | #endif //ALG_TRIE_H 199 | -------------------------------------------------------------------------------- /玩转儿数据结构/unionfind/README.md: -------------------------------------------------------------------------------- 1 | UnionFind example: 2 | 3 | 128 4 | 200 5 | 130 -------------------------------------------------------------------------------- /玩转儿数据结构/unionfind/unionfind.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-26. 3 | // 4 | 5 | #include "unionfind.h" 6 | 7 | double testUF(UF uf, int m) { 8 | int size = uf.getSize(); 9 | time_t start = clock(); 10 | // [0,size)范围随机数 11 | for (int i = 0; i < m; i++) { 12 | int a = rand() % size; 13 | int b = rand() % size; 14 | uf.unionElements(a, b); 15 | } 16 | for (int i = 0; i < m; i++) { 17 | int a = rand() % size; 18 | int b = rand() % size; 19 | uf.isConnected(a, b); 20 | } 21 | time_t end = clock(); 22 | 23 | return double(end - start) / CLOCKS_PER_SEC; 24 | } 25 | 26 | int main() { 27 | 28 | UnionFind1 unionFind1(10); 29 | cout << unionFind1.getSize() << endl; 30 | cout << unionFind1.isConnected(1, 2) << endl; 31 | unionFind1.unionElements(1, 2); 32 | cout << unionFind1.isConnected(1, 2) << endl; 33 | 34 | UnionFind2 unionFind2(10); 35 | cout << unionFind2.getSize() << endl; 36 | unionFind2.unionElements(1, 2); 37 | unionFind2.unionElements(7, 2); 38 | cout << unionFind2.isConnected(1, 2) << endl; 39 | cout << unionFind2.isConnected(1, 7) << endl; 40 | cout << unionFind2.isConnected(2, 7) << endl; 41 | 42 | unionFind2.unionElements(3, 8); 43 | unionFind2.unionElements(4, 3); 44 | unionFind2.unionElements(9, 4); 45 | cout << unionFind2.isConnected(9, 8) << endl; 46 | int size = 10000000; 47 | int m = 10000000; 48 | UnionFind1 unionFind11(size); 49 | UnionFind1 unionFind22(size); 50 | UnionFind3 unionFind33(size); 51 | UnionFind4 unionFind44(size); 52 | UnionFind5 unionFind55(size); 53 | UnionFind6 unionFind66(size); 54 | cout << "UnionFind 1 result is " << testUF(unionFind11, m) << " s." << endl; 55 | cout << "UnionFind 2 result is " << testUF(unionFind22, m) << " s." << endl; 56 | cout << "UnionFind 3 result is " << testUF(unionFind33, m) << " s." << endl; 57 | cout << "UnionFind 4 result is " << testUF(unionFind44, m) << " s." << endl; 58 | cout << "UnionFind 5 result is " << testUF(unionFind55, m) << " s." << endl; 59 | cout << "UnionFind 6 result is " << testUF(unionFind66, m) << " s." << endl; 60 | return 0; 61 | } 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /玩转儿数据结构/unionfind/unionfind.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by light on 19-10-26. 3 | // 4 | 5 | #ifndef ALG_UNIONFIND_H 6 | #define ALG_UNIONFIND_H 7 | /** 8 | * 网络中节点间的连接状态 网络是个抽象的概念 9 | * 数学中的集合类实现 10 | */ 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | class UF { 18 | public: 19 | virtual int getSize() {}; 20 | 21 | virtual bool isConnected(int p, int q) {}; 22 | 23 | virtual void unionElements(int p, int q) {}; 24 | }; 25 | 26 | /** 27 | * 第一种UnionFind 28 | */ 29 | class UnionFind1 : public UF { 30 | private: 31 | vector id; 32 | public: 33 | UnionFind1(int size) { 34 | id = vector(size); 35 | // 每个id属于不同的集合 36 | for (int i = 0; i < id.size(); i++) 37 | id[i] = i; 38 | } 39 | 40 | int getSize() { 41 | return id.size(); 42 | } 43 | 44 | private: 45 | // 查找元素p对应的集合编号 quickfind find O(1) 46 | int find(int p) { 47 | assert(p >= 0 && p < id.size()); 48 | return id[p]; 49 | } 50 | 51 | public: 52 | virtual bool isConnected(int p, int q) { 53 | return find(p) == find(q); 54 | } 55 | 56 | // quick find union O(n) 合并元素p和元素q所属的集合 57 | virtual void unionElements(int p, int q) { 58 | int pId = find(p); 59 | int qId = find(q); 60 | 61 | if (pId == qId) return; 62 | // 将pId的所有pId更换为qId 最终p与q所属集合的所有元素都与q所属集合一致 63 | for (int i = 0; i < id.size(); i++) 64 | if (id[i] == pId) id[i] = qId; 65 | } 66 | }; 67 | 68 | /** 69 | * 第二种UnionFind 70 | * 查询与合并的时间复杂度都为O(h) h远远小于n h为树的高度 71 | */ 72 | class UnionFind2 : public UF { 73 | private: 74 | vector parent; 75 | public: 76 | UnionFind2(int size) { 77 | parent = vector(size); 78 | for (int i = 0; i < parent.size(); i++) 79 | parent[i] = i; 80 | } 81 | 82 | int getSize() { 83 | return parent.size(); 84 | } 85 | 86 | private: 87 | // 递归 88 | // 查找元素p的根节点 quickfind find O(h) h= 0 && p < parent.size()); 91 | if (parent[p] == p) 92 | return p; 93 | return find(parent[p]); 94 | } 95 | 96 | // 非递归 97 | int _find(int p) { 98 | assert(p >= 0 && p < parent.size()); 99 | while (parent[p] != p) 100 | p = parent[p]; 101 | return p; 102 | } 103 | 104 | public: 105 | virtual bool isConnected(int p, int q) { 106 | return find(p) == find(q); 107 | } 108 | 109 | // union O(h) h肯定小于n 故union要快 合并元素p的根节点与元素q的根节点 110 | virtual void unionElements(int p, int q) { 111 | int pRoot = find(p); 112 | int qRoot = find(q); 113 | 114 | if (pRoot == qRoot) return; 115 | parent[pRoot] = qRoot; 116 | } 117 | 118 | }; 119 | 120 | /** 121 | * 第三种 基于树的大小(只是当前父亲节点+孩子节点总数)优化 122 | */ 123 | class UnionFind3 : public UF { 124 | private: 125 | vector parent; 126 | vector sz; // sz[i]表示以i为根的集合中元素个数 127 | public: 128 | UnionFind3(int size) { 129 | parent = vector(size); 130 | sz = vector(size); 131 | for (int i = 0; i < parent.size(); i++) { 132 | parent[i] = i; 133 | sz[i] = 1; 134 | } 135 | 136 | } 137 | 138 | int getSize() { 139 | return parent.size(); 140 | } 141 | 142 | private: 143 | // 递归 144 | // 查找元素p的根节点 quickfind find O(h) h= 0 && p < parent.size()); 147 | if (parent[p] == p) 148 | return p; 149 | return find(parent[p]); 150 | } 151 | 152 | // 非递归 153 | int _find(int p) { 154 | assert(p >= 0 && p < parent.size()); 155 | while (parent[p] != p) 156 | p = parent[p]; 157 | return p; 158 | } 159 | 160 | public: 161 | virtual bool isConnected(int p, int q) { 162 | return find(p) == find(q); 163 | } 164 | 165 | // union O(h) h肯定小于n 故union要快 合并元素p的根节点与元素q的根节点 166 | virtual void unionElements(int p, int q) { 167 | int pRoot = find(p); 168 | int qRoot = find(q); 169 | 170 | if (pRoot == qRoot) return; 171 | // 根据两个元素所在树的元素个数不同判断合并方向 172 | // 将元素少的集合合并到元素多的集合上 173 | if (sz[pRoot] < sz[qRoot]) { 174 | parent[pRoot] = qRoot; 175 | sz[qRoot] += sz[pRoot]; 176 | } else { 177 | parent[qRoot] = pRoot; 178 | sz[pRoot] += sz[qRoot]; 179 | } 180 | } 181 | }; 182 | 183 | /** 184 | * 基于rank(树的深度)的优化 185 | */ 186 | class UnionFind4 : public UF { 187 | private: 188 | vector parent; 189 | vector rank; // rank[i]表示根节点为i的树的高度 190 | public: 191 | UnionFind4(int size) { 192 | parent = vector(size); 193 | rank = vector(size); 194 | for (int i = 0; i < parent.size(); i++) { 195 | parent[i] = i; 196 | rank[i] = 1; 197 | } 198 | 199 | } 200 | 201 | int getSize() { 202 | return parent.size(); 203 | } 204 | 205 | private: 206 | // 递归 207 | // 查找元素p的根节点 quickfind find O(h) h= 0 && p < parent.size()); 210 | if (parent[p] == p) 211 | return p; 212 | return find(parent[p]); 213 | } 214 | 215 | // 非递归 216 | int _find(int p) { 217 | assert(p >= 0 && p < parent.size()); 218 | while (parent[p] != p) 219 | p = parent[p]; 220 | return p; 221 | } 222 | 223 | public: 224 | virtual bool isConnected(int p, int q) { 225 | return find(p) == find(q); 226 | } 227 | 228 | // union O(h) h肯定小于n 故union要快 合并元素p的根节点与元素q的根节点 229 | virtual void unionElements(int p, int q) { 230 | int pRoot = find(p); 231 | int qRoot = find(q); 232 | 233 | if (pRoot == qRoot) return; 234 | // 根据两个元素所在树的rank不同判断合并方向 235 | // 将rank低的集合合并到rank高的集合上 236 | if (rank[pRoot] < rank[qRoot]) 237 | parent[pRoot] = qRoot; 238 | else if (rank[qRoot] < rank[pRoot]) 239 | parent[qRoot] = pRoot; 240 | else { // rank[pRoot] == rank[qRoot] 241 | parent[qRoot] = pRoot; 242 | rank[pRoot] += 1; 243 | } 244 | } 245 | }; 246 | 247 | /** 248 | * 第五种 路径压缩 249 | */ 250 | class UnionFind5 : public UF { 251 | private: 252 | vector parent; 253 | vector rank; // rank[i]表示根节点为i的树的高度 此时不同于第四种方法 并不实际反应高度值 254 | public: 255 | UnionFind5(int size) { 256 | parent = vector(size); 257 | rank = vector(size); 258 | for (int i = 0; i < parent.size(); i++) { 259 | parent[i] = i; 260 | rank[i] = 1; 261 | } 262 | 263 | } 264 | 265 | int getSize() { 266 | return parent.size(); 267 | } 268 | 269 | private: 270 | // 递归 271 | // 查找元素p的根节点 quickfind find O(h) h= 0 && p < parent.size()); 274 | if (parent[p] == p) 275 | return p; 276 | parent[p] = parent[parent[p]]; // add this line 不需要维护rank 277 | return find(parent[p]); 278 | } 279 | 280 | // 非递归 281 | int _find(int p) { 282 | assert(p >= 0 && p < parent.size()); 283 | while (parent[p] != p) { 284 | parent[p] = parent[parent[p]]; // add this line 不需要维护rank 285 | p = parent[p]; 286 | } 287 | return p; 288 | } 289 | 290 | public: 291 | virtual bool isConnected(int p, int q) { 292 | return find(p) == find(q); 293 | } 294 | 295 | // union O(h) h肯定小于n 故union要快 合并元素p的根节点与元素q的根节点 296 | virtual void unionElements(int p, int q) { 297 | int pRoot = find(p); 298 | int qRoot = find(q); 299 | 300 | if (pRoot == qRoot) return; 301 | // 根据两个元素所在树的rank不同判断合并方向 302 | // 将rank低的集合合并到rank高的集合上 303 | if (rank[pRoot] < rank[qRoot]) 304 | parent[pRoot] = qRoot; 305 | else if (rank[qRoot] < rank[pRoot]) 306 | parent[qRoot] = pRoot; 307 | else { // rank[pRoot] == rank[qRoot] 308 | parent[qRoot] = pRoot; 309 | rank[pRoot] += 1; 310 | } 311 | } 312 | }; 313 | 314 | /** 315 | * 第六种 路径压缩 316 | */ 317 | class UnionFind6 : public UF { 318 | private: 319 | vector parent; 320 | vector rank; // rank[i]表示根节点为i的树的高度 此时不同于第四种方法 并不实际反应高度值 321 | public: 322 | UnionFind6(int size) { 323 | parent = vector(size); 324 | rank = vector(size); 325 | for (int i = 0; i < parent.size(); i++) { 326 | parent[i] = i; 327 | rank[i] = 1; 328 | } 329 | 330 | } 331 | 332 | int getSize() { 333 | return parent.size(); 334 | } 335 | 336 | private: 337 | // 递归 338 | // 查找元素p的根节点 quickfind find O(h) h= 0 && p < parent.size()); 341 | if (parent[p] != p) 342 | parent[p] = find(parent[p]); // 直接指向根节点 343 | return parent[p]; 344 | } 345 | 346 | 347 | public: 348 | virtual bool isConnected(int p, int q) { 349 | return find(p) == find(q); 350 | } 351 | 352 | // union O(h) h肯定小于n 故union要快 合并元素p的根节点与元素q的根节点 353 | virtual void unionElements(int p, int q) { 354 | int pRoot = find(p); 355 | int qRoot = find(q); 356 | 357 | if (pRoot == qRoot) return; 358 | // 根据两个元素所在树的rank不同判断合并方向 359 | // 将rank低的集合合并到rank高的集合上 360 | if (rank[pRoot] < rank[qRoot]) 361 | parent[pRoot] = qRoot; 362 | else if (rank[qRoot] < rank[pRoot]) 363 | parent[qRoot] = pRoot; 364 | else { // rank[pRoot] == rank[qRoot] 365 | parent[qRoot] = pRoot; 366 | rank[pRoot] += 1; 367 | } 368 | } 369 | }; 370 | 371 | 372 | #endif //ALG_UNIONFIND_H 373 | --------------------------------------------------------------------------------