├── .gitignore ├── CMakeLists.txt ├── Chap10_SkipAndHashTable ├── CMakeLists.txt ├── dictionary.h ├── hashChain.h ├── hashTable.h ├── skipList.h ├── skipNode.h ├── sortedChain.h ├── test_hashChain.cpp ├── test_hashTable.cpp ├── test_skipList.cpp └── test_sortedchain.cpp ├── Chap11_BinaryTree ├── CMakeLists.txt ├── advancedUnion.h ├── binaryTree.h ├── binaryTreeNode.h ├── linkedBinaryTree.h ├── test_Union.cpp └── test_binaryTree.cpp ├── Chap12_PriorityQueue ├── CMakeLists.txt ├── heapSort.h ├── huffmanTree.h ├── maxHblt.h ├── maxHeap.h ├── maxPriorityQueue.h ├── maxWblt.h ├── minHeap.h ├── test.txt ├── test_heapSort.cpp ├── test_huffmanTree.cpp ├── test_maxHblt.cpp ├── test_maxHeap.cpp └── test_maxWblt.cpp ├── Chap13_TouranmentTree ├── CMakeLists.txt ├── completeWinnerTree.h ├── test_completeWinnerTree.cpp └── winnerTree.h ├── Chap14_SearchTree ├── CMakeLists.txt ├── binarySearchTree.h ├── bsTree.h ├── indexBSTree.h ├── indexBinarySearchTree.h ├── test_binarySearchTree.cpp └── test_indexBinarySearchTree.cpp ├── Chap5_ArrayList ├── CMakeLists.txt ├── arrayList.h ├── changeLength1D.h ├── linearList.h ├── test_arrayList.cpp ├── test_vectorList.cpp └── vectorList.h ├── Chap6_LinkedList ├── CMakeLists.txt ├── chain.h ├── chainNode.h ├── circularListWithHeader.h ├── doublyLinkedListWithHeader.h ├── extendedChain.h ├── extendedLinearList.h ├── test_chain.cpp ├── test_circularListWithHeader.cpp ├── test_doublyLinkedListWithHeader.cpp └── test_extendedChain.cpp ├── Chap7_Matrix ├── CMakeLists.txt ├── matrix.h ├── spareMatrix.h ├── test_matrix.cpp └── test_spareMatrix.cpp ├── Chap8_Stack ├── CMakeLists.txt ├── arrayStack.h ├── linkedStack.h ├── stack.h ├── test_arrayStack.cpp └── test_linkedStack.cpp ├── Chap9_Queue ├── CMakeLists.txt ├── arrayDeque.h ├── arrayQueue.h ├── deque.h ├── linkedQueue.h ├── queue.h ├── test_Queue.cpp └── test_arrayDeque.cpp ├── LICENSE ├── MyExceptions.h ├── README.md └── images ├── dsa_a.jpg └── dsa_b.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | cmake-build-debug/ 3 | .DS-Store 4 | .vscode/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(DSACPP) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | add_subdirectory(Chap5_ArrayList) 7 | add_subdirectory(Chap6_LinkedList) 8 | add_subdirectory(Chap7_Matrix) 9 | add_subdirectory(Chap8_Stack) 10 | add_subdirectory(Chap9_Queue) 11 | add_subdirectory(Chap10_SkipAndHashTable) 12 | add_subdirectory(Chap11_BinaryTree) 13 | add_subdirectory(Chap12_PriorityQueue) 14 | add_subdirectory(Chap13_TouranmentTree) 15 | add_subdirectory(Chap14_SearchTree) -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | add_executable(Chap10_sortedChain dictionary.h sortedChain.h test_sortedchain.cpp) 6 | 7 | add_executable(Chap10_skipList skipNode.h skipList.h dictionary.h test_skipList.cpp) 8 | 9 | add_executable(Chap10_hashTable dictionary.h hashTable.h test_hashTable.cpp) 10 | 11 | add_executable(Chap10_hashChain dictionary.h hashChain.h test_hashChain.cpp) -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/dictionary.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/16. 3 | // 4 | 5 | #ifndef DSACPP_DICTIONARY_H 6 | #define DSACPP_DICTIONARY_H 7 | 8 | //字典的抽象类 9 | template 10 | class dictionary { 11 | public: 12 | virtual ~dictionary() {} 13 | 14 | //字典为空时返回true 15 | virtual bool empty() const = 0; 16 | 17 | //返回元素个数 18 | virtual int size() const = 0; 19 | 20 | //返回匹配数对的指针 21 | virtual std::pair* find(const K&) const = 0; 22 | 23 | //删除匹配的数对 24 | virtual void erase(const K&) = 0; 25 | 26 | //在字典中插入一个数对 27 | virtual void insert(const std::pair&) = 0; 28 | }; 29 | 30 | #endif //DSACPP_DICTIONARY_H 31 | -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/hashChain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/29. 3 | // 4 | 5 | #ifndef DSACPP_HASHCHAIN_H 6 | #define DSACPP_HASHCHAIN_H 7 | 8 | #include 9 | #include 10 | #include "dictionary.h" 11 | #include "sortedChain.h" 12 | 13 | //链表描述的hash表 14 | template 15 | class hashChain : public dictionary { 16 | public: 17 | //构造和析构函数 18 | hashChain(int theDivisor = 11); 19 | ~hashChain() { delete[] table;} 20 | 21 | //判空 22 | bool empty() const { return dSize == 0;} 23 | 24 | //数对的个数 25 | int size() const { return dSize;} 26 | 27 | //返回匹配数对的指针 28 | std::pair* find(const K& theKey) const { return table[hash(theKey) % divisor].find(theKey);} 29 | 30 | //删除匹配的数对 31 | void erase(const K&); 32 | 33 | //在字典中插入一个数对 34 | void insert(const std::pair&); 35 | 36 | //把数对插入到输出流中 37 | void output(std::ostream& out) const; 38 | 39 | private: 40 | sortedChain* table; //hash表 41 | std::hash hash; //hash函数 42 | int dSize; //数对的个数 43 | int divisor; //散列函数除数 44 | }; 45 | 46 | //构造函数 47 | template 48 | hashChain::hashChain(int theDivisor) { 49 | divisor = theDivisor; 50 | dSize = 0; 51 | table = new sortedChain [divisor]; 52 | } 53 | 54 | //插入数对 55 | template 56 | void hashChain::insert(const std::pair &thePair) { 57 | int homeBucket = (int) hash(thePair.first) % divisor; 58 | int homeSize = table[homeBucket].size(); 59 | table[homeBucket].insert(thePair); 60 | //确定是否插入了新的数对 61 | if (table[homeBucket].size() > homeSize) 62 | ++dSize; 63 | } 64 | 65 | //删除关键字对应的数对 66 | template 67 | void hashChain::erase(const K &theKey) { 68 | int homeBucket = (int) hash(theKey) % divisor; 69 | int homeSize = table[homeBucket].size(); 70 | table[homeBucket].erase(theKey); 71 | //确定是否插入了新的数对 72 | if (table[homeBucket].size() < homeSize) 73 | --dSize; 74 | } 75 | 76 | //将数对插入到输出流 77 | template 78 | void hashChain::output(std::ostream &out) const { 79 | for (int i = 0; i < divisor; ++i) { 80 | if (table[i].empty()) 81 | std::cout << "NULL "; 82 | else 83 | std::cout << table[i]; 84 | } 85 | } 86 | 87 | //重载<<运算符 88 | template 89 | std::ostream& operator<<(std::ostream& out, const hashChain& x) { 90 | x.output(out); 91 | return out; 92 | } 93 | 94 | #endif //DSACPP_HASHCHAIN_H 95 | -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/hashTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/28. 3 | // 4 | 5 | #ifndef DSACPP_HASHTABLE_H 6 | #define DSACPP_HASHTABLE_H 7 | 8 | #include 9 | #include 10 | #include "dictionary.h" 11 | #include "../MyExceptions.h" 12 | 13 | //散列表 14 | template 15 | class hashTable : public dictionary { 16 | public: 17 | //构造和析构函数 18 | hashTable(int theDivisor = 11); 19 | ~hashTable() { delete[] table;} 20 | 21 | //判断是否为空 22 | bool empty() const { return dSize == 0;} 23 | 24 | //返回数对个数 25 | int size() const { return dSize;} 26 | 27 | //寻找关键字对应的数对 28 | std::pair* find(const K&) const; 29 | 30 | //删除匹配的数对 31 | void erase(const K&); 32 | 33 | //在字典中插入一个数对 34 | void insert(const std::pair&); 35 | 36 | //把数对插入到输出流中 37 | void output(std::ostream& out) const; 38 | 39 | private: 40 | //寻找关键字对应的下标 41 | int search(const K&) const; 42 | 43 | //寻找第一个下标在theIndex左边(可循环),并且是允许被关键字theKey对应的数对替换的桶 44 | int findFirstUseful(const K &theKey, int theIndex) const; 45 | 46 | //数据成员 47 | std::pair** table; //散列表 48 | std::hash hash; //把类型K 映射到一个非负整数 49 | int dSize; //数对的个数 50 | int divisor; //散列函数除数 51 | }; 52 | 53 | //构造函数 54 | template 55 | hashTable::hashTable(int theDivisor) { 56 | divisor = theDivisor; 57 | dSize = 0; 58 | 59 | //分配和初始化散列表数组 60 | table = new std::pair* [divisor]; 61 | for (int i = 0; i < divisor; ++i) 62 | table[i] = NULL; 63 | } 64 | 65 | //寻找关键字对应的下标 66 | template 67 | int hashTable::search(const K &theKey) const { 68 | int i = (int)hash(theKey) % divisor; //起始桶 69 | int j = i; 70 | do { 71 | //table[j]不存在或者符合要求 72 | if (table[j] == NULL || table[j]->first == theKey) 73 | return j; 74 | j = (j + 1) % divisor; //下一个桶 75 | } while (j != i); 76 | 77 | return j; //表满 78 | } 79 | 80 | //查找函数 81 | template 82 | std::pair* hashTable::find(const K &theKey) const { 83 | //搜索散列表 84 | int b = search(theKey); 85 | 86 | //判断是否匹配 87 | if (table[b] == NULL || table[b]->first != theKey) 88 | return NULL; 89 | 90 | return table[b]; 91 | } 92 | 93 | //插入数对 94 | template 95 | void hashTable::insert(const std::pair &thePair) { 96 | //搜索散列表 97 | int b = search(thePair.first); 98 | 99 | //检查匹配的数对是否存在 100 | if (table[b] == NULL) { 101 | //没有匹配的数对 102 | table[b] = new std::pair (thePair); 103 | ++dSize; 104 | } else { 105 | if (table[b]->first == thePair.first) 106 | //匹配的数对存在,修改table[b]->second 107 | table[b]->second = thePair.second; 108 | else 109 | throw hashTableFull(); //表满 110 | } 111 | } 112 | 113 | //寻找第一个下标在theIndex左边(可循环),并且是允许被关键字theKey对应的数对替换的桶 114 | template 115 | int hashTable::findFirstUseful(const K &theKey, int theIndex) const { 116 | int i = (int)hash(theKey) % divisor; //起始桶 117 | int j = i; 118 | do { 119 | if (j >= theIndex || table[j]->first == theKey) 120 | return j; 121 | j = (j + 1) % divisor; 122 | } while (j != i); 123 | return j; 124 | } 125 | 126 | //删除数对 127 | template 128 | void hashTable::erase(const K &theKey) { 129 | //从要删除的从下一个位置开始,逐个检查每个桶,确定要移动的元素,直到遇到空桶或者回到删除位置 130 | int theIndex = search(theKey); 131 | 132 | //没有匹配的数对 133 | if (table[theIndex] == NULL || table[theIndex]->first != theKey) 134 | return; 135 | 136 | int i = theIndex, j = (theIndex + 1) % divisor; //i是当前需要被删除的桶,j用来检查每个桶 137 | //没有遇到空桶,或者没有回到theIndex 138 | while (table[j] != NULL && j != theIndex) { 139 | //允许被插入的位置 140 | int k = findFirstUseful(table[j]->first, i); 141 | //k正好是i 142 | if (k == i) { 143 | table[i] = table[j]; 144 | i = j; 145 | } 146 | j = (j + 1) % divisor; 147 | } 148 | table[i] = NULL; 149 | --dSize; 150 | } 151 | 152 | //将数对插入到输出流上 153 | template 154 | void hashTable::output(std::ostream &out) const { 155 | for (int i = 0; i < divisor; ++i) { 156 | if (table[i] != NULL) 157 | out << "<" << table[i]->first << ", " << table[i]->second << "> "; 158 | else 159 | cout << "NULL "; 160 | } 161 | } 162 | 163 | //重载<<运算符 164 | template 165 | std::ostream& operator<<(std::ostream& out, const hashTable& x) { 166 | x.output(out); 167 | return out; 168 | } 169 | 170 | #endif //DSACPP_HASHTABLE_H 171 | -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/skipList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/21. 3 | // 4 | 5 | #ifndef DSACPP_SKIPLIST_H 6 | #define DSACPP_SKIPLIST_H 7 | 8 | #include 9 | #include 10 | #include "skipNode.h" 11 | #include "dictionary.h" 12 | #include "../MyExceptions.h" 13 | 14 | //跳表 15 | template 16 | class skipList : public dictionary { 17 | public: 18 | //构造和析构函数 19 | skipList(K largeKey, int maxPairs = 10000, float prob = 0.5); 20 | ~skipList(); 21 | 22 | //判断是否为空 23 | bool empty() const { return dSize == 0;} 24 | 25 | //返回数对个数 26 | int size() const { return dSize;} 27 | 28 | //返回匹配数对的指针 29 | std::pair* find(const K&) const; 30 | 31 | //删除匹配的数对 32 | void erase(const K&); 33 | 34 | //在字典中插入一个数对 35 | void insert(const std::pair&); 36 | 37 | //将数对插入到输出流中 38 | void output(std::ostream& out) const; 39 | 40 | public: 41 | class iterator; //前向迭代器 42 | 43 | //begin和end方法 44 | iterator begin() { return iterator(headerNode->next[0]);} 45 | iterator end() { return iterator(tailNode);} 46 | 47 | private: 48 | //级的分配方法 49 | int level() const; 50 | 51 | //搜索并把在每一级链表搜索时遇到的最后一个结点存储起来 52 | skipNode* search(const K&) const; 53 | 54 | //数据成员 55 | float cutOff; //随机数生成器的上限,用于确定被插入结点的层数 56 | int levels; //链表的级数 57 | int dSize; //数对的个数 58 | int maxLevel; //允许的最大链表层数 59 | K tailKey; //最大关键字 60 | 61 | skipNode* headerNode; //头结点指针 62 | skipNode* tailNode; //尾结点指针 63 | skipNode** last; //last[i] 表示 i 层的最后结点 64 | }; 65 | 66 | //构造函数 67 | template 68 | skipList::skipList(K largeKey, int maxPairs, float prob) { 69 | //关键字小于largeKey 且数对个数size最多为maxPairs,0 < prob < 1 70 | cutOff = prob * RAND_MAX; 71 | maxLevel = (int) ceil(logf((float) maxPairs) / logf(1 / prob)) - 1; 72 | levels = 0; //初始化级数 73 | dSize = 0; 74 | tailKey = largeKey; 75 | 76 | //生成头结点、尾结点和数组last 77 | std::pair tailPair; 78 | tailPair.first = tailKey; 79 | headerNode = new skipNode (tailPair, maxLevel + 1); 80 | tailNode = new skipNode (tailPair, 0); 81 | last = new skipNode *[maxLevel + 1]; 82 | 83 | //链表为空,任意级链表的头结点都指向尾结点 84 | for (int i = 0; i <= maxLevel; ++i) 85 | headerNode->next[i] = tailNode; 86 | } 87 | 88 | //析构函数 89 | template 90 | skipList::~skipList() { 91 | //删除所有结点和数组 92 | 93 | skipNode* nextNode; 94 | //从headerNode开始,延数对链的方向删除 95 | while (headerNode != tailNode) { 96 | nextNode = headerNode->next[0]; 97 | delete headerNode; 98 | headerNode = nextNode; 99 | } 100 | 101 | delete tailNode; 102 | delete [] last; 103 | } 104 | 105 | //前向迭代器 106 | template 107 | class skipList::iterator { 108 | public: 109 | typedef forward_iterator_tag iterator_category; //向前迭代器 110 | typedef std::pair value_type; //迭代器指向的数据类型 111 | typedef std::pair* pointer; //指针 112 | typedef std::pair& reference; //引用 113 | 114 | //构造函数 115 | iterator(skipNode* theNode = NULL) { node = theNode;} 116 | 117 | //解引用操作符 118 | std::pair& operator*() { return node->element;} 119 | std::pair* operator->() { return &node->element;} 120 | 121 | //迭代器加法操作 122 | iterator& operator++() {node = node->next[0]; return *this;} //前加 123 | iterator operator++(int){ //后加 124 | iterator old = *this; 125 | node = node->next[0]; 126 | return old; 127 | } 128 | 129 | //相等检验 130 | bool operator!=(const iterator right) const {return node != right.node;} 131 | bool operator==(const iterator right) const {return node == right.node;} 132 | private: 133 | skipNode* node; //指向跳表结点的指针 134 | }; 135 | 136 | //返回匹配数对的指针 137 | template 138 | std::pair* skipList::find(const K &theKey) const { 139 | //从最高级链表开始查找,在每一级链表中,从左边尽可能逼近要查找的记录 140 | 141 | //没有可能匹配的数对 142 | if (theKey >= tailKey) 143 | return NULL; 144 | 145 | //位置beforeNode是关键字为theKey的结点之前最右边的位置 146 | skipNode* beforeNode = headerNode; 147 | for (int i = levels; i >= 0; --i) { 148 | //自上而下追踪 i 级链表指针 149 | while (beforeNode->next[i]->element.first < theKey) 150 | beforeNode = beforeNode->next[i]; 151 | } 152 | 153 | //检查下一个结点的关键字是否是theKey 154 | if (beforeNode->next[0]->element.first == theKey) 155 | return &beforeNode->next[0]->element; 156 | 157 | return NULL; //没有匹配的数对 158 | } 159 | 160 | //确定新插入的结点分配到哪一级 161 | template 162 | int skipList::level() const { 163 | //返回一个表示链表级的随机数,这个数不大于maxLevel 164 | int lev = 0; 165 | while (rand() <= cutOff) 166 | ++lev; 167 | return (lev <= maxLevel) ? lev : maxLevel; 168 | } 169 | 170 | //搜索并把在每一级链表搜索时遇到的最后一个结点存储起来 171 | template 172 | skipNode* skipList::search(const K &theKey) const { 173 | //位置beforeNode是关键字为theKey的结点之前最右边的位置 174 | skipNode* beforeNode = headerNode; 175 | for (int i = levels; i >= 0; --i) { 176 | //自上而下追踪 i 级链表指针 177 | while (beforeNode->next[i]->element.first < theKey) 178 | beforeNode = beforeNode->next[i]; 179 | last[i] = beforeNode; //存储搜索 i 级链表时遇到的最后一个结点 180 | } 181 | return beforeNode->next[0]; 182 | } 183 | 184 | //跳表的插入 185 | template 186 | void skipList::insert(const std::pair &thePair) { 187 | //关键字太大 188 | if (thePair.first >= tailKey) { 189 | std::ostringstream s; 190 | s << "Key = " << thePair.first << " Must be < " << tailKey; 191 | throw illegalParameterValue(s.str()); 192 | } 193 | 194 | //查看和插入数对相同关键字的数对是否已经存在 195 | skipNode* theNode = search(thePair.first); 196 | if (theNode->element.first == thePair.first) { 197 | //已经存在,则更新数对的值 198 | theNode->element.second = thePair.second; 199 | return; 200 | } 201 | 202 | //如果不存在,则确定新结点所在的级链表 203 | int theLevel = level(); //新结点的级 204 | //保证级theLevel <= levels + 1 205 | if (theLevel > levels) { 206 | theLevel = ++levels; 207 | last[theLevel] = headerNode; 208 | } 209 | 210 | //在结点theNode之后插入新结点 211 | skipNode* newNode = new skipNode (thePair, theLevel + 1); 212 | for (int i = 0; i <= theLevel; ++i) { 213 | //自下而上,插入i级链表 214 | newNode->next[i] = last[i]->next[i]; 215 | last[i]->next[i] = newNode; 216 | } 217 | 218 | ++dSize; 219 | return; 220 | } 221 | 222 | //删除跳表的记录 223 | template 224 | void skipList::erase(const K &theKey) { 225 | //关键字太大 226 | if (theKey >= tailKey) 227 | return; 228 | 229 | //查看是否存在关键字匹配的数对 230 | skipNode* theNode = search(theKey); 231 | if (theNode->element.first != theKey) 232 | //不存在 233 | return; 234 | 235 | //从跳表中删除结点 236 | for (int i = 0; i <= levels && last[i]->next[i] == theNode; ++i) 237 | last[i]->next[i] = theNode->next[i]; 238 | 239 | //更新链表级 240 | while (levels > 0 && headerNode->next[levels] == tailNode) 241 | --levels; 242 | 243 | delete theNode; 244 | --dSize; 245 | } 246 | 247 | //将数对插入到输出流 248 | template 249 | void skipList::output(std::ostream &out) const { 250 | //遍历0级链表 251 | for (skipNode* currentNode = headerNode->next[0]; currentNode != tailNode; 252 | currentNode = currentNode->next[0]) 253 | out << "<" << currentNode->element.first << ", " << currentNode->element.second << "> "; 254 | } 255 | 256 | //重载<<运算符 257 | template 258 | ostream& operator<<(ostream& out, const skipList& x) { 259 | x.output(out); 260 | return out; 261 | } 262 | 263 | #endif //DSACPP_SKIPLIST_H 264 | -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/skipNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/21. 3 | // 4 | 5 | #ifndef DSACPP_SKIPNODE_H 6 | #define DSACPP_SKIPNODE_H 7 | 8 | #include 9 | 10 | //跳表的结点 11 | template 12 | struct skipNode { 13 | typedef std::pair pairType; 14 | 15 | pairType element; 16 | skipNode **next; //指针数组 17 | 18 | //构造函数 19 | skipNode(const pairType& thePair, int size) : element(thePair) { 20 | next = new skipNode* [size]; 21 | } 22 | }; 23 | 24 | #endif //DSACPP_SKIPNODE_H 25 | -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/sortedChain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/18. 3 | // 4 | 5 | #ifndef DSACPP_SORTEDCHAIN_H 6 | #define DSACPP_SORTEDCHAIN_H 7 | 8 | #include 9 | #include "dictionary.h" 10 | 11 | //字典结点 12 | template 13 | struct pairNode { 14 | typedef std::pair pairType; 15 | pairType element; 16 | pairNode* next; 17 | 18 | pairNode(const pairType& theElement, pairNode* theNext) : element(theElement) { 19 | next = theNext; 20 | } 21 | }; 22 | 23 | 24 | //用链表描述的已排序字典 25 | template 26 | class sortedChain : public dictionary { 27 | public: 28 | //构造和析构函数 29 | sortedChain() { firstNode = NULL; dSize = 0;} 30 | ~sortedChain(); 31 | 32 | //判空 33 | bool empty() const { return dSize == 0;} 34 | 35 | //返回元素个数 36 | int size() const { return dSize;} 37 | 38 | //寻找关键字K对应元素值 39 | std::pair* find(const K&) const; 40 | 41 | //删除关键字K对应的数对 42 | void erase(const K&); 43 | 44 | //插入数对 45 | void insert(const std::pair&); 46 | 47 | //将数对插入到输出流 48 | void output(std::ostream& out) const; 49 | 50 | //重载[]运算符 51 | std::pair* operator[](const K&); 52 | 53 | private: 54 | pairNode* firstNode; //链表结点 55 | int dSize; //链表长度 56 | }; 57 | 58 | //析构函数 59 | template 60 | sortedChain::~sortedChain() { 61 | //删除所有工具 62 | while (firstNode != NULL) { 63 | pairNode* nextNode = firstNode->next; 64 | delete firstNode; 65 | firstNode = nextNode; 66 | } 67 | } 68 | 69 | //重载[] 70 | template 71 | std::pair* sortedChain::operator[](const K &theKey) { 72 | pairNode* currentNode = firstNode; 73 | //搜索关键字为thekey的数对 74 | while (currentNode != NULL && currentNode->element.first != theKey) 75 | currentNode = currentNode->next; 76 | 77 | //判断是否匹配 78 | if (currentNode != NULL && currentNode->element.first == theKey) 79 | return ¤tNode->element; 80 | 81 | //没有匹配的数对 82 | return NULL; 83 | } 84 | 85 | //寻找关键字对应的数对 86 | template 87 | std::pair* sortedChain::find(const K &thekey) const { 88 | pairNode* currentNode = firstNode; 89 | //搜索关键字为thekey的数对 90 | while (currentNode != NULL && currentNode->element.first != thekey) 91 | currentNode = currentNode->next; 92 | 93 | //判断是否匹配 94 | if (currentNode != NULL && currentNode->element.first == thekey) 95 | return ¤tNode->element; 96 | 97 | //没有匹配的数对 98 | return NULL; 99 | } 100 | 101 | //插入数对 102 | template 103 | void sortedChain::insert(const std::pair &thePair) { 104 | pairNode *p = firstNode, *tp = NULL; //tp是p的前驱结点 105 | 106 | //找到第一个关键字不小于所给数对关键字的结点 107 | while (p != NULL && p->element.first < thePair.first) { 108 | tp = p; 109 | p = p->next; 110 | } 111 | 112 | //检查是否有匹配的数对 113 | if (p != NULL && p->element.first == thePair.first) { 114 | //替换旧值 115 | p->element.second = thePair.second; 116 | return; 117 | } 118 | 119 | //插入新的结点 120 | pairNode *newNode = new pairNode(thePair, p); 121 | 122 | //插入到tp之后 123 | if (tp == NULL) firstNode = newNode; 124 | else tp->next = newNode; 125 | 126 | ++dSize; 127 | } 128 | 129 | //删除关键字为K的数对 130 | template 131 | void sortedChain::erase(const K &theKey) { 132 | pairNode *p = firstNode, *tp = NULL; //tp是p的前驱结点 133 | 134 | //找到第一个关键字不小于所给数对关键字的结点 135 | while (p != NULL && p->element.first < theKey) { 136 | tp = p; 137 | p = p->next; 138 | } 139 | 140 | //检查是否有匹配的数对 141 | if (p != NULL && p->element.first == theKey) { 142 | //从链表删除结点 143 | if (tp == NULL) firstNode = p->next; //p是第一个结点 144 | else tp->next = p->next; 145 | 146 | delete p; 147 | --dSize; 148 | } 149 | } 150 | 151 | //将数对插入到输出流 152 | template 153 | void sortedChain::output(std::ostream &out) const { 154 | pairNode* currentNode = firstNode; 155 | //搜索关键字为thekey的数对 156 | while (currentNode != NULL) { 157 | out << "<" << currentNode->element.first << ", " << currentNode->element.second << "> "; 158 | currentNode = currentNode->next; 159 | } 160 | } 161 | 162 | //重载<<运算符 163 | template 164 | std::ostream& operator<<(std::ostream& out, const sortedChain& theChain) { 165 | theChain.output(out); 166 | return out; 167 | } 168 | 169 | #endif //DSACPP_SORTEDCHAIN_H 170 | -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/test_hashChain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/29. 3 | // 4 | 5 | #include 6 | #include "hashChain.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | hashChain z(11); 12 | pair p; 13 | 14 | // test insert 15 | p.first = 0; p.second = 3; 16 | z.insert(p); 17 | p.first = 2; p.second = 10; 18 | z.insert(p); 19 | p.first = 10; p.second = 50; 20 | z.insert(p); 21 | p.first = 24; p.second = 120; 22 | z.insert(p); 23 | p.first = 32; p.second = 160; 24 | z.insert(p); 25 | p.first = 3; p.second = 15; 26 | z.insert(p); 27 | p.first = 12; p.second = 60; 28 | z.insert(p); 29 | p.first = 21; p.second = 8; 30 | z.insert(p); 31 | cout << "The dictionary is " << endl << z << endl; 32 | cout << "Its size is " << z.size() << endl; 33 | 34 | // test find 35 | cout << "Element associated with 2 is " << z.find(2)->second << endl; 36 | cout << "Element associated with 10 is " << z.find(10)->second << endl; 37 | cout << "Element associated with 12 is " << z.find(12)->second << endl; 38 | 39 | // test erase 40 | z.erase(10); 41 | cout << "Delete the element whose key is 10: " << z << endl; 42 | z.erase(2); 43 | cout << "Delete the element whose key is 2: " << z << endl; 44 | 45 | p.first = 21; p.second = 4; 46 | z.insert(p); 47 | p.first = 43; p.second = 89; 48 | z.insert(p); 49 | p.first = 54; p.second = 78; 50 | z.insert(p); 51 | cout << "Insert the elements(<21, 4>, <43, 89>, <54, 78>): " << z << endl; 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/test_hashTable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/28. 3 | // 4 | 5 | #include 6 | #include "hashTable.h" 7 | 8 | using namespace std; 9 | 10 | int main() 11 | { 12 | hashTable z(11); 13 | pair p; 14 | 15 | // test insert 16 | p.first = 0; p.second = 3; 17 | z.insert(p); 18 | p.first = 2; p.second = 10; 19 | z.insert(p); 20 | p.first = 10; p.second = 50; 21 | z.insert(p); 22 | p.first = 24; p.second = 120; 23 | z.insert(p); 24 | p.first = 32; p.second = 160; 25 | z.insert(p); 26 | p.first = 3; p.second = 15; 27 | z.insert(p); 28 | p.first = 12; p.second = 60; 29 | z.insert(p); 30 | p.first = 21; p.second = 8; 31 | z.insert(p); 32 | cout << "The dictionary is " << endl << z << endl; 33 | cout << "Its size is " << z.size() << endl; 34 | 35 | // test find 36 | cout << "Element associated with 2 is " << z.find(2)->second << endl; 37 | cout << "Element associated with 10 is " << z.find(10)->second << endl; 38 | cout << "Element associated with 12 is " << z.find(12)->second << endl; 39 | 40 | // test erase 41 | z.erase(10); 42 | cout << "Delete the element whose key is 10: " << z << endl; 43 | z.erase(2); 44 | cout << "Delete the element whose key is 2: " << z << endl; 45 | 46 | p.first = 21; p.second = 4; 47 | z.insert(p); 48 | p.first = 43; p.second = 89; 49 | z.insert(p); 50 | p.first = 54; p.second = 78; 51 | z.insert(p); 52 | cout << "Insert the elements(<21, 4>, <43, 89>, <54, 78>): " << z << endl; 53 | return 0; 54 | } -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/test_skipList.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/21. 3 | // 4 | 5 | #include 6 | #include "skipList.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | skipList z(1000); 12 | pair p; 13 | 14 | // test insert 15 | p.first = 2; p.second = 10; 16 | z.insert(p); 17 | p.first = 10; p.second = 50; 18 | z.insert(p); 19 | p.first = 6; p.second = 30; 20 | z.insert(p); 21 | p.first = 8; p.second = 40; 22 | z.insert(p); 23 | p.first = 1; p.second = 5; 24 | z.insert(p); 25 | p.first = 12; p.second = 60; 26 | z.insert(p); 27 | cout << "The dictionary is " << z << endl; 28 | cout << "Its size is " << z.size() << endl; 29 | 30 | cout << "Use iterator and operator-> "; 31 | for (skipList::iterator i = z.begin(); i != z.end(); ++i) 32 | cout << "<" << i->first << ", " << i->second << "> "; 33 | cout << endl; 34 | cout << "Use iterator and operator* "; 35 | for (skipList::iterator i = z.begin(); i != z.end(); ++i) 36 | cout << "<" << (*i).first << ", " << (*i).second << "> "; 37 | cout << endl; 38 | 39 | // test find 40 | cout << "Element associated with 1 is " << z.find(1)->second << endl; 41 | cout << "Element associated with 6 is " << z.find(6)->second << endl; 42 | cout << "Element associated with 12 is " << z.find(12)->second << endl; 43 | 44 | // test erase 45 | z.erase(1); 46 | z.erase(2); 47 | z.erase(6); 48 | z.erase(12); 49 | cout << "Deleted 1, 2, 6, 12" << endl; 50 | cout << "The dictionary is " << z << endl; 51 | cout << "Its size is " << z.size() << endl; 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Chap10_SkipAndHashTable/test_sortedchain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/18. 3 | // 4 | 5 | #include 6 | #include "sortedChain.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | sortedChain s; 12 | for(int i = 0; i < 26; ++i) { 13 | s.insert(make_pair('a' + i, i)); 14 | s.insert(make_pair('A' + i, i)); 15 | } 16 | s['E']->second=8; 17 | cout << s.find('E')->second << endl; 18 | cout << s << endl; 19 | s.erase('E'); 20 | cout << s << endl; 21 | return 0; 22 | } -------------------------------------------------------------------------------- /Chap11_BinaryTree/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | include_directories(../Chap8_Stack) 6 | include_directories(../Chap9_Queue) 7 | 8 | add_executable(Chap11_linkedBinaryTree binaryTree.h binaryTreeNode.h linkedBinaryTree.h test_binaryTree.cpp) 9 | 10 | add_executable(Chap11_union advancedUnion.h test_Union.cpp) -------------------------------------------------------------------------------- /Chap11_BinaryTree/advancedUnion.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/3. 3 | // 4 | 5 | /* 6 | * 因为路径压缩会改变树的高度,但不会改变树的重量,所以使用重量规则来优化合并函数 7 | * 接下来分别实现了3种路径压缩算法(路径紧缩、路径分割和路径对折)来优化查找函数 8 | */ 9 | //使用重量规则的结点结构 10 | struct unionFindNode { 11 | int parent; //root为真时表示树的重量,即结点数,否则是父结点的指针 12 | bool root; //仅当为根时,值为真 13 | 14 | unionFindNode() { parent = 1; root = true;} 15 | }; 16 | 17 | struct advancedUnion { 18 | unionFindNode *node; 19 | advancedUnion(int numberOfElements) { initialize(numberOfElements);} 20 | 21 | //初始化并查集,每个结点就是一棵只包含它自己的树 22 | void initialize(int numberOfElements) { 23 | node = new unionFindNode[numberOfElements + 1]; 24 | } 25 | 26 | //使用重量规则来合并两个不同根的树 27 | void unite(int rootA, int rootB) { 28 | //将重量较轻的作为子树 29 | if (node[rootA].parent < node[rootB].parent) { 30 | //rootA作为子树 31 | node[rootB].parent += node[rootA].parent; 32 | node[rootA].root = false; 33 | node[rootA].parent = rootB; 34 | } else { 35 | node[rootA].parent += node[rootB].parent; 36 | node[rootB].root = false; 37 | node[rootB].parent = rootA; 38 | } 39 | } 40 | 41 | //普通的查找函数 42 | int find(int theElement) { 43 | while (!node[theElement].root) 44 | theElement = node[theElement].parent; 45 | return theElement; 46 | } 47 | 48 | /* 49 | * 使用路径紧缩来优化的查找函数 50 | * 从待查结点到根结点的路径上,所有结点的parent指针都被改为指向根结点 51 | */ 52 | int findWithCompaction(int theElement) { 53 | //找到最终的根theRoot 54 | int theRoot = theElement; 55 | while (!node[theRoot].root) 56 | theRoot = node[theRoot].parent; 57 | 58 | //压缩从theElement到theRoot的路径,将路径上的每个结点都指向theRoot 59 | int currentNode = theElement; 60 | while (currentNode != theRoot) { 61 | int parentNode = node[currentNode].parent; 62 | node[currentNode].parent = theRoot; //直接指向theRoot 63 | currentNode = parentNode; //向上移动一层 64 | } 65 | return theRoot; 66 | } 67 | 68 | /* 69 | * 使用路径分割来优化的查找函数 70 | * 从待查结点到根结点的路径上,除根结点和其子结点之外,每个结点的parent指针都被改为指向各自的祖父 71 | */ 72 | int findWithSplitting(int theElement) { 73 | int parentNode = 0; 74 | //除根结点和其子结点之外,每个结点的parent指针都被改为指向各自的祖父 75 | while (!node[theElement].root) { 76 | parentNode = node[theElement].parent; 77 | if (node[parentNode].root) //根结点的子结点 78 | return parentNode; 79 | node[theElement].parent = node[parentNode].parent; 80 | theElement = parentNode; 81 | } 82 | //最终的根结点 83 | return theElement; 84 | } 85 | 86 | /* 87 | * 使用路径对折来优化的查找函数 88 | * 从待查结点到根结点的路径上,除根结点和其子结点之外,每个结点的parent指针都被改为指向各自的祖父 89 | */ 90 | int findWithHalving(int theElement) { 91 | int parentNode = 0; 92 | //除根结点和其子结点之外,每个结点的parent指针都被改为指向各自的祖父 93 | while (!node[theElement].root) { 94 | parentNode = node[theElement].parent; 95 | if (node[parentNode].root) //根结点的子结点 96 | return parentNode; 97 | node[theElement].parent = node[parentNode].parent; 98 | theElement = node[parentNode].parent; 99 | } 100 | //最终的根结点 101 | return theElement; 102 | } 103 | }; -------------------------------------------------------------------------------- /Chap11_BinaryTree/binaryTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/2. 3 | // 4 | 5 | #ifndef DSACPP_BINARYTREE_H 6 | #define DSACPP_BINARYTREE_H 7 | 8 | //二叉树抽象类 9 | template 10 | class binaryTree { 11 | public: 12 | virtual ~binaryTree() {} 13 | 14 | //判断二叉树是否为空 15 | virtual bool empty() const = 0; 16 | 17 | //返回二叉树的元素个数 18 | virtual int size() const = 0; 19 | 20 | /* 21 | * 下面是4中遍历方法,参数为函数指针,可以制订访问结点数据时的方法 22 | */ 23 | //前序遍历 24 | virtual void preOrder(void (*) (T *)) = 0; 25 | 26 | //中序遍历 27 | virtual void inOrder(void (*) (T *)) = 0; 28 | 29 | //后序遍历 30 | virtual void postOrder(void (*) (T *)) = 0; 31 | 32 | //层次遍历 33 | virtual void levelOrder(void (*) (T *)) = 0; 34 | }; 35 | 36 | #endif //DSACPP_BINARYTREE_H 37 | -------------------------------------------------------------------------------- /Chap11_BinaryTree/binaryTreeNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/2. 3 | // 4 | 5 | #ifndef DSACPP_BINARYTREENODE_H 6 | #define DSACPP_BINARYTREENODE_H 7 | 8 | //链表二叉树的结点结构 9 | template 10 | struct binaryTreeNode { 11 | //结点数据和左右指针 12 | T element; 13 | binaryTreeNode *leftChild, *rightChild; 14 | 15 | binaryTreeNode() {leftChild = rightChild = nullptr;} 16 | binaryTreeNode(const T& theElement) : element(theElement) { 17 | leftChild = rightChild = nullptr; 18 | } 19 | binaryTreeNode(const T& theElement, binaryTreeNode *theLeftChild, 20 | binaryTreeNode *theRightChild) : element(theElement) { 21 | leftChild = theLeftChild; 22 | rightChild = theRightChild; 23 | } 24 | 25 | }; 26 | 27 | #endif //DSACPP_BINARYTREENODE_H 28 | -------------------------------------------------------------------------------- /Chap11_BinaryTree/linkedBinaryTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/2. 3 | // 4 | 5 | #ifndef DSACPP_LINKEDBINARYTREE_H 6 | #define DSACPP_LINKEDBINARYTREE_H 7 | 8 | #include "binaryTreeNode.h" 9 | #include "binaryTree.h" 10 | #include "arrayStack.h" 11 | #include "arrayQueue.h" 12 | 13 | //类linkedBinaryTree 14 | template 15 | class linkedBinaryTree : public binaryTree> { 16 | public: 17 | //构造和析构函数 18 | linkedBinaryTree() {root = NULL; treeSize = 0;} 19 | ~linkedBinaryTree() {erase();} 20 | 21 | //合成二叉树 22 | void makeTree(const E& theElement, linkedBinaryTree& theLeft, linkedBinaryTree& theRight); 23 | 24 | //判断是否为空 25 | bool empty() const { return treeSize == 0;} 26 | 27 | //树的结点个数 28 | int size() const { return treeSize;} 29 | 30 | //前序遍历 31 | void preOrder(void (*theVisit) (binaryTreeNode *)); 32 | 33 | //中序遍历 34 | void inOrder(void (*theVisit) (binaryTreeNode *)); 35 | 36 | //后序遍历 37 | void postOrder(void (*theVisit) (binaryTreeNode *)); 38 | 39 | //层次遍历 40 | void levelOrder(void (*theVisit) (binaryTreeNode *)); 41 | 42 | //求树的高度 43 | int height() const { return height(root);} 44 | 45 | //清空整个二叉树 46 | void erase() { 47 | postOrder(dispose); 48 | root = NULL; treeSize = 0; 49 | } 50 | 51 | protected: 52 | binaryTreeNode *root; //指向根结点的指针 53 | int treeSize; //树的结点个数 54 | static void (*visit) (binaryTreeNode*); //访问函数指针 55 | 56 | //删除结点 57 | static void dispose(binaryTreeNode *t) {delete t;} 58 | 59 | //求树的高度 60 | static int height(binaryTreeNode *t); 61 | }; 62 | 63 | //用于实力化visit 64 | template 65 | void (*linkedBinaryTree::visit)(binaryTreeNode*); 66 | 67 | //合成二叉树 68 | template 69 | void linkedBinaryTree::makeTree(const E &theElement, linkedBinaryTree &theLeft, linkedBinaryTree &theRight) { 70 | root = new binaryTreeNode (theElement, theLeft.root, theRight.root); 71 | treeSize = theLeft.treeSize + theRight.treeSize + 1; 72 | 73 | //释放子树 74 | theLeft.root = theRight.root = NULL; 75 | theLeft.treeSize = theRight.treeSize = 0; 76 | } 77 | 78 | //前序遍历 79 | template 80 | void linkedBinaryTree::preOrder(void (*theVisit) (binaryTreeNode *)) { 81 | //非递归实现 82 | if (root == NULL) 83 | return; 84 | 85 | visit = theVisit; 86 | arrayStack*> s(treeSize); 87 | binaryTreeNode *p = NULL; 88 | s.push(root); 89 | while (!s.empty()) { 90 | //访问根 91 | p = s.top(); 92 | s.pop(); 93 | visit(p); 94 | //按右左的顺序入栈 95 | if (p->rightChild != NULL) 96 | s.push(p->rightChild); 97 | if (p->leftChild != NULL) 98 | s.push(p->leftChild); 99 | } 100 | } 101 | 102 | //中序遍历 103 | template 104 | void linkedBinaryTree::inOrder(void (*theVisit) (binaryTreeNode *)) { 105 | //非递归实现 106 | if (root == NULL) 107 | return; 108 | 109 | visit = theVisit; 110 | arrayStack*> s(treeSize); 111 | binaryTreeNode *p = root; 112 | while (p != NULL || !s.empty()) { 113 | //将最左侧的结点入栈 114 | if (p != NULL) { 115 | s.push(p); 116 | p = p->leftChild; 117 | } else { 118 | //访问当前结点并进入右子树 119 | p = s.top(); 120 | s.pop(); 121 | visit(p); 122 | p = p->rightChild; 123 | } 124 | } 125 | } 126 | 127 | //后序遍历 128 | template 129 | void linkedBinaryTree::postOrder(void (*theVisit) (binaryTreeNode *)) { 130 | //非递归实现 131 | if (root == NULL) 132 | return; 133 | 134 | visit = theVisit; 135 | arrayStack*> s(treeSize); 136 | s.push(root); 137 | //用于后面判断是否可以将栈顶的结点弹出 138 | binaryTreeNode *pre = NULL; 139 | binaryTreeNode *cur = NULL; 140 | while (!s.empty()) { 141 | cur = s.top(); 142 | 143 | //判断是否需要弹出栈顶 144 | if ((cur->leftChild == NULL && cur->rightChild == NULL) || 145 | (pre != NULL && (pre == cur->leftChild || pre == cur->rightChild))) { 146 | //当当前结点是叶子结点,或者当前结点的左右子树都被访问过的时候弹出 147 | s.pop(); 148 | visit(cur); 149 | pre = cur; 150 | } else { 151 | //将右左子结点入栈 152 | if (cur->rightChild != NULL) 153 | s.push(cur->rightChild); 154 | if (cur->leftChild != NULL) 155 | s.push(cur->leftChild); 156 | } 157 | } 158 | } 159 | 160 | //层次遍历 161 | template 162 | void linkedBinaryTree::levelOrder(void (*theVisit) (binaryTreeNode *)) { 163 | //利用队列实现 164 | if (root == NULL) 165 | return; 166 | 167 | visit = theVisit; 168 | //辅助的队列空间 169 | arrayQueue*> q(treeSize / 2 + 1); 170 | q.push(root); 171 | binaryTreeNode *p = NULL; 172 | while (!q.empty()) { 173 | p = q.front(); 174 | q.pop(); 175 | visit(p); 176 | if (p->leftChild != NULL) 177 | q.push(p->leftChild); 178 | if (p->rightChild != NULL) 179 | q.push(p->rightChild); 180 | } 181 | } 182 | 183 | //求树高 184 | template 185 | int linkedBinaryTree::height(binaryTreeNode *t) { 186 | //采用中序遍历的方式 187 | if (t == NULL) 188 | return 0; 189 | int h1 = height(t->leftChild); 190 | int h2 = height(t->rightChild); 191 | 192 | //树的高度等于左右子树高度的最大值 + 1 193 | return 1 + ((h1 > h2) ? h1 : h2); 194 | } 195 | 196 | #endif //DSACPP_LINKEDBINARYTREE_H 197 | -------------------------------------------------------------------------------- /Chap11_BinaryTree/test_Union.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/3. 3 | // 4 | 5 | #include 6 | #include 7 | #include "advancedUnion.h" 8 | 9 | using namespace std; 10 | 11 | int main() { 12 | advancedUnion test1(1000), test2(1000), test3(1000), test4(1000); 13 | 14 | cout << "begin test!" << endl; 15 | //测试不同查找算法的性能 16 | std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); 17 | for (int n = 0; n < 10000; ++n) { 18 | int i = test1.find(rand() % 1000 + 1); 19 | int j = test1.find(rand() % 1000 + 1); 20 | if (i != j) test1.unite(i, j); 21 | } 22 | std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); 23 | std::chrono::duration time_used = std::chrono::duration_cast>(t2 - t1)*1000; 24 | std::cout << "find: " << time_used.count() << " ms" << std::endl; 25 | 26 | t1 = std::chrono::high_resolution_clock::now(); 27 | for (int n = 0; n < 10000; ++n) { 28 | int i = test2.findWithCompaction(rand() % 1000 + 1); 29 | int j = test2.findWithCompaction(rand() % 1000 + 1); 30 | if (i != j) test2.unite(i, j); 31 | } 32 | t2 = std::chrono::high_resolution_clock::now(); 33 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 34 | std::cout << "findWithCompaction: " << time_used.count() << " ms" << std::endl; 35 | 36 | t1 = std::chrono::high_resolution_clock::now(); 37 | for (int n = 0; n < 10000; ++n) { 38 | int i = test3.findWithSplitting(rand() % 1000 + 1); 39 | int j = test3.findWithSplitting(rand() % 1000 + 1); 40 | if (i != j) test3.unite(i, j); 41 | } 42 | t2 = std::chrono::high_resolution_clock::now(); 43 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 44 | std::cout << "findWithSplitting: " << time_used.count() << " ms" << std::endl; 45 | 46 | t1 = std::chrono::high_resolution_clock::now(); 47 | for (int n = 0; n < 10000; ++n) { 48 | int i = test4.findWithHalving(rand() % 1000 + 1); 49 | int j = test4.findWithHalving(rand() % 1000 + 1); 50 | if (i != j) test4.unite(i, j); 51 | } 52 | t2 = std::chrono::high_resolution_clock::now(); 53 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 54 | std::cout << "findWithHalving: " << time_used.count() << " ms" << std::endl; 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Chap11_BinaryTree/test_binaryTree.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/2. 3 | // 4 | 5 | #include 6 | #include "linkedBinaryTree.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | linkedBinaryTree a,x,y,z; 12 | y.makeTree(1,a,a); 13 | z.makeTree(2,a,a); 14 | x.makeTree(3,y,z); 15 | y.makeTree(4,x,a); 16 | cout << "Number of nodes = "; 17 | cout << y.size() << endl; 18 | cout << "height = "; 19 | cout << y.height() << endl; 20 | 21 | auto output = [] (binaryTreeNode* t) { if (t != NULL) cout << t->element << " ";}; 22 | cout << "preOrder output: "; 23 | y.preOrder(output); 24 | 25 | cout << endl << "inOrder output: "; 26 | y.inOrder(output); 27 | 28 | cout << endl << "postOrder output: "; 29 | y.postOrder(output); 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /Chap12_PriorityQueue/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | include_directories(../Chap11_BinaryTree) 6 | include_directories(../Chap8_Stack) 7 | include_directories(../Chap9_Queue) 8 | 9 | add_executable(Chap12_maxHeap maxPriorityQueue.h maxHeap.h ../MyExceptions.h ../Chap5_ArrayList/changeLength1D.h test_maxHeap.cpp) 10 | 11 | add_executable(Chap12_heapSort heapSort.h test_heapSort.cpp) 12 | 13 | add_executable(Chap12_maxHblt ../Chap11_BinaryTree/binaryTree.h maxHblt.h maxPriorityQueue.h test_maxHblt.cpp) 14 | 15 | add_executable(Chap12_maxWblt ../Chap11_BinaryTree/binaryTree.h maxPriorityQueue.h maxWblt.h test_maxWblt.cpp) 16 | 17 | add_executable(Chap12_huffmanTree minHeap.h huffmanTree.h test_huffmanTree.cpp) -------------------------------------------------------------------------------- /Chap12_PriorityQueue/heapSort.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/5. 3 | // 4 | 5 | #ifndef DSACPP_HEAPSORT_H 6 | #define DSACPP_HEAPSORT_H 7 | 8 | #include "maxHeap.h" 9 | 10 | //堆排序算法,排序a[1:n] 11 | template 12 | void heapSort(T a[], int n) { 13 | maxHeap heap(1); 14 | heap.initialize(a, n); 15 | //逐个从大根堆中提取最大值 16 | for (int i = n; i >= 1; --i) 17 | heap.pop(); 18 | 19 | //在heap析构之前保护a 20 | heap.deactivateArray(); 21 | } 22 | 23 | #endif //DSACPP_HEAPSORT_H 24 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/huffmanTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/9. 3 | // 4 | 5 | #ifndef DSACPP_HUFFMANTREE_H 6 | #define DSACPP_HUFFMANTREE_H 7 | 8 | #include "../Chap11_BinaryTree/binaryTreeNode.h" 9 | #include "minHeap.h" 10 | 11 | //huffman树的结点类型 12 | template 13 | struct huffmanNode { 14 | binaryTreeNode *tree; //二叉树的指针 15 | T weight; //权重 16 | 17 | //重载()运算符 18 | operator T () const { return weight;} 19 | }; 20 | 21 | //构造一棵huffman树 22 | template 23 | binaryTreeNode* huffmanTree(T weights[], int n) { 24 | //用权weight[1:n]生成huffman树,n >= 1 25 | //创建一组单结点树 26 | huffmanNode *hNode = new huffmanNode [n + 1]; 27 | for (int i = 1; i <= n; ++i) { 28 | hNode[i].weight = weights[i]; 29 | hNode[i].tree = new binaryTreeNode (i, NULL, NULL); 30 | } 31 | 32 | //使用一组单结点树构成小根堆 33 | minHeap> heap(1); 34 | heap.initialize(hNode, n); 35 | 36 | //不断从小根堆中提取两个树进行合并,直到只剩下一棵树 37 | huffmanNode w, x, y; 38 | binaryTreeNode *z; 39 | while (heap.size() > 1) { 40 | //从小根堆中提取两棵最轻的树 41 | x = heap.top(); heap.pop(); 42 | y = heap.top(); heap.pop(); 43 | 44 | //合并 45 | z = new binaryTreeNode (0, x.tree, y.tree); 46 | w.weight = x.weight + y.weight; //权重求和 47 | w.tree = z; 48 | heap.push(w); 49 | } 50 | 51 | //返回最后的huffman树 52 | return heap.top().tree; 53 | } 54 | 55 | #endif //DSACPP_HUFFMANTREE_H 56 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/maxHblt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/6. 3 | // 4 | 5 | #ifndef DSACPP_MAXHBLT_H 6 | #define DSACPP_MAXHBLT_H 7 | 8 | #include 9 | #include 10 | #include "../Chap11_BinaryTree/linkedBinaryTree.h" 11 | #include "../MyExceptions.h" 12 | #include "maxPriorityQueue.h" 13 | 14 | //最大高度优先左高树 15 | template 16 | class maxHblt : public maxPriorityQueue, linkedBinaryTree> { 17 | public: 18 | //判断是否为空 19 | bool empty() const { return this->treeSize == 0;} 20 | 21 | //元素个数 22 | int size() const { return this->treeSize;} 23 | 24 | //队首元素的引用 25 | const T& top(); 26 | 27 | //删除队首 28 | void pop(); 29 | 30 | //添加元素 31 | void push(const T& theElement); 32 | 33 | //初始化左高树 34 | void initialize(T *theElements, int theSize); 35 | 36 | //合并另一个棵树 37 | void meld(maxHblt &theHblt); 38 | 39 | typedef binaryTreeNode> pairType; 40 | private: 41 | //合并两棵左高树 42 | void meld(binaryTreeNode> *&, binaryTreeNode> *&); 43 | }; 44 | 45 | //返回最大元素的引用 46 | template 47 | const T& maxHblt::top() { 48 | if (this->treeSize == 0) 49 | throw queueEmpty(); 50 | 51 | return this->root->element.second; 52 | } 53 | 54 | //私有方法 合并两棵左高树 55 | template 56 | void maxHblt::meld(binaryTreeNode> *&x, binaryTreeNode> *&y) { 57 | //合并以 x 和 y 为根的两棵左高树,合并后的左高树以 x 为根 58 | if (y == NULL) return; 59 | if (x == NULL) { x = y; return;} 60 | 61 | //保证 x 是根结点的较大者 62 | if (x->element.second < y->element.second) 63 | std::swap(x, y); 64 | 65 | //递归的把 y 合并到 x->rightChild 66 | meld(x->rightChild, y); 67 | 68 | //如果 x 是叶子结点的话,现在 x 不是左高树,需要交换 x 的左右子结点 69 | if (x->leftChild == NULL) { 70 | x->leftChild = x->rightChild; 71 | x->rightChild = NULL; 72 | x->element.first = 1; //因为 x->rightChild 的 s 值是 0 73 | } else { 74 | //保证 x->leftChild 的 s 值是较大的 75 | if (x->leftChild->element.first < x->rightChild->element.first) 76 | std::swap(x->leftChild, x->rightChild); 77 | 78 | //更新 x 的 s 值 79 | x->element.first = x->rightChild->element.first + 1; //左高树的右子树的 s 值 是较小的那个 80 | } 81 | } 82 | 83 | //公有方法 合并另一颗左高树到*this上 84 | template 85 | void maxHblt::meld(maxHblt &theHblt) { 86 | //合并两个对象里面的左高树 87 | meld(this->root, theHblt.root); 88 | this->treeSize += theHblt.treeSize; 89 | //theHblt现在是空的 90 | theHblt.root = NULL; 91 | theHblt.treeSize = 0; 92 | } 93 | 94 | //插入元素 95 | template 96 | void maxHblt::push(const T &theElement) { 97 | //建立只有一个结点,并且值是theElement的左高树 98 | pairType *x = new pairType (std::make_pair(1, theElement)); 99 | 100 | //将 x 合并到 root 上 101 | meld(this->root, x); 102 | ++(this->treeSize); 103 | } 104 | 105 | //删除最大元素 106 | template 107 | void maxHblt::pop() { 108 | if (this->treeSize == 0) 109 | throw queueEmpty(); 110 | 111 | //合并root的左右子树并作为新的root 112 | pairType *left = this->root->leftChild, *right = this->root->rightChild; 113 | delete this->root; 114 | this->root = left; 115 | meld(this->root, right); 116 | --(this->treeSize); 117 | } 118 | 119 | //初始化 120 | template 121 | void maxHblt::initialize(T *theElements, int theSize) { 122 | //用每个元素值建立出只有一个结点的左高树并放入队列中 123 | //然后依次弹出队列的前两个进行合并,并重新放入队列,直到队列中只有一个树 124 | arrayQueue Q(theSize); 125 | this->erase(); //清空原来的树 126 | 127 | //初始化左高树的森林并放入队列 128 | for (int i = 1; i <= theSize; ++i) 129 | Q.push(new pairType(std::make_pair(1, theElements[i]))); 130 | 131 | //从队列中重复的弹出两棵树进行合并,然后把新的树重新放入 132 | while (Q.size() > 1) { 133 | pairType *b = Q.front(); 134 | Q.pop(); 135 | pairType *c = Q.front(); 136 | Q.pop(); 137 | meld(b, c); 138 | Q.push(b); 139 | } 140 | 141 | if (theSize > 0) this->root = Q.front(); 142 | this->treeSize = theSize; 143 | } 144 | 145 | #endif //DSACPP_MAXHBLT_H 146 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/maxHeap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/4. 3 | // 4 | 5 | #ifndef DSACPP_MAXHEAP_H 6 | #define DSACPP_MAXHEAP_H 7 | 8 | #include 9 | #include 10 | #include "maxPriorityQueue.h" 11 | #include "../Chap5_ArrayList/changeLength1D.h" 12 | #include "../MyExceptions.h" 13 | 14 | //大根堆 15 | template 16 | class maxHeap : public maxPriorityQueue { 17 | public: 18 | //构造和析构函数 19 | maxHeap(int initialCapacity = 10); 20 | ~maxHeap() { delete[] heap;} 21 | 22 | //判空 23 | bool empty() const { return heapSize == 0;} 24 | 25 | //返回元素个数 26 | int size() const { return heapSize;} 27 | 28 | //对队首元素的引用 29 | const T& top(); 30 | 31 | //删除队首元素 32 | void pop(); 33 | 34 | //添加元素 35 | void push(const T&); 36 | 37 | //初始化 38 | void initialize(T*, int); 39 | 40 | //将heap置为NULL 41 | void deactivateArray() { heap = NULL; arrayLength = heapSize = 0;} 42 | 43 | private: 44 | T *heap; //元素数组,逻辑上的完全二叉树 45 | int arrayLength; //数组容量 46 | int heapSize; //元素个数 47 | }; 48 | 49 | //构造函数 50 | template 51 | maxHeap::maxHeap(int initialCapacity) { 52 | if (initialCapacity < 1) { 53 | ostringstream s; 54 | s << "Initial capacity = " << initialCapacity << " Must be > 0"; 55 | throw illegalParameterValue(s.str()); 56 | } 57 | 58 | arrayLength = initialCapacity + 1; //元素从下标为1的地方开始存放 59 | heap = new T[arrayLength]; 60 | heapSize = 0; 61 | } 62 | 63 | //初始化一个大根堆,theHeap[1:theSize] 64 | template 65 | void maxHeap::initialize(T *theHeap, int theSize) { 66 | //重置heap数组 67 | delete[] heap; 68 | heap = theHeap; 69 | heapSize = theSize; 70 | arrayLength = heapSize + 1; 71 | 72 | //按大根堆的性质进行初始化,从最后一个有子结点的结点开始自下而上的遍历 73 | for (int root = heapSize / 2; root >= 1; --root) { 74 | //维护以root为根的树具有大根堆的性质 75 | T rootElement = heap[root]; 76 | 77 | //为rootElement寻找位置 78 | int child = root * 2; //child的双亲是rootElement的位置 79 | while (child <= heapSize) { 80 | //让child成为两个子结点中较大者的下标 81 | if (child < heapSize && heap[child] < heap[child + 1]) 82 | ++child; 83 | 84 | //需要把theElement换到heap[child / 2] 85 | if (rootElement >= heap[child]) 86 | break; 87 | 88 | //不需要交换 89 | heap[child / 2] = heap[child]; //把孩子上移 90 | child *= 2; //移到下一层 91 | } 92 | heap[child / 2] = rootElement; 93 | } 94 | } 95 | 96 | //对队首元素的引用 97 | template 98 | const T& maxHeap::top() { 99 | if (heapSize == 0) 100 | //堆为空 101 | throw queueEmpty(); 102 | 103 | return heap[1]; 104 | } 105 | 106 | //插入元素 107 | template 108 | void maxHeap::push(const T &theElement) { 109 | //必要时数组长度加倍 110 | if (heapSize == arrayLength - 1) { 111 | changeLength1D(heap, arrayLength, arrayLength * 2); 112 | arrayLength *= 2; 113 | } 114 | 115 | //为theElement寻找位置 116 | //从新的叶子向上移动 117 | int currentNode = ++heapSize; 118 | while (currentNode != 1 && heap[currentNode / 2] < theElement) { 119 | //不能把theElement放在currentNode的位置 120 | heap[currentNode] = heap[currentNode / 2]; //把原来的双亲下移 121 | currentNode /= 2; //currentNode移向双亲 122 | } 123 | 124 | heap[currentNode] = theElement; 125 | } 126 | 127 | //删除最大元素 128 | template 129 | void maxHeap::pop() { 130 | //如果堆为空,抛出异常 131 | if (heapSize == 0) 132 | throw queueEmpty(); 133 | 134 | T lastElement = heap[heapSize--]; 135 | //把最大元素交换到heapSize+1的位置 136 | heap[heapSize + 1] = heap[1]; 137 | 138 | //从根开始,为最后一个元素寻找位置 139 | int currentNode = 1, child = 2; //child是currentNode的孩子结点 140 | while (child <= heapSize) { 141 | //child应该是currentNode的较大的孩子的下标 142 | if (child < heapSize && heap[child] < heap[child + 1]) 143 | ++child; 144 | 145 | //需要把lastElement放在currentNode的位置 146 | if (lastElement >= heap[child]) 147 | break; 148 | 149 | //不需要 150 | heap[currentNode] = heap[child]; //把孩子中的较大者上移,变成双亲 151 | currentNode = child; //移到下一层 152 | child *= 2; 153 | } 154 | heap[currentNode] = lastElement; 155 | } 156 | 157 | #endif //DSACPP_MAXHEAP_H 158 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/maxPriorityQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/4. 3 | // 4 | 5 | #ifndef DSACPP_MAXPRIORITYQUEUE_H 6 | #define DSACPP_MAXPRIORITYQUEUE_H 7 | 8 | //大根堆的抽象类 9 | template 10 | class maxPriorityQueue { 11 | public: 12 | virtual ~maxPriorityQueue() {} 13 | //判断是否为空 14 | virtual bool empty() const = 0; 15 | 16 | //返回队列的元素个数 17 | virtual int size() const = 0; 18 | 19 | //返回优先级最大的元素的引用 20 | virtual const T& top() = 0; 21 | 22 | //删除队首元素 23 | virtual void pop() = 0; 24 | 25 | //插入元素theElement 26 | virtual void push(const T& theElement) = 0; 27 | }; 28 | 29 | #endif //DSACPP_MAXPRIORITYQUEUE_H 30 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/maxWblt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/9. 3 | // 4 | 5 | #ifndef DSACPP_MAXWBLT_H 6 | #define DSACPP_MAXWBLT_H 7 | 8 | #include 9 | #include 10 | #include "../Chap11_BinaryTree/linkedBinaryTree.h" 11 | #include "../MyExceptions.h" 12 | #include "maxPriorityQueue.h" 13 | 14 | //最大重量优先左高树 15 | template 16 | class maxWblt : public maxPriorityQueue, linkedBinaryTree> { 17 | public: 18 | //判断是否为空 19 | bool empty() const { return this->treeSize == 0;} 20 | 21 | //元素个数 22 | int size() const { return this->treeSize;} 23 | 24 | //队首元素的引用 25 | const T& top(); 26 | 27 | //删除队首 28 | void pop(); 29 | 30 | //添加元素 31 | void push(const T& theElement); 32 | 33 | //初始化左高树 34 | void initialize(T *theElements, int theSize); 35 | 36 | //合并另一个棵树 37 | void meld(maxWblt &theWblt); 38 | 39 | typedef binaryTreeNode> pairType; 40 | private: 41 | //合并两棵左高树 42 | void meld(binaryTreeNode> *&, binaryTreeNode> *&); 43 | }; 44 | 45 | //队列最大元素的引用 46 | template 47 | const T& maxWblt::top() { 48 | //如果树为空,则返回异常 49 | if (this->treeSize == 0) 50 | throw queueEmpty(); 51 | 52 | return this->root->element.second; 53 | } 54 | 55 | //私有方法 合并以 x 和 y 为根的左高树,合并后的左高树以 x 为根 56 | template 57 | void maxWblt::meld(binaryTreeNode> *&x, binaryTreeNode> *&y) { 58 | if (y == NULL) //y为空 59 | return; 60 | if (x == NULL) { 61 | //x为空 62 | x = y; 63 | return; 64 | } 65 | 66 | //保证 x 指向根结点较大的树 67 | if (x->element.second < y->element.second) 68 | std::swap(x, y); 69 | 70 | //递归的把 y 合并到 x->rightChild 上 71 | meld(x->rightChild, y); 72 | 73 | //x 的左子树为空,交换两个子树 74 | if (x->leftChild == NULL) { 75 | x->leftChild = x->rightChild; 76 | x->rightChild = NULL; 77 | x->element.first = x->leftChild->element.first + 1; //更新 x 的 w 值 78 | } else { 79 | //保证左子树的 w 值为较大的那个 80 | if (x->leftChild->element.first < x->rightChild->element.first) 81 | std::swap(x->leftChild, x->rightChild); 82 | //更新 w 值 83 | x->element.first = x->leftChild->element.first + x->rightChild->element.first + 1; 84 | } 85 | } 86 | 87 | //公有方法,合并两个最大重量优先的左高树描述的优先队列 88 | template 89 | void maxWblt::meld(maxWblt &theWblt) { 90 | //合并两个对象里面的左高树 91 | meld(this->root, theWblt.root); 92 | this->treeSize += theWblt.treeSize; 93 | //theHblt现在是空的 94 | theWblt.root = NULL; 95 | theWblt.treeSize = 0; 96 | } 97 | 98 | //删除队列的最大元素 99 | template 100 | void maxWblt::pop() { 101 | //如果为空,抛出异常 102 | if (this->treeSize == 0) 103 | throw queueEmpty(); 104 | 105 | //合并root的左右子树并作为新的root 106 | pairType *left = this->root->leftChild, *right = this->root->rightChild; 107 | delete this->root; 108 | this->root = left; 109 | meld(this->root, right); 110 | --(this->treeSize); 111 | } 112 | 113 | //插入元素theElement 114 | template 115 | void maxWblt::push(const T &theElement) { 116 | //建立只有一个结点,并且值是theElement的左高树 117 | pairType *x = new pairType (std::make_pair(1, theElement)); 118 | 119 | //将 x 合并到 root 上 120 | meld(this->root, x); 121 | ++(this->treeSize); 122 | } 123 | 124 | //初始化一棵重量优先左高树 125 | template 126 | void maxWblt::initialize(T *theElements, int theSize) { 127 | //用每个元素值建立出只有一个结点的左高树并放入队列中 128 | //然后依次弹出队列的前两个进行合并,并重新放入队列,直到队列中只有一个树 129 | arrayQueue Q(theSize); 130 | this->erase(); //清空原来的树 131 | 132 | //初始化左高树的森林并放入队列 133 | for (int i = 1; i <= theSize; ++i) 134 | Q.push(new pairType(std::make_pair(1, theElements[i]))); 135 | 136 | //从队列中重复的弹出两棵树进行合并,然后把新的树重新放入 137 | while (Q.size() > 1) { 138 | pairType *b = Q.front(); 139 | Q.pop(); 140 | pairType *c = Q.front(); 141 | Q.pop(); 142 | meld(b, c); 143 | Q.push(b); 144 | } 145 | 146 | if (theSize > 0) this->root = Q.front(); 147 | this->treeSize = theSize; 148 | } 149 | 150 | #endif //DSACPP_MAXWBLT_H 151 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/minHeap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/9. 3 | // 4 | 5 | #ifndef DSACPP_minHeap_H 6 | #define DSACPP_minHeap_H 7 | 8 | #include 9 | #include 10 | #include "maxPriorityQueue.h" 11 | #include "../Chap5_ArrayList/changeLength1D.h" 12 | #include "../MyExceptions.h" 13 | 14 | //大根堆 15 | template 16 | class minHeap : public maxPriorityQueue { 17 | public: 18 | //构造和析构函数 19 | minHeap(int initialCapacity = 10); 20 | ~minHeap() { delete[] heap;} 21 | 22 | //判空 23 | bool empty() const { return heapSize == 0;} 24 | 25 | //返回元素个数 26 | int size() const { return heapSize;} 27 | 28 | //对队首元素的引用 29 | const T& top(); 30 | 31 | //删除队首元素 32 | void pop(); 33 | 34 | //添加元素 35 | void push(const T&); 36 | 37 | //初始化 38 | void initialize(T*, int); 39 | 40 | //将heap置为NULL 41 | void deactivateArray() { heap = NULL; arrayLength = heapSize = 0;} 42 | 43 | private: 44 | T *heap; //元素数组,逻辑上的完全二叉树 45 | int arrayLength; //数组容量 46 | int heapSize; //元素个数 47 | }; 48 | 49 | //构造函数 50 | template 51 | minHeap::minHeap(int initialCapacity) { 52 | if (initialCapacity < 1) { 53 | ostringstream s; 54 | s << "Initial capacity = " << initialCapacity << " Must be > 0"; 55 | throw illegalParameterValue(s.str()); 56 | } 57 | 58 | arrayLength = initialCapacity + 1; //元素从下标为1的地方开始存放 59 | heap = new T[arrayLength]; 60 | heapSize = 0; 61 | } 62 | 63 | //初始化一个大根堆,theHeap[1:theSize] 64 | template 65 | void minHeap::initialize(T *theHeap, int theSize) { 66 | //重置heap数组 67 | delete[] heap; 68 | heap = theHeap; 69 | heapSize = theSize; 70 | arrayLength = heapSize + 1; 71 | 72 | //按大根堆的性质进行初始化,从最后一个有子结点的结点开始自下而上的遍历 73 | for (int root = heapSize / 2; root >= 1; --root) { 74 | //维护以root为根的树具有大根堆的性质 75 | T rootElement = heap[root]; 76 | 77 | //为rootElement寻找位置 78 | int child = root * 2; //child的双亲是rootElement的位置 79 | while (child <= heapSize) { 80 | //让child成为两个子结点中较小者的下标 81 | if (child < heapSize && heap[child] > heap[child + 1]) 82 | ++child; 83 | 84 | //需要把theElement换到heap[child / 2] 85 | if (rootElement <= heap[child]) 86 | break; 87 | 88 | //不需要交换 89 | heap[child / 2] = heap[child]; //把孩子上移 90 | child *= 2; //移到下一层 91 | } 92 | heap[child / 2] = rootElement; 93 | } 94 | } 95 | 96 | //对队首元素的引用 97 | template 98 | const T& minHeap::top() { 99 | if (heapSize == 0) 100 | //堆为空 101 | throw queueEmpty(); 102 | 103 | return heap[1]; 104 | } 105 | 106 | //插入元素 107 | template 108 | void minHeap::push(const T &theElement) { 109 | //必要时数组长度加倍 110 | if (heapSize == arrayLength - 1) { 111 | changeLength1D(heap, arrayLength, arrayLength * 2); 112 | arrayLength *= 2; 113 | } 114 | 115 | //为theElement寻找位置 116 | //从新的叶子向上移动 117 | int currentNode = ++heapSize; 118 | while (currentNode != 1 && heap[currentNode / 2] > theElement) { 119 | //不能把theElement放在currentNode的位置 120 | heap[currentNode] = heap[currentNode / 2]; //把原来的双亲下移 121 | currentNode /= 2; //currentNode移向双亲 122 | } 123 | 124 | heap[currentNode] = theElement; 125 | } 126 | 127 | //删除最大元素 128 | template 129 | void minHeap::pop() { 130 | //如果堆为空,抛出异常 131 | if (heapSize == 0) 132 | throw queueEmpty(); 133 | 134 | T lastElement = heap[heapSize--]; 135 | //把最大元素交换到heapSize+1的位置 136 | heap[heapSize + 1] = heap[1]; 137 | 138 | //从根开始,为最后一个元素寻找位置 139 | int currentNode = 1, child = 2; //child是currentNode的孩子结点 140 | while (child <= heapSize) { 141 | //child应该是currentNode的较小的孩子的下标 142 | if (child < heapSize && heap[child] > heap[child + 1]) 143 | ++child; 144 | 145 | //需要把lastElement放在currentNode的位置 146 | if (lastElement <= heap[child]) 147 | break; 148 | 149 | //不需要 150 | heap[currentNode] = heap[child]; //把孩子中的较大者上移,变成双亲 151 | currentNode = child; //移到下一层 152 | child *= 2; 153 | } 154 | heap[currentNode] = lastElement; 155 | } 156 | 157 | #endif //DSACPP_minHeap_H 158 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/test.txt: -------------------------------------------------------------------------------- 1 | Hooray! It's snowing! It's time to make a snowman.James runs out. 2 | He makes a big pile of snow. He puts a big snowball on top. 3 | He adds a scarf and a hat. He adds an orange for the nose. 4 | He adds coal for the eyes and buttons.In the evening, James opens the door. 5 | What does he see? The snowman is moving! James invites him in. 6 | The snowman has never been inside a house. 7 | He says hello to the cat. He plays with paper towels. 8 | A moment later, the snowman takes James's hand and goes out.They go up, up, up into the air! 9 | They are flying! What a wonderful night!The next morning, James jumps out of bed. 10 | He runs to the door.He wants to thank the snowman. But he's gone. -------------------------------------------------------------------------------- /Chap12_PriorityQueue/test_heapSort.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/5. 3 | // 4 | 5 | #include 6 | #include "heapSort.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | int nums[1000001]; 12 | for (int i = 1; i <= 1000000; ++i) 13 | nums[i] = rand() % 1500000; 14 | chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now(); 15 | 16 | heapSort(nums, 1000000); 17 | chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now(); 18 | chrono::duration time_used = chrono::duration_cast>(t2 - t1)*1000; 19 | 20 | for (int i = 1; i < 1000000; ++i) 21 | if (nums[i] > nums[i+1]) { 22 | cout << "error" << endl; 23 | break; 24 | } 25 | 26 | cout << "heapSort use: " << time_used.count() << " ms" << endl; 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Chap12_PriorityQueue/test_huffmanTree.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/9. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "../Chap11_BinaryTree/binaryTreeNode.h" 9 | #include "../Chap8_Stack/arrayStack.h" 10 | #include "huffmanTree.h" 11 | 12 | using namespace std; 13 | 14 | void enCode(binaryTreeNode *tree, int *weights, string str) { 15 | if (tree == NULL) return; 16 | 17 | //是叶子结点 18 | if (tree->leftChild == NULL && tree->rightChild == NULL) { 19 | cout << "element: " << char('a' + tree->element - 1) << ", weight: " << weights[tree->element] << ", code: " << str 20 | << endl; 21 | return; 22 | } 23 | //递归左右子树 24 | if (tree->leftChild != NULL) 25 | enCode(tree->leftChild, weights, str + "0"); 26 | if (tree->rightChild != NULL) 27 | enCode(tree->rightChild, weights, str + "1"); 28 | } 29 | 30 | int main() { 31 | //加载test.txt文件里的英文小短文,统计里面每个字母的频率 32 | ifstream in("../../Chap12_PriorityQueue/test.txt"); 33 | int weights[27] = {0}; 34 | string str; 35 | if (in) { 36 | while (in >> str) { 37 | for (char c : str) { 38 | if (c > 'a' && c < 'z') 39 | ++weights[c - 'a' + 1]; 40 | else if (c > 'A' && c < 'Z') 41 | ++weights[c - 'A' + 1]; 42 | str = ""; 43 | } 44 | } 45 | in.close(); 46 | } else { 47 | cout << "Failed to open TXT file!" << endl; 48 | return 0; 49 | } 50 | 51 | //构建huffman树 52 | binaryTreeNode *tree = huffmanTree(weights, 26); 53 | 54 | //根据huffman树对字符进行编码 55 | enCode(tree, weights, ""); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chap12_PriorityQueue/test_maxHblt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/6. 3 | // 4 | 5 | #include 6 | #include "maxHblt.h" 7 | 8 | int main() { 9 | maxHblt h; 10 | for (int i = 1; i <= 10000; ++i) 11 | h.push(rand() % 15000); 12 | 13 | for (int i = 1; i <= 10000; ++i) { 14 | cout << h.top() << endl; 15 | h.pop(); 16 | } 17 | return 0; 18 | } -------------------------------------------------------------------------------- /Chap12_PriorityQueue/test_maxHeap.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/4. 3 | // 4 | 5 | #include 6 | #include "maxHeap.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | maxHeap h; 12 | for (int i = 1; i <= 100000; ++i) 13 | h.push(rand() % 150000); 14 | 15 | for (int i = 1; i <= 100000; ++i) { 16 | cout << h.top() << endl; 17 | h.pop(); 18 | } 19 | return 0; 20 | } -------------------------------------------------------------------------------- /Chap12_PriorityQueue/test_maxWblt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/9. 3 | // 4 | 5 | #include 6 | #include "maxWblt.h" 7 | 8 | int main() { 9 | maxWblt h; 10 | int nums[10001]; 11 | for (int i = 1; i <= 10000; ++i) 12 | nums[i] = rand() % 15000; 13 | h.initialize(nums, 10000); 14 | for (int i = 1; i <= 10000; ++i) { 15 | cout << h.top() << endl; 16 | h.pop(); 17 | } 18 | return 0; 19 | } -------------------------------------------------------------------------------- /Chap13_TouranmentTree/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | add_executable(Chap13_completeWinnerTree winnerTree.h completeWinnerTree.h ../MyExceptions.h test_completeWinnerTree.cpp) -------------------------------------------------------------------------------- /Chap13_TouranmentTree/completeWinnerTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/10. 3 | // 4 | 5 | #ifndef DSACPP_COMPLETEWINNERTREE_H 6 | #define DSACPP_COMPLETEWINNERTREE_H 7 | 8 | #include "winnerTree.h" 9 | #include "../MyExceptions.h" 10 | 11 | //使用完全二叉树的数组来实现赢者树 12 | template 13 | class completeWinnerTree : public winnerTree { 14 | public: 15 | //构造和析构函数 16 | completeWinnerTree(T *thePlayer, int theNumberOfPlayers); 17 | ~completeWinnerTree() {delete[] tree;} 18 | 19 | //初始化一棵赢者树 20 | void initialize(T *thePlayer, int theNumberOfPlayers); 21 | 22 | //返回最终赢者的索引 23 | int winner() const { return tree[1];} 24 | 25 | //在参赛者thePLayer的分数变化之后重赛 26 | void rePlay(int thePLayer); 27 | 28 | private: 29 | T *player; //选手(外部结点)数组 30 | int *tree; //赢者(内部结点)数组,tree[i]是player的一个索引 31 | int numberOfPlayers; //选手的数量 32 | int lowExt; //最底层外部结点的个数 33 | int offset; //offset = 2 * s - 1,其中 s 是最底层最左端的内部结点的编号,所以offset = 2 ^ log(n - 1) - 1 34 | 35 | //让 theLeft 和 theRight 进行在tree[p]的比赛,并尝试在晋级之后继续比赛 36 | void play(int p, int theLeft, int theRight); 37 | 38 | //判断选手thePLayer的值改变之后,在matchNode产生的新赢者是否需要继续比赛 39 | bool needNext(int matchNode, int theLeft, int theRight, int thePLayer); 40 | }; 41 | 42 | //构造函数 43 | template 44 | completeWinnerTree::completeWinnerTree(T *thePlayer, int theNumberOfPlayers) { 45 | tree = NULL; 46 | initialize(thePlayer, theNumberOfPlayers); 47 | } 48 | 49 | //初始化赢者树 50 | template 51 | void completeWinnerTree::initialize(T *thePlayer, int theNumberOfPlayers) { 52 | //最少要有两名选手 53 | if (theNumberOfPlayers < 2) 54 | throw illegalParameterValue("must have at least 2 players"); 55 | 56 | //重置私有数据成员 57 | player = thePlayer; 58 | numberOfPlayers = theNumberOfPlayers; 59 | delete[] tree; 60 | tree = new int [numberOfPlayers]; 61 | 62 | //计算最底层最左端的内部结点编号 s = 2 ^ log(n - 1) 63 | //s 是最接近 n-1 的2的幂 64 | int s = 1; 65 | while (s * 2 <= numberOfPlayers - 1) s *= 2; 66 | 67 | //lowExt = 2 * (n - s), offset = 2 * s - 1 68 | lowExt = 2 * (numberOfPlayers - s); 69 | offset = 2 * s - 1; 70 | 71 | //从右孩子开始,进行他所参加的比赛 72 | //让最底层的外部结点进行比赛 73 | int i; 74 | for (i = 2; i <= lowExt; i += 2) 75 | play((i + offset) / 2, i - 1, i); 76 | 77 | //有一个多余的外部结点需要和tree[n-1]进行比赛 78 | if (numberOfPlayers % 2 == 1) { 79 | play(numberOfPlayers / 2, tree[numberOfPlayers - 1], lowExt + 1); 80 | i = lowExt + 3; //i定位到下一个需要比赛的外部结点 81 | } 82 | else 83 | i = lowExt + 2; //i定位到下一个需要比赛的外部结点 84 | 85 | //剩余的其他选手进行比赛 86 | while (i <= numberOfPlayers) { 87 | play((i - lowExt + numberOfPlayers - 1) / 2, i - 1, i); 88 | i += 2; 89 | } 90 | } 91 | 92 | //让 theLeft 和 theRight 进行在tree[p]的比赛,并尝试在晋级之后继续比赛 93 | template 94 | void completeWinnerTree::play(int p, int theLeft, int theRight) { 95 | //先进行theLeft和theRight的比赛 96 | //x <= y,当且仅当选手 x 赢了选手 y 97 | tree[p] = player[theLeft] <= player[theRight] ? theLeft : theRight; 98 | 99 | //如果p是右孩子,那么它还要进行一场比赛 100 | while (p % 2 == 1 && p > 1) { 101 | tree[p / 2] = player[tree[p-1]] <= player[tree[p]] ? tree[p-1] : tree[p]; 102 | p /= 2; //移动上一层 103 | } 104 | } 105 | 106 | //在参赛者thePLayer的分数变化之后重赛 107 | template 108 | void completeWinnerTree::rePlay(int thePLayer) { 109 | //如果thePLayer不是正规的选手编号,则抛出异常 110 | if (thePLayer <= 0 || thePLayer > numberOfPlayers) 111 | throw illegalIndex("Player index is illegal"); 112 | 113 | //确定thePLayer第一场比赛的对手和比赛结点 114 | int matchNode, theLeft, theRight; 115 | if (thePLayer <= lowExt) { 116 | //thePLayer是最底层的外部结点 117 | matchNode = (thePLayer + offset) / 2; 118 | theLeft = 2 * matchNode - offset; //theLeft是matchNode的左孩子 119 | theRight = theLeft + 1; 120 | } else { 121 | //thePLayer是倒数第二层的外部结点 122 | matchNode = (thePLayer - lowExt + numberOfPlayers - 1) / 2; 123 | 124 | if (matchNode * 2 == numberOfPlayers - 1) { 125 | //thePLayer需要和tree[n-1]比赛 126 | theLeft = tree[numberOfPlayers - 1]; 127 | theRight = thePLayer; 128 | } else { 129 | //thePLayer直接和外部结点比赛 130 | theLeft = matchNode * 2 - numberOfPlayers + 1 + lowExt; 131 | theRight = theLeft + 1; 132 | } 133 | } 134 | 135 | //开始重新比赛,当一场比赛的赢者和之前相同并且之前的赢者不是thePLayer时,就不用继续了 136 | if (!needNext(matchNode, theLeft, theRight, thePLayer)) 137 | return; 138 | 139 | //如果matchNode是最后一个内部结点并且 n 是奇数,那么需要和多余的一个外部结点比赛一次 140 | if (matchNode == numberOfPlayers - 1 && numberOfPlayers % 2 == 1) { 141 | matchNode /= 2; 142 | if (!needNext(matchNode, tree[numberOfPlayers - 1], lowExt + 1, thePLayer)) 143 | return; 144 | } 145 | 146 | //向上重新进行必要的比赛 147 | matchNode /= 2; 148 | while (matchNode >= 1) { 149 | if (!needNext(matchNode, tree[matchNode * 2], tree[matchNode * 2 + 1], thePLayer)) 150 | break; 151 | matchNode /= 2; 152 | } 153 | } 154 | 155 | //判断选手thePLayer的值改变之后,在matchNode产生的新赢者是否需要继续比赛 156 | template 157 | bool completeWinnerTree::needNext(int matchNode, int theLeft, int theRight, int thePLayer) { 158 | int newWinner = player[theLeft] <= player[theRight] ? theLeft : theRight; 159 | if (newWinner == tree[matchNode] && tree[matchNode] != thePLayer) 160 | return false; 161 | else { 162 | tree[matchNode] = newWinner; 163 | return true; 164 | } 165 | } 166 | 167 | #endif //DSACPP_COMPLETEWINNERTREE_H 168 | -------------------------------------------------------------------------------- /Chap13_TouranmentTree/test_completeWinnerTree.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/11. 3 | // 4 | 5 | #include 6 | #include "completeWinnerTree.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | int nums[10001]; 12 | for (int i = 1; i <= 10000; ++i) 13 | nums[i] = rand() % 10000; 14 | 15 | completeWinnerTree winnerTree(nums, 10000); 16 | for (int i = 1; i <= 10000; ++i) { 17 | int winner = winnerTree.winner(); 18 | cout << nums[winner] << endl; 19 | nums[winner] = INT_MAX; 20 | winnerTree.rePlay(winner); 21 | } 22 | return 0; 23 | } -------------------------------------------------------------------------------- /Chap13_TouranmentTree/winnerTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/10. 3 | // 4 | 5 | #ifndef DSACPP_WINNERTREE_H 6 | #define DSACPP_WINNERTREE_H 7 | 8 | //赢者树的抽象类 9 | template 10 | class winnerTree { 11 | public: 12 | virtual ~winnerTree() {} 13 | 14 | //用数组thePlayer[1:numberOfPlayers]生成赢者树 15 | virtual void initialize(T *thePlayer, int theNumberOfPlayers) = 0; 16 | 17 | //返回最终赢者的索引 18 | virtual int winner() const = 0; 19 | 20 | //在参赛者thePLayer的分数变化之后重赛 21 | virtual void rePlay(int thePLayer) = 0; 22 | }; 23 | 24 | 25 | #endif //DSACPP_WINNERTREE_H 26 | -------------------------------------------------------------------------------- /Chap14_SearchTree/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | include_directories(../Chap8_Stack) 6 | include_directories(../Chap9_Queue) 7 | include_directories(../Chap10_SkipAndHashTable) 8 | include_directories(../Chap11_BinaryTree) 9 | 10 | add_executable(Chap14_binarySearchTree ../Chap10_SkipAndHashTable/dictionary.h bsTree.h binarySearchTree.h test_binarySearchTree.cpp) 11 | 12 | add_executable(Chap14_indexBinarySearchTree indexBSTree.h indexBinarySearchTree.h test_indexBinarySearchTree.cpp) -------------------------------------------------------------------------------- /Chap14_SearchTree/binarySearchTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/12. 3 | // 4 | 5 | #ifndef DSACPP_BINARYSEARCHTREE_H 6 | #define DSACPP_BINARYSEARCHTREE_H 7 | 8 | #include 9 | #include 10 | #include "bsTree.h" 11 | #include "linkedBinaryTree.h" 12 | 13 | //二叉搜索树 14 | template 15 | class binarySearchTree : public bsTree, public linkedBinaryTree> { 16 | public: 17 | //判断是否为空 18 | bool empty() const { return this->treeSize == 0;} 19 | 20 | //返回数对的个数 21 | int size() const { return this->treeSize;} 22 | 23 | //按关键字查找 24 | std::pair* find(const K&) const; 25 | 26 | //删除匹配的数对 27 | void erase(const K&); 28 | 29 | //在字典中插入一个数对 30 | void insert(const std::pair&); 31 | 32 | //按升序输出 33 | void ascend(); 34 | 35 | typedef std::pair pairType; 36 | }; 37 | 38 | //按升序输出 39 | template 40 | void binarySearchTree::ascend() { 41 | this->inOrder([] (binaryTreeNode* t) { 42 | if (t != NULL) std::cout << t->element.first << " " << t->element.second << std::endl; 43 | }); 44 | } 45 | 46 | //按关键字查找 47 | template 48 | std::pair* binarySearchTree::find(const K &theKey) const { 49 | //从根结点开始,寻找关键字等于theKey的元素 50 | binaryTreeNode *p = this->root; 51 | while (p != NULL) { 52 | //检查p->element的关键字 53 | if (theKey == p->element.first) //找到匹配的元素 54 | return &p->element; 55 | else if (theKey < p->element.first) //迭代进入左子树 56 | p = p->leftChild; 57 | else //迭代进入左子树 58 | p = p->rightChild; 59 | } 60 | 61 | //没有匹配的数对 62 | return NULL; 63 | } 64 | 65 | //插入数对 66 | template 67 | void binarySearchTree::insert(const std::pair &thePair) { 68 | //寻找合适的插入位置,和这个位置的父结点 69 | binaryTreeNode *p = this->root, *pp = NULL; 70 | while (p != NULL) { 71 | pp = p; //保护下一层的父结点 72 | if (thePair.first == p->element.first) { 73 | //覆盖旧的值 74 | p->element.second = thePair.second; 75 | return; 76 | } 77 | //p 进入对应的孩子结点继续寻找 78 | else if (thePair.first < p->element.first) 79 | p = p->leftChild; 80 | else 81 | p = p->rightChild; 82 | } 83 | 84 | //需要新插入一个结点 85 | binaryTreeNode *newNode = new binaryTreeNode (thePair); 86 | if (this->root == NULL) //插入空树 87 | this->root = newNode; 88 | else { 89 | if (thePair.first < pp->element.first) 90 | pp->leftChild = newNode; 91 | else 92 | pp->rightChild = newNode; 93 | } 94 | 95 | ++(this->treeSize); 96 | } 97 | 98 | //删除数对 99 | template 100 | void binarySearchTree::erase(const K &theKey) { 101 | //寻找关键字和它的父结点 102 | binaryTreeNode *p = this->root, *pp = NULL; 103 | while (p != NULL && theKey != p->element.first) { 104 | pp = p; //保护下一层的父结点 105 | if (theKey < p->element.first) 106 | p = p->leftChild; 107 | else 108 | p = p->rightChild; 109 | } 110 | 111 | //关键字theKey不存在 112 | if (p == NULL) return; 113 | 114 | //p的两个孩子都存在 115 | if (p->leftChild != NULL && p->rightChild != NULL) { 116 | //寻找p的直接前驱,即p的左子树的最右端结点 117 | binaryTreeNode *s = p->leftChild, *ps = p; //ps是s的父结 118 | while (s->rightChild != NULL) { 119 | ps = s; 120 | s = s->rightChild; 121 | } 122 | 123 | //用s的元素值来新建一个替换p的结点 124 | binaryTreeNode *q = new binaryTreeNode (s->element, p->leftChild, p->rightChild); 125 | //用q来替换p的位置 126 | if (pp == NULL) this->root = q; 127 | else if (p == pp->leftChild) 128 | pp->leftChild = q; 129 | else 130 | pp->rightChild = q; 131 | 132 | //s就是p的左孩子 133 | if (ps == p) 134 | pp = q; 135 | else 136 | pp = ps; //用来后面把s的左孩子变成ps的右孩子 137 | delete p; 138 | p = s; //用来后面把s的左孩子变成ps的右孩子 139 | } 140 | 141 | //p最多只有一个孩子 142 | //用c保存孩子指针 143 | binaryTreeNode *c; 144 | if (p->leftChild != NULL) 145 | c = p->leftChild; 146 | else 147 | c = p->rightChild; 148 | 149 | //删除p 150 | if (p == this->root) 151 | this->root = c; 152 | else { 153 | if (p == pp->leftChild) 154 | pp->leftChild = c; 155 | else 156 | pp->rightChild = c; 157 | } 158 | delete p; 159 | --(this->treeSize); 160 | } 161 | 162 | #endif //DSACPP_BINARYSEARCHTREE_H 163 | -------------------------------------------------------------------------------- /Chap14_SearchTree/bsTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/12. 3 | // 4 | 5 | #ifndef DSACPP_BSTREE_H 6 | #define DSACPP_BSTREE_H 7 | 8 | #include "../Chap10_SkipAndHashTable/dictionary.h" 9 | 10 | //二叉搜索树的抽象类 11 | template 12 | class bsTree : public dictionary { 13 | public: 14 | //按关键字升序输出 15 | virtual void ascend() = 0; 16 | }; 17 | 18 | 19 | #endif //DSACPP_BSTREE_H 20 | -------------------------------------------------------------------------------- /Chap14_SearchTree/indexBSTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/12. 3 | // 4 | 5 | #ifndef DSACPP_INDEXBSTREE_H 6 | #define DSACPP_INDEXBSTREE_H 7 | 8 | #include 9 | #include "bsTree.h" 10 | 11 | //索引二叉搜索树的抽象类 12 | template 13 | class indexBSTree : public bsTree { 14 | public: 15 | //根据给定的索引,返回对应数对的指针 16 | virtual std::pair* get(int) const = 0; 17 | 18 | //删除给定索引对应的数对 19 | virtual void eraseIndex(int) = 0; 20 | }; 21 | 22 | #endif //DSACPP_INDEXBSTREE_H 23 | -------------------------------------------------------------------------------- /Chap14_SearchTree/indexBinarySearchTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/13. 3 | // 4 | 5 | #ifndef DSACPP_INDEXBINARYSEARCHTREE_H 6 | #define DSACPP_INDEXBINARYSEARCHTREE_H 7 | 8 | #include 9 | #include "arrayStack.h" 10 | #include "linkedBinaryTree.h" 11 | #include "indexBSTree.h" 12 | 13 | //索引二叉搜索树的结点的数值域 14 | template 15 | struct indexElement { 16 | int leftSize; 17 | std::pair element; 18 | 19 | indexElement() : leftSize(0) {} 20 | indexElement(const std::pair &thePair) : leftSize(0), element(thePair) {} 21 | }; 22 | 23 | //索引二叉搜索树 24 | template 25 | class indexBinarySearchTree : public indexBSTree, public linkedBinaryTree> { 26 | public: 27 | //判断是否为空 28 | bool empty() const { return this->treeSize == 0;} 29 | 30 | //返回数对的个数 31 | int size() const { return this->treeSize;} 32 | 33 | //按关键字查找 34 | std::pair* find(const K&) const; 35 | 36 | //删除匹配的数对 37 | void erase(const K&); 38 | 39 | //在字典中插入一个数对 40 | void insert(const std::pair&); 41 | 42 | //按升序输出 43 | void ascend(); 44 | 45 | //根据给定的索引,返回对应数对的指针 46 | virtual std::pair* get(int) const; 47 | 48 | //删除给定索引对应的数对 49 | virtual void eraseIndex(int); 50 | }; 51 | 52 | //按升序输出 53 | template 54 | void indexBinarySearchTree::ascend() { 55 | this->inOrder([] (binaryTreeNode>* t) { 56 | if (t != NULL) 57 | std::cout << t->element.leftSize << " " << t->element.element.first << " " << t->element.element.second << std::endl; 58 | }); 59 | } 60 | 61 | //按关键字查找 62 | template 63 | std::pair* indexBinarySearchTree::find(const K &theKey) const { 64 | //从根结点开始,寻找关键字等于theKey的元素 65 | binaryTreeNode> *p = this->root; 66 | while (p != NULL) { 67 | //检查p->element的关键字 68 | if (theKey == p->element.element.first) //找到匹配的元素 69 | return &p->element.element; 70 | else if (theKey < p->element.element.first) //迭代进入左子树 71 | p = p->leftChild; 72 | else //迭代进入左子树 73 | p = p->rightChild; 74 | } 75 | 76 | //没有匹配的数对 77 | return NULL; 78 | } 79 | 80 | //按索引查找 81 | template 82 | std::pair* indexBinarySearchTree::get(int theIndex) const { 83 | //如果索引无效 84 | if (theIndex < 0 || theIndex >= this->treeSize) 85 | throw illegalIndex("index must be >= 0 and < treeSize"); 86 | 87 | //从根结点开始,寻找索引等于theIndex的元素 88 | binaryTreeNode> *p = this->root; 89 | while (p != NULL) { 90 | //检查p->element的索引 91 | if (theIndex == p->element.leftSize) //找到匹配的元素 92 | return &p->element.element; 93 | else if (theIndex < p->element.leftSize) //迭代进入左子树,索引不变 94 | p = p->leftChild; 95 | else { //迭代进入右子树,索引改变 96 | theIndex -= (p->element.leftSize + 1); 97 | p = p->rightChild; 98 | } 99 | } 100 | 101 | //没有匹配的数对 102 | return NULL; 103 | } 104 | 105 | //插入数对 106 | template 107 | void indexBinarySearchTree::insert(const pair &thePair) { 108 | //寻找合适的插入位置,和这个位置的父结点 109 | binaryTreeNode> *p = this->root; 110 | arrayStack> *> stack; //保存搜索路径上经过的结点 111 | while (p != NULL) { 112 | stack.push(p); 113 | if (thePair.first == p->element.element.first) { //覆盖旧的值 114 | p->element.element.second = thePair.second; 115 | return; 116 | } else if (thePair.first < p->element.element.first) 117 | p = p->leftChild; 118 | else 119 | p = p->rightChild; 120 | } 121 | //需要新插入一个结点 122 | binaryTreeNode> *newNode = new binaryTreeNode> (thePair); 123 | if (this->root == NULL) //插入空树 124 | this->root = newNode; 125 | else { 126 | p = stack.top(); stack.pop(); 127 | if (thePair.first < p->element.element.first) { 128 | p->leftChild = newNode; 129 | p->element.leftSize += 1; 130 | } else 131 | p->rightChild = newNode; 132 | } 133 | //自底向上更新结点的leftSize 134 | binaryTreeNode> *pp; 135 | while (!stack.empty()) { 136 | pp = stack.top(); stack.pop(); 137 | if (p == pp->leftChild) 138 | pp->element.leftSize += 1; 139 | p = pp; 140 | } 141 | ++(this->treeSize); 142 | } 143 | 144 | //按关键字删除索引二叉搜索树的数对 145 | template 146 | void indexBinarySearchTree::erase(const K &theKey) { 147 | //寻找关键字对应的结点 148 | binaryTreeNode> *p = this->root, *pp = NULL; 149 | arrayStack> *> stack; //保存搜索路径上经过的结点 150 | while (p != NULL && theKey != p->element.element.first) { 151 | pp = p; 152 | stack.push(p); 153 | if (theKey < p->element.element.first) 154 | p = p->leftChild; 155 | else 156 | p = p->rightChild; 157 | } 158 | //关键字theKey不存在 159 | if (p == NULL) return; 160 | //把栈里结点的leftSize更新 161 | binaryTreeNode> *deleteA = NULL, *deleteB = p; 162 | while (!stack.empty()) { 163 | deleteA = stack.top(); stack.pop(); 164 | if (deleteB == deleteA->leftChild) 165 | deleteA->element.leftSize -= 1; 166 | deleteB = deleteA; 167 | } 168 | //p的两个孩子都存在 169 | if (p->leftChild != NULL && p->rightChild != NULL) { 170 | //寻找p的直接前驱,即p的左子树的最右端结点 171 | binaryTreeNode> *s = p->leftChild, *ps = p; //ps是s的父结 172 | while (s->rightChild != NULL) { 173 | ps = s; 174 | s = s->rightChild; 175 | } 176 | //用s的元素值来新建一个替换p的结点 177 | binaryTreeNode> *q = new binaryTreeNode> (s->element, p->leftChild, p->rightChild); 178 | q->element.leftSize = p->element.leftSize - 1; //s移到了p的位置上,所以leftSize - 1 179 | if (pp == NULL) this->root = q; //删除的是根结点 180 | else if (p == pp->leftChild) 181 | pp->leftChild = q; 182 | else 183 | pp->rightChild = q; 184 | //s就是p的左孩子 185 | if (ps == p) 186 | pp = q; 187 | else 188 | pp = ps; //用来后面把s的左孩子变成ps的右孩子 189 | delete p; 190 | p = s; //用来后面把s的左孩子变成ps的右孩子 191 | } 192 | //p最多只有一个孩子 193 | binaryTreeNode> *c; //用c保存孩子指针 194 | if (p->leftChild != NULL) 195 | c = p->leftChild; 196 | else 197 | c = p->rightChild; 198 | //删除p 199 | if (p == this->root) 200 | this->root = c; 201 | else { 202 | if (p == pp->leftChild) 203 | pp->leftChild = c; 204 | else 205 | pp->rightChild = c; 206 | } 207 | delete p; 208 | --(this->treeSize); 209 | } 210 | 211 | //按索引删除索引二叉搜索树的数对 212 | template 213 | void indexBinarySearchTree::eraseIndex(int theIndex) { 214 | //寻找关键字对应的结点 215 | binaryTreeNode> *p = this->root, *pp = NULL; 216 | arrayStack> *> stack; //保存搜索路径上经过的结点 217 | while (p != NULL && theIndex != p->element.leftSize) { 218 | pp = p; 219 | stack.push(p); 220 | if (theIndex < p->element.leftSize) 221 | p = p->leftChild; 222 | else { 223 | theIndex -= (p->element.leftSize + 1); 224 | p = p->rightChild; 225 | } 226 | } 227 | //关键字theKey不存在 228 | if (p == NULL) return; 229 | 230 | //把栈里结点的leftSize更新 231 | binaryTreeNode> *deleteA = NULL, *deleteB = p; 232 | while (!stack.empty()) { 233 | deleteA = stack.top(); stack.pop(); 234 | if (deleteB == deleteA->leftChild) 235 | deleteA->element.leftSize -= 1; 236 | deleteB = deleteA; 237 | } 238 | //p的两个孩子都存在 239 | if (p->leftChild != NULL && p->rightChild != NULL) { 240 | //寻找p的直接前驱,即p的左子树的最右端结点 241 | binaryTreeNode> *s = p->leftChild, *ps = p; //ps是s的父结 242 | while (s->rightChild != NULL) { 243 | ps = s; 244 | s = s->rightChild; 245 | } 246 | 247 | //用s的元素值来新建一个替换p的结点 248 | binaryTreeNode> *q = new binaryTreeNode> (s->element, p->leftChild, p->rightChild); 249 | q->element.leftSize = p->element.leftSize - 1; //s移到了p的位置上,所以leftSize - 1 250 | if (pp == NULL) this->root = q; //删除的是根结点 251 | else if (p == pp->leftChild) 252 | pp->leftChild = q; 253 | else 254 | pp->rightChild = q; 255 | 256 | //s就是p的左孩子 257 | if (ps == p) 258 | pp = q; 259 | else 260 | pp = ps; //用来后面把s的左孩子变成ps的右孩子 261 | delete p; 262 | p = s; //用来后面把s的左孩子变成ps的右孩子 263 | } 264 | 265 | //p最多只有一个孩子 266 | //用c保存孩子指针 267 | binaryTreeNode> *c; 268 | if (p->leftChild != NULL) 269 | c = p->leftChild; 270 | else 271 | c = p->rightChild; 272 | 273 | //删除p 274 | if (p == this->root) 275 | this->root = c; 276 | else { 277 | if (p == pp->leftChild) 278 | pp->leftChild = c; 279 | else 280 | pp->rightChild = c; 281 | } 282 | delete p; 283 | --(this->treeSize); 284 | } 285 | 286 | #endif //DSACPP_INDEXBINARYSEARCHTREE_H 287 | -------------------------------------------------------------------------------- /Chap14_SearchTree/test_binarySearchTree.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/12. 3 | // 4 | 5 | #include 6 | #include "skipList.h" 7 | #include "binarySearchTree.h" 8 | 9 | using namespace std; 10 | 11 | int main() { 12 | //做一个跳表和二叉搜索树的性能测试 13 | int keys[10000]; //保存关键字的数组 14 | skipList skip(20000); 15 | binarySearchTree bsTree; 16 | for (int i = 0; i < 10000; ++i) { 17 | int key = rand() % 20000; 18 | keys[i] = key; 19 | } 20 | 21 | chrono::high_resolution_clock::time_point t1, t2; 22 | chrono::duration time_used; 23 | //开始插入测试 24 | t1 = chrono::high_resolution_clock::now(); 25 | for (int i = 0; i < 10000; ++i) { 26 | skip.insert(make_pair(keys[i], 1)); 27 | } 28 | t2 = chrono::high_resolution_clock::now(); 29 | time_used = chrono::duration_cast>(t2 - t1)*1000; 30 | cout << "Insert 10000 keywords into skip: " << time_used.count() << " ms" << endl; 31 | cout << "skip.size(): " << skip.size() << endl; 32 | 33 | t1 = chrono::high_resolution_clock::now(); 34 | for (int i = 0; i < 10000; ++i) { 35 | bsTree.insert(make_pair(keys[i], 1)); 36 | } 37 | t2 = chrono::high_resolution_clock::now(); 38 | time_used = chrono::duration_cast>(t2 - t1)*1000; 39 | cout << "Insert 10000 keywords into bsTree: " << time_used.count() << " ms" << endl; 40 | cout << "bsTree.size(): " << bsTree.size() << endl << "bsTree.height(): " << bsTree.height() << endl << endl; 41 | 42 | //开始测试查找的性能 43 | t1 = chrono::high_resolution_clock::now(); 44 | for (int i = 0; i < 10000; ++i) { 45 | skip.find(keys[i]); 46 | } 47 | t2 = chrono::high_resolution_clock::now(); 48 | time_used = chrono::duration_cast>(t2 - t1)*1000; 49 | cout << "find 10000 keywords into skip: " << time_used.count() << " ms" << endl; 50 | 51 | t1 = chrono::high_resolution_clock::now(); 52 | for (int i = 0; i < 10000; ++i) { 53 | bsTree.find(keys[i]); 54 | } 55 | t2 = chrono::high_resolution_clock::now(); 56 | time_used = chrono::duration_cast>(t2 - t1)*1000; 57 | cout << "find 10000 keywords into bsTree: " << time_used.count() << " ms" << endl << endl; 58 | 59 | //开始测试删除的性能 60 | t1 = chrono::high_resolution_clock::now(); 61 | for (int i = 0; i < 10000; ++i) { 62 | skip.erase(keys[i]); 63 | } 64 | t2 = chrono::high_resolution_clock::now(); 65 | time_used = chrono::duration_cast>(t2 - t1)*1000; 66 | cout << "erase 10000 keywords into skip: " << time_used.count() << " ms" << endl; 67 | 68 | t1 = chrono::high_resolution_clock::now(); 69 | for (int i = 0; i < 10000; ++i) { 70 | bsTree.erase(keys[i]); 71 | } 72 | t2 = chrono::high_resolution_clock::now(); 73 | time_used = chrono::duration_cast>(t2 - t1)*1000; 74 | cout << "erase 10000 keywords into bsTree: " << time_used.count() << " ms" << endl; 75 | 76 | return 0; 77 | } -------------------------------------------------------------------------------- /Chap14_SearchTree/test_indexBinarySearchTree.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/12/13. 3 | // 4 | 5 | #include 6 | #include "indexBinarySearchTree.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | indexBinarySearchTree indexTree; 12 | for (int i = 0; i < 20; ++i) { 13 | int num = rand() % 30; 14 | indexTree.insert({num, 1}); 15 | cout << num << " "; 16 | } 17 | cout << endl; 18 | indexTree.erase(19); 19 | indexTree.erase(23); 20 | indexTree.erase(7); 21 | indexTree.eraseIndex(5); 22 | indexTree.ascend(); 23 | return 0; 24 | } -------------------------------------------------------------------------------- /Chap5_ArrayList/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | add_executable(Chap5_arrayList test_arrayList.cpp ../MyExceptions.h linearList.h changeLength1D.h arrayList.h) 6 | 7 | add_executable(Chap5_vectorList linearList.h vectorList.h test_vectorList.cpp ../MyExceptions.h) -------------------------------------------------------------------------------- /Chap5_ArrayList/arrayList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-09-04. 3 | // 4 | 5 | #ifndef DSACPP_ARRAYLIST_H 6 | #define DSACPP_ARRAYLIST_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "linearList.h" 13 | #include "changeLength1D.h" 14 | #include "../MyExceptions.h" 15 | 16 | template 17 | class arrayList : public linearList{ 18 | public: 19 | //构造函数,拷贝构造函数和析构函数 20 | arrayList(int initialCapacity = 10); 21 | arrayList(const arrayList&); 22 | ~arrayList() {delete [] element;}; 23 | 24 | //ADT方法 25 | bool empty() const {return listSize == 0;}; 26 | int size() const {return listSize;}; 27 | T& get(int theIndex) const; 28 | int indexOf(const T& theElement) const; 29 | void erase(int theIndex); 30 | void insert(int theIndex, const T& theElement); 31 | void output(ostream& out) const; 32 | 33 | //其他方法 34 | //给出数组当前的长度 35 | int capacity() const {return arrayLength;}; 36 | 37 | //返回指定元素最后出现时的索引 38 | int lastIndex(const T& theElement) const; 39 | 40 | //尾插入 41 | void push_back(const T& theElement); 42 | 43 | //尾弹出 44 | void pop_back(); 45 | 46 | //设置大小 47 | void setSize(int theSize); 48 | 49 | //改变数组的容量为当前容量和theCapacity的较大者 50 | void reserve(int theCapacity); 51 | 52 | //用元素theElement替换索引为theIndex的元素 53 | void set(int theIndex, const T& theElement); 54 | 55 | //删除指定范围内的所有元素 56 | void removeRange(int beginIndex, int endIndex); 57 | 58 | //翻转数组 59 | void reverse(); 60 | 61 | //交换两个数组 62 | void swap(arrayList& theList); 63 | 64 | //清空数组 65 | void clear(); 66 | 67 | // 判断两个数组是否相等 68 | bool isEqual(const arrayList& theList) const; 69 | 70 | //判断当前数组是否小于theList数组 71 | bool isLess(const arrayList& theList) const; 72 | 73 | // 判断当前数组是否大于theList数组 74 | bool isBigger(const arrayList& theList) const; 75 | 76 | //设置表的大小,用在第7章的稀疏矩阵中 77 | void reSet(int theSize); 78 | 79 | //重载[]运算符 80 | T& operator[](int theIndex) { 81 | //返回数组在索引theIndex上的引用 82 | 83 | //检查索引是否有效 84 | checkIndex(theIndex); 85 | return element[theIndex]; 86 | } 87 | 88 | protected: 89 | //若索引theIndex无效,则抛出异常 90 | void checkIndex(int theIndex) const; 91 | 92 | T* element; //存储线性表元素的一维数组 93 | int arrayLength; //一维数组的容量 94 | int listSize; //线性表的元素个数 95 | public: 96 | // 内部类, 迭代器,可以随机访问 97 | class iterator{ 98 | public: 99 | typedef random_access_iterator_tag iterator_category; // 随机访问迭代器 100 | typedef T value_type; //迭代器指向的数据类型 101 | typedef ptrdiff_t difference_type; // 标准库里一种与机器相关的数据类型,常用来表示两个指针相减的结果 102 | typedef T* pointer; //指针 103 | typedef T& reference; //引用 104 | 105 | // 构造函数 106 | iterator(T* thePosition = 0) {position = thePosition;} 107 | 108 | // 解引用操作符,只是调用成员,不会改变值,所以是 const 109 | T& operator*() const {return *position;} 110 | T* operator->() const {return &*position;} 111 | 112 | // 迭代器的值增加 113 | iterator& operator++() {++position; return *this;} // 前置 114 | iterator operator++(int){ // 后置 115 | iterator old = *this; 116 | ++position; 117 | return old; 118 | } 119 | iterator operator+(int n){ 120 | // +运算符, 实现随机访问 121 | iterator old = *this; 122 | old.position += n; 123 | return old; 124 | } 125 | iterator& operator+=(int n){position += n; return *this;} 126 | 127 | // 迭代器减少 128 | iterator& operator--() {--position; return *this;} // 前置 129 | iterator operator--(int){ // 后置 130 | iterator old = *this; 131 | --position; 132 | return old; 133 | } 134 | iterator operator-(int n){ 135 | // -运算符,实现随机访问 136 | iterator old = *this; 137 | old.position -= n; 138 | return old; 139 | } 140 | iterator& operator-=(int n){position -= n; return *this;} 141 | 142 | // 计算指针之间距离的差值 143 | int operator-(const iterator& theIterator) const{ return position - theIterator.position;} 144 | 145 | //测试是否相等 146 | bool operator!=(const iterator right) const {return position != right.position;} 147 | bool operator==(const iterator right) const {return position == right.position;} 148 | bool operator<(const iterator right) const {return position < right.position;} 149 | bool operator<=(const iterator right) const {return position <= right.position;} 150 | bool operator>(const iterator right) const {return position > right.position;} 151 | bool operator>=(const iterator right) const {return position >= right.position;} 152 | protected: 153 | T* position; //指向表元素的指针 154 | }; 155 | 156 | // 返回首元素和尾元素下一个位置的迭代器 157 | iterator begin() {return iterator(element);} 158 | iterator end() {return iterator(element + listSize);} 159 | }; 160 | 161 | template 162 | arrayList::arrayList(int initialCapacity) { 163 | //构造函数 164 | if(initialCapacity < 1){ 165 | ostringstream s; 166 | s << "Initial capacity = " << initialCapacity << "Must be > 0"; 167 | throw illegalParameterValue(s.str()); 168 | } 169 | arrayLength = initialCapacity; 170 | element = new T[arrayLength]; 171 | listSize = 0; 172 | } 173 | 174 | template 175 | arrayList::arrayList(const arrayList& theList) { 176 | //拷贝构造函数 177 | arrayLength = theList.arrayLength; 178 | listSize = theList.listSize; 179 | element = new T[arrayLength]; 180 | copy(theList.element, theList.element + listSize, element); 181 | } 182 | 183 | template 184 | void arrayList::checkIndex(int theIndex) const { 185 | //确定索引theIndex在0 和 listSize - 1之间 186 | if(theIndex < 0 || theIndex >= listSize){ 187 | ostringstream s; 188 | s << "index = " << theIndex << "size = " << listSize; 189 | throw illegalParameterValue(s.str()); 190 | } 191 | } 192 | 193 | template 194 | T& arrayList::get(int theIndex) const { 195 | //返回索引为theIndex的元素 196 | //若此元素不存在,则抛出异常 197 | checkIndex(theIndex); 198 | return element[theIndex]; 199 | } 200 | 201 | template 202 | int arrayList::indexOf(const T &theElement) const { 203 | //返回元素theElement第一次出现时的索引 204 | //若元素不存在,则返回 -1 205 | 206 | //查找元素theElement 207 | int theIndex = (int) (find(element, element + listSize, theElement) - element); 208 | 209 | //确定是否找到 210 | if(theIndex == listSize) 211 | //没有找到 212 | return -1; 213 | else 214 | return theIndex; 215 | } 216 | 217 | //返回指定元素最后出现时的索引 218 | template 219 | int arrayList::lastIndex(const T &theElement) const { 220 | //返回元素theElement最后一次出现时的索引 221 | //若元素不存在,则返回 -1 222 | 223 | //查找元素theElement 224 | int i; 225 | for(i = listSize - 1; i >=0; --i){ 226 | if(element[i] == theElement) 227 | return i; 228 | } 229 | //没有找到 230 | if(i < 0) 231 | return -1; 232 | } 233 | 234 | template 235 | void arrayList::erase(int theIndex) { 236 | // 删除索引theIndex上的元素 237 | //如果元素不存在,则抛出异常 238 | checkIndex(theIndex); 239 | 240 | // 索引有效,则把索引大于theIndex的元素都向前移动 241 | copy(element + theIndex + 1, element + listSize, element + theIndex); 242 | 243 | //调用析构函数 244 | element[--listSize].~T(); 245 | } 246 | 247 | template 248 | void arrayList::insert(int theIndex, const T &theElement) { 249 | // 在索引 theIndex 的位置上插入元素 theElement 250 | 251 | if(theIndex < 0 || theIndex > listSize){ 252 | //无效的索引 253 | ostringstream s; 254 | s << "Index " << theIndex << " size = " << listSize; 255 | throw illegalParameterValue(s.str()); 256 | } 257 | 258 | //有效的索引,确定数组是否已满 259 | if(listSize == arrayLength){ 260 | //数组空间已满。数组长度倍增 261 | changeLength1D(element, arrayLength, 2 * arrayLength); 262 | arrayLength *= 2; 263 | } 264 | 265 | //把索引 theIndex 之后的元素向右移动一个位置 266 | copy_backward(element + theIndex, element + listSize, element + listSize + 1); 267 | 268 | element[theIndex] = theElement; 269 | ++listSize; 270 | } 271 | 272 | template 273 | void arrayList::output(ostream &out) const { 274 | //把线性表插入到输出流 275 | copy(element, element + listSize, ostream_iterator(cout, " ")); 276 | } 277 | 278 | //重载 << 279 | template 280 | ostream& operator<<(ostream& out, const arrayList& x){ 281 | x.output(out); 282 | return out; 283 | } 284 | 285 | //尾插法 286 | template 287 | void arrayList::push_back(const T &theElement) { 288 | //有效的索引,确定数组是否已满 289 | if(listSize == arrayLength){ 290 | //数组空间已满。数组长度倍增 291 | changeLength1D(element, arrayLength, 2 * arrayLength); 292 | arrayLength *= 2; 293 | } 294 | element[listSize++] = theElement; 295 | } 296 | 297 | //尾弹出 298 | template 299 | void arrayList::pop_back() { 300 | element[--listSize].~T(); 301 | } 302 | 303 | //设置数组大小 304 | template 305 | void arrayList::setSize(int theSize) { 306 | //如果数组的初始大小小于等于指定的值,则不增加元素 307 | //如果数组的初始大小大于指定的值,则删除多余元素 308 | if(theSize < 0){ 309 | ostringstream s; 310 | s << "Set size = " << theSize << "Must be >= 0"; 311 | throw illegalParameterValue(s.str()); 312 | } 313 | if(listSize > theSize){ 314 | while(listSize > theSize) 315 | element[--listSize].~T(); 316 | } 317 | } 318 | 319 | //改变数组的容量为当前容量和theCapacity的较大者 320 | template 321 | void arrayList::reserve(int theCapacity) { 322 | if(theCapacity > arrayLength){ 323 | changeLength1D(element, arrayLength, theCapacity); 324 | arrayLength = theCapacity; 325 | } 326 | } 327 | 328 | //用元素theElement替换索引为theIndex的元素 329 | template 330 | void arrayList::set(int theIndex, const T& theElement) { 331 | //超出索引,则抛出异常 332 | checkIndex(theIndex); 333 | element[theIndex] = theElement; 334 | } 335 | 336 | //删除指定范围内的所有元素 337 | template 338 | void arrayList::removeRange(int beginIndex, int endIndex) { 339 | //确定索引是否有效 340 | if(beginIndex < 0 || endIndex >= listSize){ 341 | //无效的索引 342 | ostringstream s; 343 | s << "Index from" << beginIndex << " to " << endIndex << " size = " << listSize; 344 | throw illegalParameterValue(s.str()); 345 | } 346 | copy(element + endIndex + 1, element + listSize, element + beginIndex); 347 | setSize(listSize - (endIndex - beginIndex + 1)); 348 | } 349 | 350 | //翻转数组 351 | template 352 | void arrayList::reverse() { 353 | int i = 0, j = listSize - 1; 354 | while(i < j){ 355 | if(element[i] != element[j]){ 356 | //swap(element[i], element[j]); 357 | T temp = element[i]; 358 | element[i] = element[j]; 359 | element[j] = temp; 360 | } 361 | ++i; 362 | --j; 363 | } 364 | } 365 | 366 | //交换两个数组 367 | template 368 | void arrayList::swap(arrayList &theList) { 369 | //如果当前数组的容量更大,则将theList扩容 370 | if(arrayLength > theList.arrayLength) 371 | theList.reserve(arrayLength); 372 | else 373 | reserve(theList.arrayLength); 374 | for(int i = 0; i < max(listSize, theList.listSize); ++i){ 375 | T temp = element[i]; 376 | element[i] = theList.element[i]; 377 | theList.element[i] = temp; 378 | } 379 | int temp = listSize; 380 | listSize = theList.listSize; 381 | theList.listSize = temp; 382 | } 383 | 384 | //清空数组 385 | template 386 | void arrayList::clear() { 387 | while(listSize > 0) 388 | element[--listSize].~T(); 389 | } 390 | 391 | // 判断是否相等 392 | template 393 | bool arrayList::isEqual(const arrayList &theList) const{ 394 | //返回是否和theList相等 395 | //数组长度相同,且每个元素都相等 396 | if(this == &theList) 397 | return true; 398 | if(listSize != theList.listSize) 399 | return false; 400 | int i = 0, j = 0; 401 | while(i < listSize && j < theList.listSize){ 402 | if(element[i] != theList.element[j]) 403 | return false; 404 | ++i; 405 | ++j; 406 | } 407 | return true; 408 | } 409 | 410 | // 重载==运算符 411 | template 412 | bool operator==(const arrayList& theLeftList, const arrayList& theRightList){ 413 | return theLeftList.isEqual(theRightList); 414 | } 415 | 416 | // 重载 != 运算符 417 | template 418 | bool operator!=(const arrayList& theLeftList, const arrayList& theRightList){ 419 | return !theLeftList.isEqual(theRightList); 420 | } 421 | 422 | // 判断当前数组是否小于theList 423 | template 424 | bool arrayList::isLess(const arrayList &theList) const{ 425 | if(this == &theList) 426 | return false; 427 | //字典序的小于 428 | int i = 0, j = 0; 429 | while(i < listSize && j < theList.listSize){ 430 | if(element[i] == theList.element[j]){ 431 | ++i; 432 | ++j; 433 | }else if(element[i] < theList.element[j]){ 434 | return true; 435 | }else 436 | return false; 437 | } 438 | if(i < j) 439 | return true; 440 | else 441 | return false; 442 | } 443 | 444 | // 重载<运算符 445 | template 446 | bool operator<(const arrayList& theLeftList, const arrayList& theRightList){ 447 | return theLeftList.isLess(theRightList); 448 | } 449 | 450 | // 重载 >= 运算符 451 | template 452 | bool operator>=(const arrayList& theLeftList, const arrayList& theRightList){ 453 | return !theLeftList.isLess(theRightList); 454 | } 455 | 456 | // 判断当前数组是否大于theList数组 457 | template 458 | bool arrayList::isBigger(const arrayList &theList) const{ 459 | if(this == &theList) 460 | return false; 461 | //字典序的小于 462 | int i = 0, j = 0; 463 | while(i < listSize && j < theList.listSize){ 464 | if(element[i] == theList.element[j]){ 465 | ++i; 466 | ++j; 467 | }else if(element[i] > theList.element[j]){ 468 | return true; 469 | }else 470 | return false; 471 | } 472 | if(i > j) 473 | return true; 474 | else 475 | return false; 476 | } 477 | 478 | // 重载 > 运算符 479 | template 480 | bool operator>(const arrayList& theLeftList, const arrayList& theRightList){ 481 | return theLeftList.isBigger(theRightList); 482 | } 483 | 484 | //重载 <= 运算符 485 | template 486 | bool operator<=(const arrayList& theLeftList, const arrayList& theRightList){ 487 | return !theLeftList.isBigger(theRightList); 488 | } 489 | 490 | //设置表的大小,用在第7章的稀疏矩阵中 491 | template 492 | void arrayList::reSet(int theSize) { 493 | if (theSize < 0) { 494 | ostringstream s; 495 | s << "Requested size = " << theSize << " Must be >= 0"; 496 | throw illegalParameterValue(s.str()); 497 | } 498 | if (theSize > arrayLength) { 499 | delete element; 500 | element = new T[theSize]; 501 | arrayLength = listSize; 502 | } 503 | listSize = theSize; 504 | } 505 | 506 | #endif //DSACPP_ARRAYLIST_H 507 | -------------------------------------------------------------------------------- /Chap5_ArrayList/changeLength1D.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-09-04. 3 | // 4 | 5 | #ifndef DSACPP_CHANGELENGTH1D_H 6 | #define DSACPP_CHANGELENGTH1D_H 7 | 8 | #include "../MyExceptions.h" 9 | 10 | template 11 | void changeLength1D(T*& a, int oldLength, int newLength){ 12 | if(newLength < 0) 13 | throw illegalParameterValue("new length must be >= 0"); 14 | T* temp = new T[newLength]; // 新数组 15 | int number = min(oldLength, newLength); // 需要复制的元素个数 16 | copy(a, a + number, temp); 17 | delete [] a; // 释放老数组的内存空间 18 | a = temp; 19 | } 20 | 21 | #endif //DSACPP_CHANGELENGTH1D_H 22 | -------------------------------------------------------------------------------- /Chap5_ArrayList/linearList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-09-04. 3 | // 4 | 5 | #ifndef DSACPP_LINEARLIST_H 6 | #define DSACPP_LINEARLIST_H 7 | 8 | #include 9 | 10 | //一个线性表的抽象类 11 | template 12 | class linearList{ 13 | public: 14 | virtual ~linearList() {}; 15 | 16 | //返回true,当线性表为空 17 | virtual bool empty() const = 0; 18 | 19 | //返回线性表的元素个数 20 | virtual int size() const = 0; 21 | 22 | //返回索引为theIndex的元素 23 | virtual T& get(int theIndex) const = 0; 24 | 25 | //返回元素theElement第一次出现时的索引 26 | virtual int indexOf(const T& theElement) const = 0; 27 | 28 | //删除索引为theindex的元素 29 | virtual void erase(int theIndex) = 0; 30 | 31 | //把theElement插入线性表中索引为theIndex的位置上 32 | virtual void insert(int theIndex, const T& theElement) = 0; 33 | 34 | //把线性表插入输出流out 35 | virtual void output(std::ostream& out) const = 0; 36 | }; 37 | 38 | #endif //DSACPP_LINEARLIST_H 39 | -------------------------------------------------------------------------------- /Chap5_ArrayList/test_arrayList.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "arrayList.h" 4 | int main() { 5 | arrayList nums1(10); 6 | arrayList nums2(15); 7 | for(int i = 0; i < 10; ++i) { 8 | nums1.insert(i, i + 1); 9 | nums2.insert(i, i + 1); 10 | } 11 | cout << "nums1.get(3): " << nums1.get(3) << endl; 12 | cout << "nums1: " << nums1 << endl; 13 | //nums1[5] = 0; 14 | cout << "nums1[5]: " << nums1[5] << endl; 15 | cout << "nums1 == nums2: " << (nums1 == nums2) << endl; 16 | cout << "nums1 != nums2: " << (nums1 != nums2) << endl; 17 | cout << "nums1 < nums2: " << (nums1 < nums2) << endl; 18 | nums1.pop_back(); 19 | cout << "执行nums1.pop_back()之后的结果: " << nums1 << endl; 20 | cout << "nums1 != nums2: " << (nums1 != nums2) << endl; 21 | nums1.push_back(11); 22 | cout << "执行nums1.push_back(11)之后的结果: " << nums1 << endl; 23 | cout << "nums1 > nums2: " << (nums1 > nums2) << endl; 24 | 25 | nums1.setSize(20); 26 | cout << "size:" << nums1.size() << endl; 27 | nums1.set(6, 8); 28 | cout << nums1 << endl; 29 | 30 | nums1.removeRange(2, 5); 31 | cout << nums1 << endl; 32 | 33 | nums2.reverse(); 34 | cout << nums2 << endl; 35 | 36 | sort(nums2.begin(), nums2.end()); 37 | cout << nums2 << endl; 38 | 39 | reverse(nums2.begin(), nums2.end()); 40 | cout << nums2 << endl; 41 | 42 | nums1.swap(nums2); 43 | cout << nums1 << endl << nums2 << endl; 44 | nums1.clear(); 45 | nums2.clear(); 46 | 47 | return 0; 48 | } -------------------------------------------------------------------------------- /Chap5_ArrayList/test_vectorList.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-10-09. 3 | // 4 | 5 | #include 6 | #include "vectorList.h" 7 | 8 | int main(){ 9 | vectorList nums1; 10 | for(int i = 0; i < 31; ++i) 11 | nums1.push_back(i); 12 | cout << nums1.get(20) << endl; 13 | nums1[30] = 0; 14 | cout << nums1 << endl; 15 | nums1.pop_back(); 16 | for(auto it = nums1.begin(); it < nums1.end(); ++it){ 17 | cout << *it << " "; 18 | } 19 | vectorList nums2; 20 | nums2.push_back(1); 21 | nums1.swap(nums2); 22 | cout << nums1 << endl << nums2 << endl; 23 | return 0; 24 | } -------------------------------------------------------------------------------- /Chap5_ArrayList/vectorList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-09-30. 3 | // 4 | 5 | #ifndef DSACPP_VECTORLIST_H 6 | #define DSACPP_VECTORLIST_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "../MyExceptions.h" 13 | #include "linearList.h" 14 | 15 | /** 16 | * 利用vector实现的基于数组的线性表 17 | */ 18 | template 19 | class vectorList : public linearList{ 20 | public: 21 | // 构造函数,复制函数和析构函数 22 | vectorList(int initialCapacity = 10); 23 | vectorList(const vectorList&); 24 | ~vectorList() {delete element;} 25 | 26 | // ADT方法 27 | bool empty() const {return element->empty();} 28 | int size() const {return (int)element->size();} 29 | T& get(int theIndex) const; 30 | int indexOf(const T& theElement) const; 31 | void erase(int theIndex); 32 | void insert(int theIndex, const T& theElement); 33 | void output(ostream& out) const; 34 | 35 | // 增加的方法 36 | int capacity() const {return (int) element->capacity();} 37 | 38 | //随机访问迭代器 39 | typedef typename vector::iterator iterator; 40 | iterator begin() {return element->begin();} 41 | iterator end() {return element->end();} 42 | 43 | // 尾插入 44 | void push_back(const T& theElement) {element->push_back(theElement);} 45 | 46 | // 尾弹出 47 | void pop_back() {element->pop_back();} 48 | 49 | // 翻转数组 50 | void reverse() {element->reserve();} 51 | 52 | //交换两个数组 53 | void swap(vectorList& theList) {element->swap(*theList.element);} 54 | 55 | // 清空数组 56 | void clear() {element->clear();} 57 | 58 | // 重载[]运算符 59 | T& operator[](int theIndex){ 60 | checkIndex(theIndex); 61 | return *(element->begin() + theIndex); 62 | } 63 | 64 | protected: 65 | void checkIndex(int theIndex) const; 66 | vector* element; // 存储线性表元素的向量 67 | }; 68 | 69 | // 构造函数 70 | template 71 | vectorList::vectorList(int initialCapacity) { 72 | if(initialCapacity < 1){ 73 | ostringstream s; 74 | s << "Initial capacity = " << initialCapacity << "Must be > 0"; 75 | throw illegalParameterValue(s.str()); 76 | } 77 | 78 | //创建容量为0的空向量 79 | element = new vector; 80 | // 容量从0增加到initialCapacity 81 | element->reserve(initialCapacity); 82 | } 83 | 84 | // 复制构造函数 85 | template 86 | vectorList::vectorList(const vectorList& theList) { 87 | element = new vector(*theList.element); 88 | } 89 | 90 | // 检查索引是否有效 91 | template 92 | void vectorList::checkIndex(int theIndex) const { 93 | if(theIndex < 0 || theIndex >= element->size()){ 94 | ostringstream s; 95 | s << "index = " << theIndex << "size = " << element->size(); 96 | throw illegalParameterValue(s.str()); 97 | } 98 | } 99 | 100 | // 取得索引theIndex上的元素值 101 | template 102 | T& vectorList::get(int theIndex) const { 103 | checkIndex(theIndex); 104 | return *(element->begin() + theIndex); 105 | } 106 | 107 | // 取得元素theElement的索引 108 | template 109 | int vectorList::indexOf(const T &theElement) const { 110 | // 不存在则返回 -1 111 | 112 | int theIndex = (int)(find(element->begin(), element->end(), theElement) - element->begin()); 113 | // 尾部的下个位置 114 | if(theIndex == element->size()) 115 | return -1; 116 | return theIndex; 117 | } 118 | 119 | // 删除索引为theIndex的元素 120 | template 121 | void vectorList::erase(int theIndex) { 122 | checkIndex(theIndex); 123 | element->erase(element->begin() + theIndex); 124 | } 125 | 126 | // 在索引为theIndex处插入元素theElement 127 | template 128 | void vectorList::insert(int theIndex, const T &theElement) { 129 | if(theIndex < 0 || theIndex > element->size()){ 130 | ostringstream s; 131 | s << "index = " << theIndex << " szie = " << element->size(); 132 | throw illegalIndex(s.str()); 133 | } 134 | element->insert(element->begin() + theIndex, theElement); 135 | } 136 | 137 | // 把元素插入到输出流 138 | template 139 | void vectorList::output(ostream &out) const { 140 | //把元素拷贝到输出流 141 | copy(element->begin(), element->end(), ostream_iterator(out, " ")); 142 | } 143 | 144 | // 重载<<运算符 145 | template 146 | ostream& operator<<(ostream& out, const vectorList& theList){ 147 | theList.output(out); 148 | return out; 149 | } 150 | 151 | #endif //DSACPP_VECTORLIST_H 152 | -------------------------------------------------------------------------------- /Chap6_LinkedList/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | include_directories(../Chap5_ArrayList) 6 | 7 | add_executable(Chap6_chain chainNode.h chain.h test_chain.cpp) 8 | 9 | add_executable(Chap6_extendedChain extendedLinearList.h extendedChain.h test_extendedChain.cpp) 10 | 11 | add_executable(Chap6_circularList circularListWithHeader.h test_circularListWithHeader.cpp) 12 | 13 | add_executable(Chap6_doublyList doublyLinkedListWithHeader.h test_doublyLinkedListWithHeader.cpp) -------------------------------------------------------------------------------- /Chap6_LinkedList/chain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-10-11. 3 | // 4 | 5 | #ifndef DSACPP_CHAIN_H 6 | #define DSACPP_CHAIN_H 7 | 8 | #include 9 | #include 10 | #include "../MyExceptions.h" 11 | #include "chainNode.h" 12 | #include "linearList.h" 13 | 14 | template 15 | class chain : public linearList { 16 | public: 17 | //构造函数,复制构造函数和析构函数 18 | chain(int initialCapacity = 10); 19 | chain(const chain&); 20 | ~chain(); 21 | 22 | //ADT方法 23 | bool empty() const {return listSize == 0;} 24 | int size() const {return listSize;} 25 | T& get(int theIndex) const; 26 | int indexOf(const T& theElement) const; 27 | void erase(int theIndex); 28 | void insert(int theIndex, const T& theElement); 29 | void output(ostream& out) const; 30 | 31 | //首元素 32 | T& front(); 33 | 34 | //从首部插入 35 | void push_front(const T& theElement); 36 | 37 | //从首部弹出 38 | void pop_front(); 39 | 40 | //使线性表的大小等于theSize 41 | void setSize(int theSize); 42 | 43 | //将索引为theIndex的元素替换为theElement 44 | void set(int theIndex, const T& theElement); 45 | 46 | //删除指定范围内的元素 47 | void removeRange(int fromIndex, int toIndex); 48 | 49 | //返回元素theElement最后出现的索引 50 | int lastIndexOf(const T& theElement) const; 51 | 52 | //是否和线性表theChain相等 53 | bool isEqual(const chain& theChain) const; 54 | 55 | //是否小于线性表theChain 56 | bool isLess(const chain& theChain) const; 57 | 58 | //交换两个线性表 59 | void swap(chain& theChain); 60 | 61 | //翻转线性表 62 | void reverse(); 63 | 64 | //清表 65 | void clear(); 66 | 67 | //重载[]运算符 68 | T& operator[](int theIndex){ 69 | //如果元素不存在,则抛出异常 70 | checkIndex(theIndex); 71 | 72 | //移向索引为theIndex的结点 73 | chainNode* currentNode = firstNode; 74 | for(int i = 0; i < theIndex; ++i) 75 | currentNode = currentNode->next; 76 | return currentNode->element; 77 | } 78 | 79 | public: 80 | //迭代器类 81 | class iterator{ 82 | public: 83 | typedef forward_iterator_tag iterator_category; //向前迭代器 84 | typedef T value_type; //迭代器指向的数据类型 85 | typedef T* pointer; //指针 86 | typedef T& reference; //引用 87 | 88 | //构造函数 89 | iterator(chainNode* theNode = NULL) {node = theNode;} 90 | 91 | //解引用操作符 92 | T& operator*() const {return node->element;} 93 | T* operator->() const {return &node->element;} 94 | 95 | //迭代器加法操作 96 | iterator& operator++() {node = node->next; return *this;} //前加 97 | iterator operator++(int){ //后加 98 | iterator old = *this; 99 | node = node->next; 100 | return old; 101 | } 102 | 103 | //相等检验 104 | bool operator!=(const iterator right) const {return node != right.node;} 105 | bool operator==(const iterator right) const {return node == right.node;} 106 | 107 | protected: 108 | chainNode* node; //结点指针 109 | }; 110 | 111 | //首元素的迭代器 112 | iterator begin() {return iterator(firstNode);} 113 | //尾元素下一个位置的迭代器 114 | iterator end() {return iterator(NULL);} 115 | 116 | protected: 117 | //如果索引无效,抛出异常 118 | void checkIndex(int theIndex) const; 119 | 120 | chainNode* firstNode; //指向链表第一个结点的指针 121 | int listSize; //线性表的元素个数 122 | }; 123 | 124 | //构造函数 125 | template 126 | chain::chain(int initialCapacity) { 127 | if(initialCapacity < 1){ 128 | ostringstream s; 129 | s << "Initial capacity = " << initialCapacity << "Must be > 0"; 130 | throw illegalParameterValue(s.str()); 131 | } 132 | firstNode = NULL; 133 | listSize = 0; 134 | } 135 | 136 | //复制构造函数 137 | template 138 | chain::chain(const chain &theList) { 139 | listSize = theList.listSize; 140 | if(listSize == 0){ 141 | //链表为空 142 | firstNode = NULL; 143 | return; 144 | } 145 | 146 | //链表非空 147 | chainNode* sourceNode = theList.firstNode; //要复制链表theIndex的结点 148 | firstNode = new chainNode(sourceNode->element); //复制链表theIndex的首元素 149 | sourceNode = sourceNode->next; 150 | chainNode* targetNode = firstNode; //当前链表*this的最后一个结点 151 | 152 | while(sourceNode != NULL){ 153 | targetNode->next = new chainNode(sourceNode->element); 154 | targetNode = targetNode->next; 155 | sourceNode = sourceNode->next; 156 | } 157 | targetNode->next = NULL; //链表结束 158 | } 159 | 160 | //析构函数 161 | template 162 | chain::~chain() { 163 | //删除所有结点 164 | while(firstNode != NULL){ 165 | //删除首结点 166 | chainNode* nextNode = firstNode->next; 167 | delete firstNode; 168 | firstNode = nextNode; 169 | } 170 | } 171 | 172 | //检查索引是否有效 173 | template 174 | void chain::checkIndex(int theIndex) const { 175 | //确定索引theIndex在0 和 listSize - 1之间 176 | if(theIndex < 0 || theIndex >= listSize){ 177 | ostringstream s; 178 | s << "index = " << theIndex << "size = " << listSize; 179 | throw illegalParameterValue(s.str()); 180 | } 181 | } 182 | 183 | //返回索引是theIndex的元素 184 | template 185 | T& chain::get(int theIndex) const { 186 | //如果元素不存在,则抛出异常 187 | checkIndex(theIndex); 188 | 189 | //移向索引为theIndex的结点 190 | chainNode* currentNode = firstNode; 191 | for(int i = 0; i < theIndex; ++i) 192 | currentNode = currentNode->next; 193 | return currentNode->element; 194 | } 195 | 196 | //获取首元素 197 | template 198 | T& chain::front() { 199 | return firstNode->element; 200 | } 201 | 202 | //返回元素theElement首次出现时的索引 203 | template 204 | int chain::indexOf(const T &theElement) const { 205 | //搜索链表寻找元素theElement 206 | chainNode* currentNode = firstNode; 207 | int theIndex = 0; //当前结点的索引 208 | while(currentNode != NULL && currentNode->element != theElement){ 209 | //移向下一个结点 210 | currentNode = currentNode->next; 211 | ++theIndex; 212 | } 213 | 214 | //确定是否找到所需的元素 215 | if(currentNode == NULL) 216 | return -1; 217 | else 218 | return theIndex; 219 | } 220 | 221 | //删除索引为theIndex的元素 222 | template 223 | void chain::erase(int theIndex) { 224 | //如果元素不存在,则抛出异常 225 | checkIndex(theIndex); 226 | 227 | //索引有效,找到要删除的元素结点 228 | chainNode* deleteNode; 229 | if(theIndex == 0){ 230 | //删除链表的首结点 231 | deleteNode = firstNode; 232 | firstNode = firstNode->next; 233 | } else{ 234 | //用p指向要删除结点的前驱结点 235 | chainNode* p = firstNode; 236 | for(int i = 0; i < theIndex - 1; ++i) 237 | p = p->next; 238 | deleteNode = p->next; 239 | p->next = p->next->next; //删除deleteNode指向的结点 240 | } 241 | --listSize; 242 | delete deleteNode; 243 | } 244 | 245 | //在索引为theIndex的位置上插入新元素theElement 246 | template 247 | void chain::insert(int theIndex, const T &theElement) { 248 | //先检查索引是否有效 249 | if(theIndex < 0 || theIndex > listSize){ 250 | //无效索引 251 | ostringstream s; 252 | s << "index = " << theIndex << " size = " << listSize; 253 | throw illegalIndex(s.str()); 254 | } 255 | 256 | if(theIndex == 0) 257 | //在链表头插入 258 | firstNode = new chainNode(theElement, firstNode); 259 | else{ 260 | //寻找新元素的前驱 261 | chainNode* p = firstNode; 262 | for(int i = 0; i < theIndex - 1; ++i) 263 | p = p->next; 264 | 265 | //在p之后插入 266 | p->next = new chainNode(theElement, p->next); 267 | } 268 | ++listSize; 269 | } 270 | 271 | //从首部插入元素 272 | template 273 | void chain::push_front(const T &theElement) { 274 | firstNode = new chainNode(theElement, firstNode); 275 | ++listSize; 276 | } 277 | 278 | //从首部弹出 279 | template 280 | void chain::pop_front() { 281 | chainNode* deleteNode = firstNode; 282 | firstNode = firstNode->next; 283 | delete deleteNode; 284 | --listSize; 285 | } 286 | 287 | //把元素插入到一个输出流 288 | template 289 | void chain::output(ostream &out) const { 290 | for(chainNode* currentNode = firstNode; currentNode != NULL; currentNode = currentNode->next) 291 | out << currentNode->element << " "; 292 | } 293 | 294 | //重载<< 295 | template 296 | ostream& operator<<(ostream& out, const chain& x){ 297 | x.output(out); 298 | return out; 299 | } 300 | 301 | //使线性表的大小等于theSize 302 | template 303 | void chain::setSize(int theSize) { 304 | //如果数组的初始大小小于等于指定的值,则增加NULL元素 305 | //如果数组的初始大小大于指定的值,则删除多余元素 306 | if(theSize < 0){ 307 | ostringstream s; 308 | s << "Set size = " << theSize << "Must be >= 0"; 309 | throw illegalParameterValue(s.str()); 310 | } 311 | if(listSize > theSize){ 312 | //找到索引为theSize的前驱 313 | chainNode* p = firstNode; 314 | for(int i = 0; i < theSize - 1; ++i) 315 | p = p->next; 316 | //删除所有结点 317 | while(p->next != NULL){ 318 | chainNode* currentNode = p->next; 319 | p->next = currentNode->next; 320 | delete currentNode; 321 | } 322 | listSize = theSize; 323 | } 324 | } 325 | 326 | //将索引为theIndex的元素替换为theElement 327 | template 328 | void chain::set(int theIndex, const T &theElement) { 329 | //索引theIndex超出异常,则抛出异常 330 | checkIndex(theIndex); 331 | 332 | //寻找需要被替换的元素 333 | chainNode* currentNode = firstNode; 334 | for(int i = 0; i < theIndex; ++i) 335 | currentNode = currentNode->next; 336 | currentNode->element = theElement; 337 | } 338 | 339 | //删除指定范围的元素 340 | template 341 | void chain::removeRange(int fromIndex, int toIndex) { 342 | //确定索引是否有效 343 | if(fromIndex < 0 || toIndex >= listSize){ 344 | //无效的索引 345 | ostringstream s; 346 | s << "Index from" << fromIndex << " to " << toIndex << " size = " << listSize; 347 | throw illegalParameterValue(s.str()); 348 | } 349 | if(fromIndex == 0){ 350 | for(int i = 0; i <= toIndex; ++i){ 351 | chainNode* p = firstNode; 352 | firstNode = firstNode->next; 353 | delete p; 354 | } 355 | } else{ 356 | //找到开始删除结点的前驱结点 357 | chainNode* p = firstNode; 358 | for(int i = 0; i < fromIndex - 1; ++i) 359 | p = p->next; 360 | int needDeleteNum = (toIndex - fromIndex + 1); 361 | while(needDeleteNum > 0){ 362 | chainNode* currentNode = p->next; 363 | p->next = currentNode->next; 364 | delete currentNode; 365 | --needDeleteNum; 366 | } 367 | } 368 | 369 | listSize -= (toIndex - fromIndex + 1); 370 | } 371 | 372 | //找到元素最后出现的位置 373 | template 374 | int chain::lastIndexOf(const T &theElement) const{ 375 | int theLastIndex = -1; 376 | chainNode* currentNode = firstNode; 377 | for(int i = 0; i < listSize; ++i){ 378 | if(currentNode->element == theElement) 379 | theLastIndex = i; 380 | currentNode = currentNode->next; 381 | } 382 | return theLastIndex; 383 | } 384 | 385 | //判断是否和线性表theChain相等 386 | template 387 | bool chain::isEqual(const chain &theChain) const { 388 | //同一个线性表 389 | if(this == &theChain) 390 | return true; 391 | 392 | //两个线性表的长度不等,肯定不相等 393 | if(listSize != theChain.listSize) 394 | return false; 395 | 396 | //比较每一个元素 397 | chainNode *p = firstNode, *q = theChain.firstNode; 398 | while(p != NULL){ 399 | //遇到不一样的元素就返回false 400 | if(p->element != q->element) 401 | return false; 402 | p = p->next; 403 | q = q->next; 404 | } 405 | 406 | return true; 407 | } 408 | 409 | //重载==运算符 410 | template 411 | bool operator==(const chain& theLeftChain, const chain& theRightChain){ 412 | return theLeftChain.isEqual(theRightChain); 413 | } 414 | 415 | //重载!=运算符 416 | template 417 | bool operator!=(const chain& theLeftChain, const chain& theRightChain){ 418 | return !theLeftChain.isEqual(theRightChain); 419 | } 420 | 421 | //判断是否小于线性表theChain 422 | template 423 | bool chain::isLess(const chain &theChain) const { 424 | //是同一个线性表 425 | if(this == &theChain) 426 | return false; 427 | 428 | //比较每一个元素 429 | chainNode *p = firstNode, *q = theChain.firstNode; 430 | while(p != NULL && q != NULL){ 431 | //当前线性表的元素更小 432 | if(firstNode->element < q->element) 433 | return true; 434 | else if(firstNode->element > q->element) 435 | //当前线性表的元素更大 436 | return false; 437 | p = p->next; 438 | q = q->next; 439 | } 440 | 441 | //当前线性表的长度更小 442 | if(p == NULL && q != NULL) 443 | return true; 444 | else 445 | return false; 446 | } 447 | 448 | //重载<运算符 449 | template 450 | bool operator<(const chain& theLeftChain, const chain& theRightChain){ 451 | return theLeftChain.isLess(theRightChain); 452 | } 453 | 454 | //交换两个线性表 455 | template 456 | void chain::swap(chain &theChain) { 457 | //交换两个指针 458 | chainNode* copyChain = theChain.firstNode; 459 | theChain.firstNode = firstNode; 460 | firstNode = copyChain; 461 | 462 | //交换线性表的长度 463 | int copyListsize = theChain.listSize; 464 | theChain.listSize = listSize; 465 | listSize = copyListsize; 466 | } 467 | 468 | //翻转链表 469 | template 470 | void chain::reverse() { 471 | //最多只有一个结点的情况下不变 472 | if(listSize < 2) return; 473 | 474 | chainNode* currentNode = firstNode->next; 475 | firstNode->next = NULL; 476 | //迭代 477 | while(currentNode != NULL){ 478 | chainNode* nextNode = currentNode->next; 479 | currentNode->next = firstNode; 480 | firstNode = currentNode; 481 | currentNode = nextNode; 482 | } 483 | } 484 | 485 | //清表 486 | template 487 | void chain::clear() { 488 | //删除所有结点 489 | while(firstNode != NULL){ 490 | //删除首结点 491 | chainNode* nextNode = firstNode->next; 492 | delete firstNode; 493 | firstNode = nextNode; 494 | } 495 | listSize = 0; 496 | } 497 | 498 | 499 | #endif //DSACPP_CHAIN_H 500 | -------------------------------------------------------------------------------- /Chap6_LinkedList/chainNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-10-10. 3 | // 4 | 5 | #ifndef DSACPP_CHAINNODE_H 6 | #define DSACPP_CHAINNODE_H 7 | 8 | template 9 | struct chainNode{ 10 | //数据成员 11 | T element; 12 | chainNode *next; 13 | 14 | //构造方法 15 | chainNode() {} 16 | chainNode(const T& element) {this->element = element;} 17 | chainNode(const T& element, chainNode* next) { 18 | this->element = element; 19 | this->next = next; 20 | } 21 | }; 22 | 23 | #endif //DSACPP_CHAINNODE_H 24 | -------------------------------------------------------------------------------- /Chap6_LinkedList/circularListWithHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/17. 3 | // 4 | 5 | #ifndef DSACPP_CIRCULARLISTWITHHEADER__H 6 | #define DSACPP_CIRCULARLISTWITHHEADER__H 7 | 8 | #include 9 | #include 10 | #include "../MyExceptions.h" 11 | #include "extendedLinearList.h" 12 | #include "chainNode.h" 13 | 14 | //带头结点的循环链表 15 | template 16 | class circularListWithHeader : public extendedLinearList { 17 | public: 18 | //构造函数和析构函数 19 | circularListWithHeader(int initialCapacity = 10); 20 | ~circularListWithHeader(); 21 | 22 | //ADT函数 23 | bool empty() const {return listSize == 0;} 24 | int size() const { return listSize;} 25 | T& get(int theIndex) const; 26 | int indexOf(const T& theElement) const; 27 | void erase(int theIndex); 28 | void insert(int theIndex, const T& theElement); 29 | void output(std::ostream& out) const; 30 | void clear(); 31 | void push_back(const T& theElement); 32 | 33 | //设置大小为theSize 34 | void setSize(int theSize); 35 | 36 | //将索引为theIndex的元素值设置为theElement 37 | void set(int theIndex, const T& theElement); 38 | 39 | //首插入 40 | void push_front(const T& theElement); 41 | 42 | //首弹出 43 | void pop_front(); 44 | 45 | //删除索引fromIndex至toIndex之间的元素 46 | void removeRange(int fromIndex, int toIndex); 47 | 48 | //反转链表 49 | void reverse(); 50 | 51 | //交换两个链表 52 | void swap(circularListWithHeader& theList); 53 | 54 | //获取首尾结点 55 | T& front() {return headerNode->next == headerNode ? lastNode->element : headerNode->next->element;} 56 | T& back() { return lastNode->element;} 57 | 58 | //判断*this是否和theList相等 59 | bool isEqual(const circularListWithHeader& theList) const; 60 | 61 | //判断*this是否小于theList 62 | bool isLess(const circularListWithHeader& theList) const; 63 | 64 | //重载[]运算符 65 | T& operator[](int theIndex){ 66 | //如果索引不存在,则抛出异常 67 | checkIndex(theIndex); 68 | 69 | if(theIndex == 0) 70 | return headerNode->next->element; 71 | else if(theIndex == listSize - 1) 72 | return lastNode->element; 73 | else{ 74 | chainNode* currentNode = headerNode->next; 75 | for(int i = 0; i < theIndex; ++i) 76 | currentNode = currentNode->next; 77 | return currentNode->element; 78 | } 79 | } 80 | 81 | public: 82 | //前向迭代器 83 | class iterator{ 84 | public: 85 | typedef forward_iterator_tag iterator_category; //向前迭代器 86 | typedef T value_type; //迭代器指向的数据类型 87 | typedef T* pointer; //指针 88 | typedef T& reference; //引用 89 | 90 | //构造函数 91 | iterator(chainNode* theNode = NULL) {node = theNode;} 92 | 93 | //解引用操作符 94 | T& operator*() const {return node->element;} 95 | T* operator->() const {return &node->element;} 96 | 97 | //迭代器加法操作 98 | iterator& operator++() {node = node->next; return *this;} //前加 99 | iterator operator++(int){ //后加 100 | iterator old = *this; 101 | node = node->next; 102 | return old; 103 | } 104 | 105 | //相等检验 106 | bool operator!=(const iterator right) const {return node != right.node;} 107 | bool operator==(const iterator right) const {return node == right.node;} 108 | 109 | protected: 110 | chainNode* node; //结点指针 111 | }; 112 | 113 | //首元素的迭代器 114 | iterator begin() {return headerNode->next;} 115 | 116 | //尾元素的下一个位置 117 | iterator end() {return lastNode->next;} 118 | 119 | protected: 120 | //检查索引是否有效 121 | void checkIndex(int theIndex) const; 122 | 123 | chainNode* headerNode; //头结点 124 | chainNode* lastNode; //指向尾结点的指针 125 | int listSize; //长度 126 | }; 127 | 128 | //构造函数 129 | template 130 | circularListWithHeader::circularListWithHeader(int initialCapacity) { 131 | if(initialCapacity < 1){ 132 | ostringstream s; 133 | s << "Initial capacity = " << initialCapacity << "Must be > 0"; 134 | throw illegalParameterValue(s.str()); 135 | } 136 | headerNode = new chainNode(); 137 | headerNode->next = headerNode; 138 | listSize = 0; 139 | } 140 | 141 | //析构函数 142 | template 143 | circularListWithHeader::~circularListWithHeader() { 144 | //删除头结点之后的结点 145 | while(headerNode->next != headerNode) { 146 | chainNode* deleteNode = headerNode->next; 147 | headerNode->next = headerNode->next->next; 148 | delete deleteNode; 149 | } 150 | } 151 | 152 | //检查索引是否有效 153 | template 154 | void circularListWithHeader::checkIndex(int theIndex) const { 155 | //确定索引theIndex在0 和 listSize - 1之间 156 | if(theIndex < 0 || theIndex >= listSize){ 157 | std::ostringstream s; 158 | s << "index = " << theIndex << "size = " << listSize; 159 | throw illegalParameterValue(s.str()); 160 | } 161 | } 162 | 163 | //取得索引theIndex上的元素 164 | template 165 | T& circularListWithHeader::get(int theIndex) const { 166 | //如果索引不存在,则抛出异常 167 | checkIndex(theIndex); 168 | 169 | //遍历寻找 170 | chainNode* currentNode = headerNode->next; 171 | for(int i = 0; i < theIndex; ++i) 172 | currentNode = currentNode->next; 173 | return currentNode->element; 174 | } 175 | 176 | //查找元素theElement的索引 177 | template 178 | int circularListWithHeader::indexOf(const T &theElement) const { 179 | //将元素theElement放入头结点 180 | headerNode->element = theElement; 181 | 182 | //在链表中搜索元素theElement 183 | chainNode* currentNode = headerNode->next; 184 | int index = 0; //当前结点的索引 185 | while(currentNode->element != theElement){ 186 | //移到下一个结点 187 | currentNode = currentNode->next; 188 | ++index; 189 | } 190 | 191 | //确定是否找到 192 | if(currentNode == headerNode) 193 | return -1; 194 | else 195 | return index; 196 | } 197 | 198 | //删除索引为theIndex的元素 199 | template 200 | void circularListWithHeader::erase(int theIndex) { 201 | //如果索引不存在,则抛出异常 202 | checkIndex(theIndex); 203 | 204 | //找到需要删除的结点 205 | chainNode* deleteNode; 206 | if(theIndex == 0){ 207 | //删除首结点 208 | deleteNode = headerNode->next; 209 | if(headerNode->next == lastNode) 210 | //只含一个元素 211 | headerNode->next = headerNode; 212 | else 213 | //连接到第二个元素 214 | headerNode->next = headerNode->next->next; 215 | } else if(theIndex == listSize - 1){ 216 | //删除多于一个结点的链表的尾结点 217 | deleteNode = lastNode; 218 | //找到倒数第二个结点 219 | chainNode* p = headerNode; 220 | while(p->next != lastNode) 221 | p = p->next; 222 | lastNode = p; 223 | lastNode->next = headerNode; 224 | } else{ 225 | //删除中间部分 226 | chainNode* p = headerNode; 227 | for(int i = 0; i < theIndex; ++i) 228 | p = p->next; 229 | deleteNode = p->next; 230 | p->next = p->next->next; 231 | } 232 | delete deleteNode; 233 | --listSize; 234 | } 235 | 236 | //把元素theElement插入到索引为theIndex的位置 237 | template 238 | void circularListWithHeader::insert(int theIndex, const T &theElement) { 239 | //先检查索引是否有效 240 | if(theIndex < 0 || theIndex > listSize){ 241 | //无效索引 242 | ostringstream s; 243 | s << "index = " << theIndex << " size = " << listSize; 244 | throw illegalIndex(s.str()); 245 | } 246 | //在首部插入 247 | if(theIndex == 0){ 248 | if(headerNode->next == headerNode) 249 | //空表 250 | headerNode->next = lastNode = new chainNode(theElement, headerNode); 251 | else 252 | //非空 253 | headerNode->next = new chainNode(theElement, headerNode->next); 254 | } else if(theIndex == listSize){ 255 | //非空且在尾部插入 256 | lastNode->next = new chainNode(theElement, headerNode); 257 | lastNode = lastNode->next; 258 | } else{ 259 | //在其他位置插入 260 | //找到需要插入位置的前驱 261 | chainNode* p = headerNode; 262 | for(int i = 0; i < theIndex; ++i) 263 | p = p->next; 264 | p->next = new chainNode(theElement, p->next); 265 | } 266 | ++listSize; 267 | } 268 | 269 | //将链表的元素插入到输出流 270 | template 271 | void circularListWithHeader::output(std::ostream &out) const { 272 | for(chainNode* currentNode = headerNode->next; currentNode != headerNode; currentNode = currentNode->next) 273 | out << currentNode->element << " "; 274 | } 275 | 276 | //重载<<运算符 277 | template 278 | ostream& operator<<(ostream& out, circularListWithHeader& x){ 279 | x.output(out); 280 | return out; 281 | } 282 | 283 | //清表 284 | template 285 | void circularListWithHeader::clear() { 286 | //删除头结点之后的结点 287 | while(headerNode->next != headerNode) { 288 | chainNode* deleteNode = headerNode->next; 289 | headerNode->next = headerNode->next->next; 290 | delete deleteNode; 291 | } 292 | lastNode = NULL; 293 | listSize = 0; 294 | } 295 | 296 | //设置大小为theSize 297 | template 298 | void circularListWithHeader::setSize(int theSize) { 299 | //如果数组的初始大小小于等于指定的值,则不增加元素 300 | //如果数组的初始大小大于指定的值,则删除多余元素 301 | if(theSize < 0){ 302 | ostringstream s; 303 | s << "Set size = " << theSize << "Must be >= 0"; 304 | throw illegalParameterValue(s.str()); 305 | } 306 | if(listSize > theSize){ 307 | //找到索引是theSize-1的结点 308 | chainNode* p = headerNode; 309 | for(int i = 0; i < theSize; ++i) 310 | p = p->next; 311 | //删除p之后的结点 312 | while(p->next != headerNode){ 313 | chainNode* deleteNode = p->next; 314 | p->next = p->next->next; 315 | delete deleteNode; 316 | } 317 | lastNode = p; 318 | listSize = theSize; 319 | } 320 | } 321 | 322 | //将索引为theIndex的元素的值设为theElement 323 | template 324 | void circularListWithHeader::set(int theIndex, const T &theElement) { 325 | //如果索引超出范围,则抛出异常 326 | checkIndex(theIndex); 327 | 328 | chainNode* currentNode = headerNode; 329 | for(int i = 0; i <= theIndex; ++i) 330 | currentNode = currentNode->next; 331 | currentNode->element = theElement; 332 | } 333 | 334 | //尾插入 335 | template 336 | void circularListWithHeader::push_back(const T &theElement) { 337 | if(headerNode->next == headerNode) 338 | //空表 339 | headerNode->next = lastNode = new chainNode(theElement, headerNode); 340 | else{ 341 | //非空 342 | lastNode->next = new chainNode(theElement, headerNode); 343 | lastNode = lastNode->next; 344 | } 345 | ++listSize; 346 | } 347 | 348 | //首插入 349 | template 350 | void circularListWithHeader::push_front(const T &theElement) { 351 | if(headerNode->next == headerNode) 352 | //空表 353 | headerNode->next = lastNode = new chainNode(theElement, headerNode); 354 | else 355 | //非空 356 | headerNode->next = new chainNode(theElement, headerNode->next); 357 | ++listSize; 358 | } 359 | 360 | //首弹出 361 | template 362 | void circularListWithHeader::pop_front() { 363 | //空表 364 | if(headerNode->next == headerNode) 365 | return; 366 | //不空 367 | chainNode* deleteNode = headerNode->next; 368 | if(headerNode->next == lastNode) 369 | //只含一个元素 370 | headerNode->next = headerNode; 371 | else 372 | //连接到第二个元素 373 | headerNode->next = headerNode->next->next; 374 | delete deleteNode; 375 | --listSize; 376 | } 377 | 378 | //删除索引为fromIndex至toIndex之间的元素 379 | template 380 | void circularListWithHeader::removeRange(int fromIndex, int toIndex) { 381 | //确定索引是否有效 382 | if(fromIndex < 0 || toIndex >= listSize){ 383 | //无效的索引 384 | ostringstream s; 385 | s << "Index from" << fromIndex << " to " << toIndex << " size = " << listSize; 386 | throw illegalParameterValue(s.str()); 387 | } 388 | //找到需要删除的起始结点的前驱 389 | chainNode* p = headerNode; 390 | for(int i = 0; i < fromIndex; ++i) 391 | p = p->next; 392 | //开始删除结点 393 | for(int i = fromIndex; i <= toIndex; ++i){ 394 | chainNode* deleteNode = p->next; 395 | p->next = p->next->next; 396 | delete deleteNode; 397 | } 398 | //如果末尾结点也在范围之内 399 | if(toIndex == listSize - 1) 400 | lastNode = p; 401 | listSize -= (toIndex - fromIndex + 1); 402 | } 403 | 404 | //反转链表 405 | template 406 | void circularListWithHeader::reverse() { 407 | //只有最多一个元素的话不用反转 408 | if(listSize < 2) return; 409 | 410 | //先断开循环,再反转 411 | lastNode->next = NULL; 412 | chainNode* p = headerNode->next->next; 413 | lastNode = headerNode->next; 414 | headerNode->next = lastNode; 415 | while(p != NULL){ 416 | chainNode* currentNode = p; 417 | p = p->next; 418 | currentNode->next = headerNode->next; 419 | headerNode->next = currentNode; 420 | } 421 | lastNode->next = headerNode; 422 | } 423 | 424 | //交换两个链表 425 | template 426 | void circularListWithHeader::swap(circularListWithHeader &theList) { 427 | //交换两个头指针 428 | chainNode* copyChain = theList.headerNode; 429 | theList.headerNode = headerNode; 430 | headerNode = copyChain; 431 | //交换两个lastnode结点 432 | copyChain = theList.lastNode; 433 | theList.lastNode = lastNode; 434 | lastNode = copyChain; 435 | //交换线性表的长度 436 | int copyListsize = theList.listSize; 437 | theList.listSize = listSize; 438 | listSize = copyListsize; 439 | } 440 | 441 | //判断*this是否和theList相等 442 | template 443 | bool circularListWithHeader::isEqual(const circularListWithHeader &theList) const { 444 | //同一个链表 445 | if(this == &theList) 446 | return true; 447 | //长度不等的话链表肯定不等 448 | if(listSize != theList.listSize) 449 | return false; 450 | //比较每一个元素 451 | chainNode *p = headerNode->next, *q = theList.headerNode->next; 452 | while(p != headerNode){ 453 | if(p->element != q->element) 454 | return false; 455 | p = p->next; 456 | q = q->next; 457 | } 458 | return true; 459 | } 460 | 461 | //重载==运算符 462 | template 463 | bool operator==(const circularListWithHeader &theLeftList, const circularListWithHeader &theRightList){ 464 | return theLeftList.isEqual(theRightList); 465 | } 466 | 467 | //判断*this是否小于theList 468 | template 469 | bool circularListWithHeader::isLess(const circularListWithHeader &theList) const { 470 | //同一个链表 471 | if(this == &theList) 472 | return false; 473 | 474 | //比较每一个元素 475 | chainNode *p = headerNode->next, *q = theList.headerNode->next; 476 | while(p != headerNode && q != theList.headerNode){ 477 | //*this当前元素更小 478 | if(p->element < q->element) 479 | return true; 480 | //*this当前元素更小 481 | else if(p->element > q->element) 482 | return false; 483 | p = p->next; 484 | q = q->next; 485 | } 486 | //*this的长度更小 487 | if(p == headerNode && p != theList.headerNode) 488 | return true; 489 | else 490 | return false; 491 | } 492 | 493 | //重载<运算符 494 | template 495 | bool operator<(const circularListWithHeader &theLeftList, const circularListWithHeader &theRightList){ 496 | return theLeftList.isLess(theRightList); 497 | } 498 | 499 | #endif //DSACPP_CIRCULARLISTWITHHEADER__H 500 | -------------------------------------------------------------------------------- /Chap6_LinkedList/extendedChain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/14. 3 | // 4 | 5 | #ifndef DSACPP_EXTENDEDCHAIN_H 6 | #define DSACPP_EXTENDEDCHAIN_H 7 | 8 | #include "extendedLinearList.h" 9 | #include "chain.h" 10 | 11 | //派生chain类作为抽象类extendedLinearList的链式描述 12 | template 13 | class extendedChain : public extendedLinearList, public chain{ 14 | public: 15 | //构造函数、复制构造函数和析构函数 16 | extendedChain(int initialCapacity = 10) : chain::chain(initialCapacity) {} 17 | extendedChain(const extendedChain& theList) : chain::chain(theList), lastNode(theList.lastNode) {} 18 | ~extendedChain() {} 19 | 20 | //ADT方法 21 | bool empty() const {return chain::empty();} 22 | int size() const {return chain::size();} 23 | T& get(int theIndex) const {return chain::get(theIndex);} 24 | int indexOf(const T& theElement) const {return chain::indexOf(theElement);} 25 | void output(ostream& out) const {chain::output(out);} 26 | //在后面实现类extenedChain的特殊版本 27 | void erase(int theIndex); 28 | void insert(int theIndex, const T& theElement); 29 | //抽象基类里的纯虚函数 30 | void clear(); 31 | void push_back(const T& theElement); 32 | 33 | //设置大小 34 | void setSize(int theSize); 35 | 36 | //首插入 37 | void push_front(const T& theElement); 38 | 39 | //首弹出 40 | void pop_front(); 41 | 42 | //首元素 43 | T& front() {return chain::firstNode->element;} 44 | 45 | //尾元素 46 | T& back() {return lastNode->element;} 47 | 48 | //删除指定范围的元素 49 | void removeRange(int fromIndex, int toIndex); 50 | 51 | //反转线性表 52 | void reverse(); 53 | 54 | //交换两个线性表 55 | void swap(extendedChain& theList); 56 | 57 | //父类chain中可直接利用的函数 58 | void set(int theIndex, const T& theElement); 59 | int lastIndexOf(const T& theElement) const {return chain::lastIndexOf(theElement);} 60 | 61 | //利用父类chain来实现自己的函数 62 | bool isEqual(const extendedChain& theList) const {return chain::isEqual(theList);} 63 | bool isLess(const extendedChain& theList) const {return chain::isLess(theList);} 64 | 65 | //重载[]运算符 66 | T& operator[](int theIndex) { 67 | //检查索引是否有效 68 | checkIndex(theIndex); 69 | if(theIndex == 0) 70 | return chain::firstNode->element; 71 | else if(theIndex == chain::listSize - 1) 72 | return lastNode->element; 73 | else{ 74 | //移向索引为theIndex的结点 75 | chainNode* currentNode = chain::firstNode; 76 | for(int i = 0; i < theIndex; ++i) 77 | currentNode = currentNode->next; 78 | return currentNode->element; 79 | } 80 | } 81 | 82 | public: 83 | //迭代器类,直接使用父类chain的迭代器 84 | typedef typename chain::iterator iterator; 85 | //首元素的迭代器 86 | iterator begin() {return iterator(chain::firstNode);} 87 | //尾元素下一个位置的迭代器 88 | iterator end() {return iterator(NULL);} 89 | 90 | protected: 91 | void checkIndex(int theIndex) const {chain::checkIndex(theIndex);} 92 | chainNode* lastNode; //尾结点 93 | }; 94 | 95 | //重载<<运算符 96 | template 97 | ostream& operator<<(ostream& out, const extendedChain& theList){ 98 | theList.output(out); 99 | return out; 100 | } 101 | 102 | //重载==运算符 103 | template 104 | bool operator==(const extendedChain& theLeftList, const extendedChain& theRightList){ 105 | return theLeftList.isEqual(theRightList); 106 | } 107 | 108 | //重载<运算符 109 | template 110 | bool operator<(const extendedChain& theLeftList, const extendedChain& theRightList){ 111 | return theLeftList.isLess(theRightList); 112 | } 113 | 114 | //删除索引为theIndex的元素 115 | template 116 | void extendedChain::erase(int theIndex) { 117 | //如果索引不存在,则抛出异常 118 | checkIndex(theIndex); 119 | 120 | //找到需要删除的结点 121 | chainNode* deleteNode; 122 | if(theIndex == 0){ 123 | //删除首结点 124 | deleteNode = chain::firstNode; 125 | chain::firstNode = chain::firstNode->next; 126 | if(chain::listSize == 1) 127 | lastNode = NULL; 128 | } else if(theIndex == chain::listSize - 1){ 129 | //删除最后一个结点 130 | //找到倒数第二个结点 131 | chainNode* p = chain::firstNode; 132 | while(p->next->next != NULL) 133 | p = p->next; 134 | deleteNode = p->next; 135 | lastNode = p; 136 | } else{ 137 | //删除任意结点 138 | chainNode* p = chain::firstNode; 139 | for(int i = 0; i < theIndex - 1; ++i) 140 | p = p->next; 141 | deleteNode = p->next; 142 | p->next = p->next->next; 143 | } 144 | --chain::listSize; 145 | delete deleteNode; 146 | } 147 | 148 | //清表 149 | template 150 | void extendedChain::clear() { 151 | //删除链表的所有结点 152 | while(chain::firstNode != NULL){ 153 | chainNode* nextNode = chain::firstNode->next; 154 | delete chain::firstNode; 155 | chain::firstNode = nextNode; 156 | } 157 | lastNode = NULL; 158 | chain::listSize = 0; 159 | } 160 | 161 | //设置大小为theSize 162 | template 163 | void extendedChain::setSize(int theSize) { 164 | //如果数组的初始大小小于等于指定的值,则增加NULL元素 165 | //如果数组的初始大小大于指定的值,则删除多余元素 166 | if(theSize < 0){ 167 | ostringstream s; 168 | s << "Set size = " << theSize << "Must be >= 0"; 169 | throw illegalParameterValue(s.str()); 170 | } 171 | if(chain::listSize > theSize){ 172 | //找到索引为theSize的前驱 173 | chainNode* p = chain::firstNode; 174 | for(int i = 0; i < theSize - 1; ++i) 175 | p = p->next; 176 | //删除所有结点 177 | while(p->next != NULL){ 178 | chainNode* currentNode = p->next; 179 | p->next = currentNode->next; 180 | delete currentNode; 181 | } 182 | lastNode = p; 183 | chain::listSize = theSize; 184 | } 185 | } 186 | 187 | //将索引为theIndex的元素值改为theElement 188 | template 189 | void extendedChain::set(int theIndex, const T &theElement) { 190 | if(theIndex == chain::listSize - 1) 191 | lastNode->element = theElement; 192 | else 193 | chain::set(theIndex, theElement); 194 | } 195 | 196 | //把元素theElement插入到线性表中索引为theIndeex的地方 197 | template 198 | void extendedChain::insert(int theIndex, const T &theElement) { 199 | //先检查索引是否有效 200 | if(theIndex < 0 || theIndex > chain::listSize){ 201 | //无效索引 202 | ostringstream s; 203 | s << "index = " << theIndex << " size = " << chain::listSize; 204 | throw illegalIndex(s.str()); 205 | } 206 | 207 | if(theIndex == 0) { 208 | //空表 209 | if(chain::firstNode == NULL) 210 | chain::firstNode = lastNode = new chainNode(theElement, NULL); 211 | else 212 | //在非空链表头插入 213 | chain::firstNode = new chainNode(theElement, chain::firstNode); 214 | }else if(theIndex == chain::listSize) { 215 | lastNode->next = new chainNode(theElement, NULL); 216 | lastNode = lastNode->next; 217 | } else{ 218 | //需要插入索引的前驱 219 | chainNode* p = chain::firstNode; 220 | for(int i = 0; i < theIndex - 1; ++i) 221 | p = p->next; 222 | p->next = new chainNode(theElement, p->next); 223 | } 224 | ++chain::listSize; 225 | } 226 | 227 | //尾插入 228 | template 229 | void extendedChain::push_back(const T &theElement) { 230 | chainNode* newNode = new chainNode(theElement, NULL); 231 | if(chain::firstNode == NULL) 232 | //链表为空 233 | chain::firstNode = lastNode = newNode; 234 | else{ 235 | //把新结点附加到lastNode指向的结点 236 | lastNode->next = newNode; 237 | lastNode = newNode; 238 | } 239 | ++chain::listSize; 240 | } 241 | 242 | //首插入 243 | template 244 | void extendedChain::push_front(const T &theElement) { 245 | //线性表初始为空 246 | if(chain::firstNode == NULL) 247 | chain::firstNode = lastNode = new chainNode(theElement, NULL); 248 | //初始不为空 249 | else 250 | chain::firstNode = new chainNode(theElement, chain::firstNode); 251 | } 252 | 253 | //首弹出 254 | template 255 | void extendedChain::pop_front() { 256 | chain::pop_front(); 257 | if(chain::firstNode == NULL) 258 | lastNode = NULL; 259 | } 260 | 261 | //删除指定范围内的元素 262 | template 263 | void extendedChain::removeRange(int fromIndex, int toIndex) { 264 | //确定索引是否有效 265 | if(fromIndex < 0 || toIndex >= chain::listSize){ 266 | //无效的索引 267 | ostringstream s; 268 | s << "Index from" << fromIndex << " to " << toIndex << " size = " << chain::listSize; 269 | throw illegalParameterValue(s.str()); 270 | } 271 | if(fromIndex == 0){ 272 | for(int i = 0; i <= toIndex; ++i){ 273 | chainNode* p = chain::firstNode; 274 | chain::firstNode = chain::firstNode->next; 275 | delete p; 276 | } 277 | if(toIndex == chain::listSize - 1) 278 | lastNode = NULL; 279 | } else{ 280 | //找到开始删除结点的前驱结点 281 | chainNode* p = chain::firstNode; 282 | for(int i = 0; i < fromIndex - 1; ++i) 283 | p = p->next; 284 | int needDeleteNum = (toIndex - fromIndex + 1); 285 | while(needDeleteNum > 0){ 286 | chainNode* currentNode = p->next; 287 | p->next = currentNode->next; 288 | delete currentNode; 289 | --needDeleteNum; 290 | } 291 | //末尾元素也在删除范围里 292 | if(toIndex == chain::listSize - 1) 293 | lastNode = p; 294 | } 295 | 296 | chain::listSize -= (toIndex - fromIndex + 1); 297 | } 298 | 299 | //反转线性表 300 | template 301 | void extendedChain::reverse() { 302 | //最多只有一个结点的情况下不变 303 | if(chain::listSize < 2) return; 304 | 305 | chainNode* currentNode = chain::firstNode->next; 306 | chain::firstNode->next = NULL; 307 | lastNode = chain::firstNode; 308 | //迭代 309 | while(currentNode != NULL){ 310 | chainNode* nextNode = currentNode->next; 311 | currentNode->next = chain::firstNode; 312 | chain::firstNode = currentNode; 313 | currentNode = nextNode; 314 | } 315 | } 316 | 317 | //交换两个线性表 318 | template 319 | void extendedChain::swap(extendedChain &theList) { 320 | chain::swap(theList); 321 | //交换两个lastnode结点 322 | chainNode* copyChain = theList.lastNode; 323 | theList.lastNode = lastNode; 324 | lastNode = copyChain; 325 | } 326 | 327 | #endif //DSACPP_EXTENDEDCHAIN_H 328 | -------------------------------------------------------------------------------- /Chap6_LinkedList/extendedLinearList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/14. 3 | // 4 | 5 | #ifndef DSACPP_EXTENDEDLINEARLIST_H 6 | #define DSACPP_EXTENDEDLINEARLIST_H 7 | 8 | #include "linearList.h" 9 | 10 | //扩展的线性表的抽象类 11 | template 12 | class extendedLinearList : public linearList{ 13 | public: 14 | //虚析构函数 15 | virtual ~extendedLinearList() {} 16 | 17 | //清表 18 | virtual void clear() = 0; 19 | 20 | //将元素theElement插入到表尾 21 | virtual void push_back(const T& theElement) = 0; 22 | }; 23 | 24 | #endif //DSACPP_EXTENDEDLINEARLIST_H 25 | -------------------------------------------------------------------------------- /Chap6_LinkedList/test_chain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-10-10. 3 | // 4 | 5 | #include 6 | #include "chain.h" 7 | 8 | using namespace std; 9 | 10 | int main(){ 11 | chain numChain1, numChain2; 12 | for(int i = 0; i < 20; ++i){ 13 | numChain1.insert(i, i); 14 | numChain2.insert(i, i); 15 | } 16 | numChain1.pop_front(); 17 | cout << "after numChain1.pop_front(): " << numChain1 << endl << "numChain1.size(): " << numChain1.size() << endl; 18 | numChain1.setSize(15); 19 | cout << "numChain1: " << numChain1 << endl; 20 | cout << "numChain1 == numChain2: " << (numChain1 == numChain2) << endl; 21 | cout << "numChain1.front(): " << numChain1.front() << endl; 22 | numChain1.front() = 1; 23 | cout << "after numChain1.front() = 1, numChain1: " << numChain1 << endl; 24 | numChain1.removeRange(11, 14); 25 | cout << "after numChain1.removeRange(11, 14): " << numChain1 << endl; 26 | numChain1.set(4, 0); 27 | cout << "after numChain1.set(4, 0): " << numChain1 << endl; 28 | cout << "numChain1: " << numChain1 << endl; 29 | cout << numChain1.lastIndexOf(0) << " " << numChain1.lastIndexOf(11) << endl; 30 | cout << "numChain1 == numChain2: " << (numChain1 == numChain2) << endl; 31 | cout << "numChain1 < numChain2: " << (numChain1 < numChain2) << endl; 32 | 33 | numChain1.swap(numChain2); 34 | cout << "numChain1: " << numChain1 << endl << "numChain2: " << numChain2 << endl; 35 | 36 | numChain1.reverse(); 37 | cout << "numChain1.reverse(): " << numChain1 << endl; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Chap6_LinkedList/test_circularListWithHeader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/17. 3 | // 4 | 5 | #include 6 | #include "circularListWithHeader.h" 7 | 8 | using namespace std; 9 | 10 | int main(){ 11 | circularListWithHeader numCircular1, numCircular2; 12 | for(int i = 0; i < 21; ++i) { 13 | numCircular1.push_back(i); 14 | numCircular2.push_front(i); 15 | } 16 | cout << "numCircular1: " << numCircular1 << endl; 17 | cout << "numCircular2: " << numCircular2 << endl; 18 | cout << "numCircular1 == numCircular2: " << (numCircular1 == numCircular2) << endl; 19 | numCircular2.reverse(); 20 | cout << "after numCircular2.reverse(): " << numCircular2 << endl; 21 | cout << "numCircular2 use iterator: "; 22 | for(auto it = numCircular2.begin(); it != numCircular2.end(); ++it) 23 | cout << *it << " "; 24 | cout << endl; 25 | cout << "numCircular1 == numCircular2: " << (numCircular1 == numCircular2) << endl; 26 | numCircular1.insert(5, 0); 27 | cout << "after numCircular1.insert(5, 7): " << numCircular1 << endl; 28 | numCircular2.pop_front(); 29 | cout << "after numCircular2.pop_back(): " << numCircular2 << endl; 30 | numCircular1.erase(0); 31 | cout << "after numCircular1.erase(0): " << numCircular1 << endl; 32 | cout << "numCircular1 < numCircular2: " << (numCircular1 < numCircular2) << endl; 33 | numCircular2.setSize(10); 34 | cout << "after numCircular2.setSize(10): " << numCircular2 << endl; 35 | numCircular1.set(4, 5); 36 | cout << "after numCircular1.set(4, 5): " << numCircular1 << endl; 37 | numCircular1.removeRange(5, 20); 38 | cout << "after numCircular1.removeRange(5, 20): " << numCircular1 << endl; 39 | numCircular1.swap(numCircular2); 40 | cout << "after numCircular1.swap(numCircular2), numCircular1: " << numCircular1 << endl; 41 | cout << "after numCircular1.swap(numCircular2), numCircular2: " << numCircular2 << endl; 42 | numCircular1.push_back(55); 43 | numCircular2.push_back(66); 44 | cout << "after numCircular1.push_back(55): " << numCircular1 << endl; 45 | cout << "after numCircular2.push_back(66): " << numCircular2 << endl; 46 | cout << numCircular1.size() << " " << numCircular2.size() << endl; 47 | cout << "from ++end() to end(): "; 48 | for(auto it = ++numCircular1.end(); it != numCircular1.end(); ++it) 49 | cout << *it << " "; 50 | numCircular1.clear(); 51 | numCircular2.clear(); 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Chap6_LinkedList/test_doublyLinkedListWithHeader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/20. 3 | // 4 | 5 | #include 6 | #include "doublyLinkedListWithHeader.h" 7 | 8 | using namespace std; 9 | 10 | int main(){ 11 | doublyLinkedListWithHeader nums1, nums2; 12 | for(int i = 0; i < 30; ++i) { 13 | nums1.push_back(i); 14 | nums2.push_front(i); 15 | } 16 | cout << "nums1: " << nums1 << endl << "nums2: " << nums2 << endl; 17 | nums1.pop_front(); 18 | nums1.pop_back(); 19 | cout << "after nums1.pop_front(), nums1.pop_back(): " << nums1 << endl; 20 | cout << "for(auto it = ++nums2.end(); it != nums2.end(); ++it): "; 21 | for(auto it = ++nums2.end(); it != nums2.end(); ++it) 22 | cout << *it << " "; 23 | cout << endl; 24 | nums1.swap(nums2); 25 | cout << "after nums1.swap(nums2):" << endl; 26 | cout << "nums1: " << nums1 << endl << "nums2: " << nums2 << endl; 27 | nums1.reverse(); 28 | cout << "after nums1.reverse(): " << nums1 << endl; 29 | nums1.removeRange(3, 10); 30 | nums1.set(3, 3); 31 | nums1.insert(4, 4); 32 | cout << "nums1.removeRange(3, 10), nums1.set(3, 3), nums1.insert(4, 4): " << nums1 << endl; 33 | nums1.erase(5); 34 | cout << "after nums1.erase(5): " << nums1 << endl; 35 | return 0; 36 | } -------------------------------------------------------------------------------- /Chap6_LinkedList/test_extendedChain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/14. 3 | // 4 | 5 | #include "extendedChain.h" 6 | 7 | int main(){ 8 | extendedChain numChain1, numChain2; 9 | for(int i = 0; i < 20; ++i){ 10 | numChain1.push_back(i); 11 | numChain2.push_back(i); 12 | } 13 | numChain2.push_back(20); 14 | cout << "numChain1: " << numChain1 << endl << "numChain2: " << numChain2 << endl; 15 | numChain1.reverse(); 16 | cout << "after numChain1.reverse(), numChain1: " << numChain1 << endl; 17 | numChain1.swap(numChain2); 18 | cout << "after numChain1.swap(numChain2), numChain1: " << numChain1 << endl; 19 | cout << "after numChain1.swap(numChain2), numChain2: " << numChain2 << endl; 20 | cout << "use iterator: "; 21 | for(auto it = numChain1.begin(); it != numChain1.end(); ++it) 22 | cout << *it << " "; 23 | cout << endl; 24 | cout << "numChain1.back(): " << numChain1.back() << endl; 25 | cout << "numChain1 == numChain2: " << numChain1.isEqual(numChain2) << endl; 26 | numChain1.push_back(55); 27 | cout << numChain1 << endl; 28 | extendedChain numChain3; 29 | //numChain3.insert(0, 1); 30 | numChain3.push_front(1); 31 | //numChain3.erase(0); 32 | //numChain3.pop_front(); 33 | cout << numChain3.back() << endl; 34 | numChain3.push_back(2); 35 | cout << numChain3 << endl; 36 | numChain1.removeRange(0, 4); 37 | cout << numChain1 << endl; 38 | 39 | 40 | numChain1.clear(); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /Chap7_Matrix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | include_directories(../Chap5_ArrayList) 6 | 7 | add_executable(Chap7_matrix matrix.h test_matrix.cpp) 8 | 9 | add_executable(Chap7_spareMatrix spareMatrix.h test_spareMatrix.cpp) -------------------------------------------------------------------------------- /Chap7_Matrix/matrix.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/24. 3 | // 4 | 5 | #ifndef DSACPP_MATRIX_H 6 | #define DSACPP_MATRIX_H 7 | 8 | #include 9 | #include "../MyExceptions.h" 10 | 11 | //矩阵类 12 | template 13 | class matrix { 14 | // 友元函数,重载的<< 15 | friend ostream& operator<<(ostream& out, const matrix& m) { 16 | for (int i = 0; i < m.theRows; ++i) { 17 | for (int j = 0; j < m.theColumns; ++j) { 18 | out << m.element[i * m.theColumns + j] << " "; 19 | } 20 | out << endl; 21 | } 22 | return out; 23 | } 24 | public: 25 | //构造函数、复制构造函数和析构函数 26 | matrix(int theRows = 0, int theColums = 0); 27 | matrix(const matrix&); 28 | ~matrix() {delete [] element;} 29 | 30 | // 获取行数和列数 31 | int rows() const {return theRows;} 32 | int columns() const {return theColumns;} 33 | 34 | // 重载(),可以像数学表达式一样访问元素 35 | T& operator() (int i, int j) const; 36 | 37 | // 重载=运算符 38 | matrix& operator=(const matrix&); 39 | 40 | // 一元和二元的+运算符 41 | matrix operator+() const; 42 | matrix operator+(const matrix&) const; 43 | 44 | // 一元和二元的-运算符 45 | matrix operator-() const; 46 | matrix operator-(const matrix&) const; 47 | 48 | // 重载*运算符 49 | matrix operator*(const matrix&) const; 50 | 51 | // 重载+=,-=,*=,/=运算符 52 | matrix& operator+=(const T&); 53 | matrix& operator-=(const T&); 54 | matrix& operator*=(const T&); 55 | matrix& operator/=(const T&); 56 | 57 | // 矩阵转置 58 | matrix tranpose() const; 59 | 60 | private: 61 | int theRows, theColumns; //矩阵的行数和列数 62 | T *element; // 数组 element 63 | }; 64 | 65 | // 构造函数和复制构造函数 66 | template 67 | matrix::matrix(int theRows, int theColumns) { 68 | // 检查参数的有效性,可以生成行数和列数都大于0的矩阵,也可以生成0*0的矩阵 69 | if (theRows < 0 || theColumns < 0) 70 | throw illegalParameterValue("Rows and Columns must be >= 0"); 71 | if ((theRows ==0 || theColumns == 0) && (theRows != 0 || theColumns != 0)) 72 | throw illegalParameterValue("Either both or neither rows and columns should be zero"); 73 | 74 | // 创建行主映射矩阵 75 | this->theRows = theRows; 76 | this->theColumns = theColumns; 77 | this->element = new T [theRows * theColumns]; 78 | } 79 | 80 | template 81 | matrix::matrix(const matrix& m) { 82 | // 创建矩阵 83 | theRows = m.theRows; 84 | theColumns = m.theColumns; 85 | element = new T [theRows * theColumns]; 86 | 87 | // 复制所有元素 88 | copy(m.element, m.element + theRows * theColumns, element); 89 | } 90 | 91 | // 重载=运算符 92 | template 93 | matrix& matrix::operator=(const matrix& m) { 94 | // 不能赋值给自己 95 | if (this != &m) { 96 | // 先清空,再复制 97 | delete [] element; 98 | theRows = m.theRows; 99 | theColumns = m.theColumns; 100 | element = new T [theRows * theColumns]; 101 | copy(m.element, m.element + theRows * theColumns, element); 102 | } 103 | return *this; 104 | } 105 | 106 | // 重载()运算符,满足数学表达式一样的访问 107 | template 108 | T& matrix::operator()(int i, int j) const { 109 | // 检查索引是否有效 110 | if (i < 1 || i > theRows || j < 1 || j > theColumns) 111 | throw matrixIndexOutOfBounds(); 112 | return element[(i - 1) * theColumns + j - 1]; 113 | } 114 | 115 | // 重载+运算符,矩阵加法 116 | template 117 | matrix matrix::operator+(const matrix &m) const { 118 | // 只有行列数相同的矩阵才能相加 119 | if (theRows != m.theRows || theColumns != m.theColumns) 120 | throw matrixIndexOutOfBounds(); 121 | 122 | // 生成结果矩阵 123 | matrix w(theRows, theColumns); 124 | for(int i = 0; i < theRows * theColumns; ++i) 125 | w.element[i] = element[i] + m.element[i]; 126 | 127 | return w; 128 | } 129 | 130 | // 一元+运算符 131 | template 132 | matrix matrix::operator+() const { 133 | matrix m(theRows, theColumns); 134 | for(int i = 0; i < theRows * theColumns; ++i) 135 | m.element[i] = +element[i]; 136 | return m; 137 | } 138 | 139 | // 重载+=运算符 140 | template 141 | matrix& matrix::operator+=(const T &x) { 142 | for(int i = 0; i < theRows * theColumns; ++i) 143 | element[i] += x; 144 | return *this; 145 | } 146 | 147 | // 重载-运算符,矩阵减法 148 | template 149 | matrix matrix::operator-(const matrix &m) const { 150 | // 只有行列数相同的矩阵才能相加 151 | if (theRows != m.theRows || theColumns != m.theColumns) 152 | throw matrixIndexOutOfBounds(); 153 | 154 | // 生成结果矩阵 155 | matrix w(theRows, theColumns); 156 | for(int i = 0; i < theRows * theColumns; ++i) 157 | w.element[i] = element[i] - m.element[i]; 158 | 159 | return w; 160 | } 161 | 162 | // 一元-运算符 163 | template 164 | matrix matrix::operator-() const { 165 | matrix m(theRows, theColumns); 166 | for(int i = 0; i < theRows * theColumns; ++i) 167 | m.element[i] = -element[i]; 168 | return m; 169 | } 170 | 171 | // 重载-=运算符 172 | template 173 | matrix& matrix::operator-=(const T &x) { 174 | for(int i = 0; i < theRows * theColumns; ++i) 175 | element[i] -= x; 176 | return *this; 177 | } 178 | 179 | // 重载*运算符,矩阵乘法 180 | template 181 | matrix matrix::operator*(const matrix &m) const { 182 | // 要求*this的列数等于m的行数 183 | if (theColumns != m.theRows) 184 | throw matrixIndexOutOfBounds(); 185 | 186 | matrix w(theRows, m.theColumns); // 结果矩阵 187 | 188 | // 矩阵*this,m和w的游标且初始化为(1, 1)元素定位 189 | int ct = 0, cm = 0, cw = 0; 190 | 191 | //对所有i和j计算 w(i, j) 192 | for(int i = 1; i <= theRows; ++i) { 193 | // 计算结果的第i行 194 | for(int j = 1; j <= m.theColumns; ++j) { 195 | // 计算w(i, j) 196 | T sum = element[ct] * m.element[cm]; 197 | 198 | // 累加其他剩余项 199 | for(int k = 2; k <= theColumns; ++k) { 200 | ++ct; // *this第i行的下一项 201 | cm += m.theColumns; // m第j列的下一项 202 | sum += element[ct] * element[cm]; 203 | } 204 | w.element[cw++] = sum; 205 | 206 | // 从行的起点和下一列重新开始 207 | ct -= theColumns - 1; 208 | cm = j; 209 | } 210 | 211 | //从下一行和第一列开始 212 | ct += theColumns; 213 | cm = 0; 214 | } 215 | return w; 216 | } 217 | 218 | // 重载*=运算符 219 | template 220 | matrix& matrix::operator*=(const T &x) { 221 | for(int i = 0; i < theRows * theColumns; ++i) 222 | element[i] *= x; 223 | return *this; 224 | } 225 | 226 | // 重载/=运算符 227 | template 228 | matrix& matrix::operator/=(const T &x) { 229 | for(int i = 0; i < theRows * theColumns; ++i) 230 | element[i] /= x; 231 | return *this; 232 | } 233 | 234 | // 矩阵转置 235 | template 236 | matrix matrix::tranpose() const { 237 | // 生成结果矩阵 238 | matrix m(theColumns, theRows); 239 | 240 | // *this的(i, j)索引上的元素是 m 的(j, i)索引上的元素 241 | for (int it = 0; it < theRows * theColumns; ++it) { 242 | int i = it / theColumns; 243 | int j = it % theColumns; 244 | m.element[j * theRows + i] = element[it]; 245 | } 246 | return m; 247 | } 248 | 249 | #endif //DSACPP_MATRIX_H 250 | -------------------------------------------------------------------------------- /Chap7_Matrix/spareMatrix.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/31. 3 | // 4 | 5 | #ifndef DSACPP_SPAREMATRIX_H 6 | #define DSACPP_SPAREMATRIX_H 7 | 8 | #include "../MyExceptions.h" 9 | #include "../Chap5_ArrayList/arrayList.h" 10 | 11 | //按行主次序,记录每个非零元素的行号、列号和值 12 | template 13 | struct matrixTerm { 14 | int row, col; //行号和列号 15 | T value; //元素值 16 | matrixTerm() : row(0), col(0), value(0) {} 17 | matrixTerm(int r, int c, const T& v): row(r), col(c), value(v) {} 18 | operator T() const {return value;} 19 | }; 20 | 21 | template class spareMatrix; 22 | template istream& operator>>(istream& in, spareMatrix& x); 23 | template ostream& operator<<(ostream& out, spareMatrix& x); 24 | 25 | //稀疏矩阵类 26 | template 27 | class spareMatrix { 28 | //重载输入、输出运算符 29 | friend ostream& operator<< <>(ostream& out, spareMatrix& x); 30 | friend istream& operator>> <>(istream& in, spareMatrix& x); 31 | public: 32 | //构造函数和复制构造函数 33 | spareMatrix() {} 34 | spareMatrix(const spareMatrix& m); 35 | 36 | //get和set方法 37 | T& get(int theRow, int theColumn) const; 38 | void set(int theRow, int theColumn, const T& theValue); 39 | 40 | //转置 41 | void transpose(spareMatrix &b); 42 | 43 | //加法 44 | void add(spareMatrix &b, spareMatrix &c); 45 | 46 | //乘法 47 | void multiply(spareMatrix &b, spareMatrix &c); 48 | private: 49 | int rows, cols; //矩阵行数和列数 50 | arrayList > terms; //非0项表 51 | }; 52 | 53 | //重载<<运算符 54 | template 55 | ostream& operator<<(ostream& out, spareMatrix& x) { 56 | //输出矩阵特征 57 | out << "rows = " << x.rows << "columns = " << x.cols << endl; 58 | out << "nonzero terms = " << x.terms.size() << endl; 59 | 60 | //输出矩阵项 61 | for(auto i = x.terms.begin(); i != x.terms.end(); ++i) 62 | out << "a(" << (*i).row << ',' << (*i).col << ") = " << (*i).value << endl; 63 | return out; 64 | } 65 | 66 | //重载>>运算符 67 | template 68 | istream& operator>>(istream& in, spareMatrix& x) { 69 | //输入矩阵特征 70 | int numberOfTerms; 71 | cout << "Enter number of rows, columns, and #terms" << endl; 72 | in >> x.rows >> x.cols >> numberOfTerms; 73 | 74 | //检查输入合法性 75 | if (x.rows < 0 || x.cols < 0) 76 | throw illegalParameterValue("Rows and Columns must be >= 0"); 77 | if ((x.rows ==0 || x.cols == 0) && (x.rows != 0 || x.cols != 0)) 78 | throw illegalParameterValue("Either both or neither rows and columns should be zero"); 79 | if (numberOfTerms >= (x.rows * x.cols / 3)) 80 | throw illegalParameterValue("number of term must be < (rows * columns / 3)"); 81 | 82 | //设置x.terms的大小,确保足够的容量 83 | x.terms.reSet(numberOfTerms); 84 | 85 | //输入项 86 | matrixTerm mTerms; 87 | for(int i = 0; i < numberOfTerms; ++i) { 88 | cout << "Enter row, columns, and value of term " << (i + 1) << endl; 89 | in >> mTerms.row >> mTerms.col >> mTerms.value; 90 | 91 | //检查输入合法性 92 | if (mTerms.row < 1 || mTerms.row > x.rows || mTerms.col < 1 || mTerms.col > x.cols) 93 | throw matrixIndexOutOfBounds(); 94 | if (i >= 1 && (mTerms.row < x.terms[i - 1].row || 95 | (mTerms.row == x.terms[i - 1].row && mTerms.col <= x.terms[i - 1].col))) 96 | throw illegalParameterValue("Please enter in line main order"); 97 | if (mTerms.value == 0) 98 | throw illegalParameterValue("value of term must be != 0"); 99 | x.terms.set(i, mTerms); 100 | } 101 | return in; 102 | } 103 | 104 | //复制构造函数 105 | template 106 | spareMatrix::spareMatrix(const spareMatrix &m) { 107 | rows = m.rows; 108 | cols = m.cols; 109 | terms = arrayList>(m.terms); 110 | } 111 | 112 | //get方法 113 | template 114 | T & spareMatrix::get(int theRow, int theColumn) const { 115 | //检查索引是否有效 116 | if (theRow < 1 || theRow > rows || theColumn < 1 || theColumn > cols) 117 | throw matrixIndexOutOfBounds(); 118 | 119 | //找到第一个不在所给索引之前的非0元素 120 | auto i = terms.begin(); 121 | while (i != terms.end() && !((*i).row >= theRow && (*i).col >= theColumn)) 122 | ++i; 123 | 124 | //所给索引位置的元素是非0的 125 | if ((*i).row == theRow && (*i).col == theColumn) 126 | return (*i).value; 127 | else 128 | return 0; 129 | } 130 | 131 | //set方法 132 | template 133 | void spareMatrix::set(int theRow, int theColumn, const T &theValue) { 134 | //检查索引是否有效 135 | if (theRow < 1 || theRow > rows || theColumn < 1 || theColumn > cols) 136 | throw matrixIndexOutOfBounds(); 137 | 138 | //找到第一个不在所给索引之前的非0元素 139 | auto i = terms.begin(); 140 | while (i != terms.end() && !((*i).row >= theRow && (*i).col >= theColumn)) 141 | ++i; 142 | 143 | //所给索引位置的元素是非0的 144 | if ((*i).row == theRow && (*i).col == theColumn) { 145 | //theValue非0 146 | if(theValue != 0) 147 | (*i).value = theValue; 148 | else 149 | //设为0,需要删除 150 | terms.erase(i - terms.begin()); 151 | } else if (theValue != 0) 152 | //插入新的非0元素 153 | terms.insert(i - terms.begin(), matrixTerm(theRow, theColumn, theValue)); 154 | } 155 | 156 | //矩阵转置 157 | template 158 | void spareMatrix::transpose(spareMatrix &b) { 159 | //设置转置矩阵特征 160 | b.cols = rows; 161 | b.rows = cols; 162 | b.terms.reSet(terms.size()); 163 | 164 | int *colSize = new int[cols + 1]; //*this的每一列的项的数目 165 | int *rowNext = new int[cols + 1]; //b中每一行的起始项在terms中的位置 166 | 167 | for (int i = 1; i <= cols; ++i) 168 | colSize[i] = 0; 169 | for (auto i = terms.begin(); i != terms.end(); ++i) 170 | ++colSize[(*i).col]; 171 | 172 | rowNext[1] = 0; 173 | for (int i = 2; i <= cols; ++i) 174 | rowNext[i] = rowNext[i - 1] + colSize[i - 1]; 175 | 176 | //开始转置 177 | matrixTerm mTerms; 178 | for (auto i = terms.begin(); i != terms.end(); ++i) { 179 | int j = rowNext[(*i).col]++; //在b的terms中的位置 180 | mTerms.row = (*i).col; 181 | mTerms.col = (*i).row; 182 | mTerms.value = (*i).value; 183 | b.terms.set(j, mTerms); 184 | } 185 | } 186 | 187 | //矩阵相加 188 | template 189 | void spareMatrix::add(spareMatrix &b, spareMatrix &c) { 190 | //计算c = (*this) + b 191 | 192 | //检验相容性 193 | if (rows != b.rows || cols != b.cols) 194 | throw matrixSizeMismatch(); 195 | //设置结果矩阵c的特征 196 | c.rows = rows; 197 | c.cols = cols; 198 | c.terms.clear(); 199 | int cSize = 0; 200 | 201 | //定义*this和b的迭代器 202 | auto it = terms.begin(); 203 | auto ib = b.terms.begin(); 204 | auto itEnd = terms.end(); 205 | auto ibEnd = b.terms.end(); 206 | 207 | //遍历*this和b,把相关的项相加 208 | while (it != itEnd && ib != ibEnd) { 209 | //行主索引加上每一项的列数 210 | int tIndex = (*it).row * cols + (*it).col; 211 | int bIndex = (*ib).row * cols + (*ib).col; 212 | 213 | if (tIndex < bIndex) { 214 | //b项在后 215 | c.terms.insert(cSize++, *it); 216 | ++it; 217 | } else if (tIndex == bIndex) { 218 | //同一位置 219 | if ((*it).value + (*ib).value != 0) { 220 | //两项和不为0时加入c 221 | c.terms.insert(cSize++, matrixTerm((*it).row, (*it).col, (*it).value + (*ib).value)); 222 | } 223 | ++it; 224 | ++ib; 225 | } else { 226 | //*this在后 227 | c.terms.insert(cSize++, *ib); 228 | ++ib; 229 | } 230 | } 231 | 232 | //复制剩余项 233 | while (it != itEnd) 234 | c.terms.insert(cSize++, *(it++)); 235 | while (ib != ibEnd) 236 | c.terms.insert(cSize++, *(ib++)); 237 | } 238 | 239 | //乘法 240 | template 241 | void spareMatrix::multiply(spareMatrix &b, spareMatrix &c) { 242 | //计算c = (*this) * b 243 | //检验相容性 244 | if (cols != b.rows) 245 | throw matrixSizeMismatch(); 246 | //设置结果矩阵c的特征 247 | c.rows = rows; c.cols = b.cols; c.terms.clear(); 248 | int cSize = 0; 249 | 250 | //将b转置 251 | spareMatrix d; 252 | b.transpose(d); 253 | 254 | //统计*this和d的每一行的非0元素个数 255 | int *rowSizeA = new int[rows + 1], *rowNext = new int[rows + 1]; 256 | for (int i = 1; i <= rows; ++i) rowSizeA[i] = 0; 257 | for (auto i = terms.begin(); i != terms.end(); ++i) ++rowSizeA[(*i).row]; 258 | //*this每行开始的位置 259 | rowNext[1] = 0; 260 | for (int i = 2; i <= cols; ++i) 261 | rowNext[i] = rowNext[i - 1] + rowSizeA[i - 1]; 262 | 263 | int *rowSizeD = new int[d.rows + 1]; 264 | for (int i = 1; i <= d.rows; ++i) rowSizeD[i] = 0; 265 | for (auto i = d.terms.begin(); i != d.terms.end(); ++i) ++rowSizeD[(*i).row]; 266 | 267 | //*this的每一行和d的每一行做内积 268 | auto it = terms.begin(), id = d.terms.begin(); 269 | for (int i = 1; i <= rows; ++i) { 270 | id = d.terms.begin(); 271 | for (int j = 1; j <= d.rows; ++j) { 272 | if (rowSizeA[i] != 0 && rowSizeD[j] != 0) { 273 | it = terms.begin() + rowNext[i]; 274 | int sum = 0, rA = rowSizeA[i], rD = rowSizeD[j]; 275 | while (rA != 0 && rD != 0) { 276 | if ((*it).col < (*id).col) { 277 | ++it; --rA; 278 | } else if ((*it).col > (*id).col) { 279 | ++id; --rD; 280 | } else { 281 | sum += ((*it).value * (*id).value); 282 | ++it; ++id; --rA; --rD; 283 | } 284 | } 285 | if (rA != 0) it += rA; 286 | if (rD != 0) id += rD; 287 | if (sum != 0) 288 | c.terms.insert(cSize++, matrixTerm(i, j, sum)); 289 | } 290 | } 291 | } 292 | } 293 | 294 | #endif //DSACPP_SPAREMATRIX_H 295 | -------------------------------------------------------------------------------- /Chap7_Matrix/test_matrix.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/24. 3 | // 4 | 5 | #include 6 | #include "matrix.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | matrix m(4, 6); 12 | 13 | for (int i = 1; i <= 4; ++i) { 14 | for (int j = 1; j <= 6; ++j) { 15 | m(i, j) = (rand() % 50); 16 | } 17 | } 18 | cout << m << endl; 19 | cout << m.tranpose() << endl; 20 | return 0; 21 | } -------------------------------------------------------------------------------- /Chap7_Matrix/test_spareMatrix.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/10/31. 3 | // 4 | 5 | #include 6 | #include "spareMatrix.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | spareMatrix m1; 12 | cout << "Input M: " << endl; 13 | cin >> m1; 14 | cout << m1; 15 | 16 | spareMatrix m2; 17 | m1.transpose(m2); 18 | spareMatrix w1; 19 | cout << "M + M^T: " << endl; 20 | m1.add(m2, w1); 21 | cout << w1; 22 | 23 | cout << "Input N: " << endl; 24 | cin >> m2; 25 | cout << m2; 26 | m1.multiply(m2, w1); 27 | cout << "M * N: " << endl; 28 | cout << w1; 29 | return 0; 30 | } -------------------------------------------------------------------------------- /Chap8_Stack/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | add_executable(Chap8_arrayStack arrayStack.h stack.h test_arrayStack.cpp) 6 | 7 | add_executable(Chap8_linkedStack linkedStack.h test_linkedStack.cpp) -------------------------------------------------------------------------------- /Chap8_Stack/arrayStack.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/5. 3 | // 4 | 5 | #ifndef DSACPP_ARRAYSTACK_H 6 | #define DSACPP_ARRAYSTACK_H 7 | 8 | #include 9 | #include "stack.h" 10 | #include "../MyExceptions.h" 11 | #include "../Chap5_ArrayList/changeLength1D.h" 12 | 13 | //数组描述的栈 14 | template 15 | class arrayStack : public Stack { 16 | public: 17 | //构造和析构函数 18 | arrayStack(int initCapacity = 10); 19 | ~arrayStack() {delete [] stack;} 20 | 21 | //判断 22 | bool empty() const {return stackTop == -1;} 23 | 24 | //取得栈的大小 25 | int size() const {return stackTop + 1;} 26 | 27 | //取得栈顶的引用 28 | T& top() { 29 | if (stackTop == -1) 30 | throw stackEmpty(); 31 | return stack[stackTop]; 32 | } 33 | 34 | //删除栈顶元素 35 | void pop() { 36 | if (stackTop == -1) 37 | throw stackEmpty(); 38 | stack[stackTop--].~T(); 39 | } 40 | 41 | //将元素theElement压入栈 42 | void push(const T& theElement); 43 | private: 44 | int stackTop; //当前栈顶 45 | int arrayLength; //栈的容量 46 | T *stack; //元素数组 47 | }; 48 | 49 | //构造函数 50 | template 51 | arrayStack::arrayStack(int initCapacity) { 52 | if (initCapacity < 1) { 53 | ostringstream s; 54 | s << "Initial capacity = " << initCapacity << " Must be > 0"; 55 | throw illegalParameterValue(s.str()); 56 | } 57 | arrayLength = initCapacity; 58 | stack = new T[arrayLength]; 59 | stackTop = -1; 60 | } 61 | 62 | //将元素theElement压入栈 63 | template 64 | void arrayStack::push(const T &theElement) { 65 | //如果空间已满,容量加倍 66 | if (stackTop == (arrayLength - 1)) { 67 | changeLength1D(stack, arrayLength, arrayLength * 2); 68 | arrayLength *= 2; 69 | } 70 | //栈顶插入 71 | stack[++stackTop] = theElement; 72 | } 73 | 74 | #endif //DSACPP_ARRAYSTACK_H 75 | -------------------------------------------------------------------------------- /Chap8_Stack/linkedStack.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/5. 3 | // 4 | 5 | #ifndef DSACPP_LINKEDSTACK_H 6 | #define DSACPP_LINKEDSTACK_H 7 | 8 | #include "stack.h" 9 | #include "../Chap6_LinkedList/chainNode.h" 10 | #include "../MyExceptions.h" 11 | 12 | //链表描述的栈 13 | template 14 | class linkedStack : public Stack { 15 | public: 16 | //构造函数 17 | linkedStack(int initCapacity = 10) {stackTop = NULL; stackSize = 0;} 18 | 19 | //析构函数 20 | ~linkedStack(); 21 | 22 | //判空 23 | bool empty() const { return stackSize == 0;} 24 | 25 | //返回栈的大小 26 | int size() const { return stackSize;} 27 | 28 | //返回栈顶的引用 29 | T& top() { 30 | if (stackSize == 0) 31 | throw stackEmpty(); 32 | return stackTop->element; 33 | } 34 | 35 | //删除栈顶 36 | void pop(); 37 | 38 | //元素theElement入栈 39 | void push(const T& theElement) { 40 | stackTop = new chainNode(theElement, stackTop); 41 | ++stackSize; 42 | } 43 | private: 44 | chainNode* stackTop; //栈顶指针 45 | int stackSize; //元素个数 46 | }; 47 | 48 | //析构函数 49 | template 50 | linkedStack::~linkedStack() { 51 | while (stackTop != NULL) { 52 | chainNode* nextNode = stackTop->next; 53 | delete stackTop; 54 | stackTop = nextNode; 55 | } 56 | } 57 | 58 | //删除栈顶元素 59 | template 60 | void linkedStack::pop() { 61 | if (stackSize == 0) 62 | throw stackEmpty(); 63 | 64 | chainNode* nextNode = stackTop->next; 65 | delete stackTop; 66 | stackTop = nextNode; 67 | --stackSize; 68 | } 69 | 70 | #endif //DSACPP_LINKEDSTACK_H 71 | -------------------------------------------------------------------------------- /Chap8_Stack/stack.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/5. 3 | // 4 | 5 | #ifndef DSACPP_STACK_H 6 | #define DSACPP_STACK_H 7 | 8 | //抽象类栈 9 | template 10 | class Stack { 11 | public: 12 | virtual ~Stack() {} 13 | //判断栈是否为空 14 | virtual bool empty() const = 0; 15 | 16 | //返回栈中元素的个数 17 | virtual int size() const = 0; 18 | 19 | //返回栈顶元素的引用 20 | virtual T& top() = 0; 21 | 22 | //删除栈顶元素 23 | virtual void pop() = 0; 24 | 25 | //将元素theElement压入栈顶 26 | virtual void push(const T& theElement) = 0; 27 | }; 28 | 29 | #endif //DSACPP_STACK_H 30 | -------------------------------------------------------------------------------- /Chap8_Stack/test_arrayStack.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/5. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "arrayStack.h" 9 | 10 | using namespace std; 11 | 12 | int main() { 13 | std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); 14 | arrayStack s1; 15 | for (int i = 0; i < 100000000; ++i) 16 | s1.push(i); 17 | std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); 18 | std::chrono::duration time_used = std::chrono::duration_cast>(t2 - t1)*1000; 19 | std::cout << "Push 100 million integers using arrayStack: " << time_used.count() << " ms" << std::endl; 20 | 21 | t1 = std::chrono::high_resolution_clock::now(); 22 | stack s2; 23 | for (int i = 0; i < 100000000; ++i) 24 | s2.push(i); 25 | t2 = std::chrono::high_resolution_clock::now(); 26 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 27 | std::cout << "Push 100 million integers using stack: " << time_used.count() << " ms" << std::endl; 28 | 29 | t1 = std::chrono::high_resolution_clock::now(); 30 | for (int i = 0; i < 100000000; ++i) 31 | s1.pop(); 32 | t2 = std::chrono::high_resolution_clock::now(); 33 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 34 | std::cout << "Pop 100 million integers using arrayStack: " << time_used.count() << " ms" << std::endl; 35 | 36 | t1 = std::chrono::high_resolution_clock::now(); 37 | for (int i = 0; i < 100000000; ++i) 38 | s2.pop(); 39 | t2 = std::chrono::high_resolution_clock::now(); 40 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 41 | std::cout << "Pop 100 million integers using stack: " << time_used.count() << " ms" << std::endl; 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chap8_Stack/test_linkedStack.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/5. 3 | // 4 | 5 | #include 6 | #include 7 | #include "arrayStack.h" 8 | #include "linkedStack.h" 9 | 10 | using namespace std; 11 | 12 | int main() { 13 | std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); 14 | arrayStack s1; 15 | for (int i = 0; i < 100000000; ++i) 16 | s1.push(i); 17 | std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); 18 | std::chrono::duration time_used = std::chrono::duration_cast>(t2 - t1)*1000; 19 | std::cout << "Push 100 million integers using arrayStack: " << time_used.count() << " ms" << std::endl; 20 | 21 | t1 = std::chrono::high_resolution_clock::now(); 22 | linkedStack s2; 23 | for (int i = 0; i < 100000000; ++i) 24 | s2.push(i); 25 | t2 = std::chrono::high_resolution_clock::now(); 26 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 27 | std::cout << "Push 100 million integers using linkedStack: " << time_used.count() << " ms" << std::endl; 28 | 29 | t1 = std::chrono::high_resolution_clock::now(); 30 | for (int i = 0; i < 100000000; ++i) 31 | s1.pop(); 32 | t2 = std::chrono::high_resolution_clock::now(); 33 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 34 | std::cout << "Pop 100 million integers using arrayStack: " << time_used.count() << " ms" << std::endl; 35 | 36 | t1 = std::chrono::high_resolution_clock::now(); 37 | for (int i = 0; i < 100000000; ++i) 38 | s2.pop(); 39 | t2 = std::chrono::high_resolution_clock::now(); 40 | time_used = std::chrono::duration_cast>(t2 - t1)*1000; 41 | std::cout << "Pop 100 million integers using linkedStack: " << time_used.count() << " ms" << std::endl; 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chap9_Queue/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | add_executable(Chap9_Queue queue.h arrayQueue.h test_Queue.cpp linkedQueue.h) 6 | 7 | add_executable(Chap9_arrayDeque deque.h arrayDeque.h test_arrayDeque.cpp) -------------------------------------------------------------------------------- /Chap9_Queue/arrayDeque.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/7. 3 | // 4 | 5 | #ifndef DSACPP_ARRAYDEQUE_H 6 | #define DSACPP_ARRAYDEQUE_H 7 | 8 | #include 9 | #include 10 | #include "deque.h" 11 | #include "../MyExceptions.h" 12 | 13 | //用数组描述的双端队列,使用循环队列 14 | template 15 | class arrayDeque : public Deque { 16 | public: 17 | //构造函数和析构函数 18 | arrayDeque(int initCapacity = 10); 19 | ~arrayDeque() {delete [] deque;} 20 | 21 | //判空 22 | bool empty() const { return dequeFront == dequeEnd;} 23 | 24 | //返回元素个数 25 | int size() const { return (dequeEnd - dequeFront + arrayLength) % arrayLength;} 26 | 27 | //首元素的引用 28 | T& front() { 29 | if (dequeFront == dequeEnd) 30 | throw dequeEmpty(); 31 | return deque[dequeFront]; 32 | } 33 | 34 | //尾元素的引用 35 | T& back() { 36 | if (dequeFront == dequeEnd) 37 | throw dequeEmpty(); 38 | return deque[(dequeEnd - 1 + arrayLength) % arrayLength]; 39 | } 40 | 41 | //在头部插入和删除 42 | void push_front(const T& theElement); 43 | void pop_front(); 44 | 45 | //在尾部插入和删除 46 | void push_back(const T& theElement); 47 | void pop_back(); 48 | 49 | //清空 50 | void clear() { 51 | delete [] deque; 52 | dequeFront = dequeEnd = 0; 53 | } 54 | 55 | //随机访问迭代器 56 | class iterator { 57 | public: 58 | typedef random_access_iterator_tag iterator_category; // 随机访问迭代器 59 | typedef T value_type; //迭代器指向的数据类型 60 | typedef ptrdiff_t difference_type; // 标准库里一种与机器相关的数据类型,常用来表示两个指针相减的结果 61 | typedef T* pointer; //指针 62 | typedef T& reference; //引用 63 | 64 | //迭代器的构造函数 65 | iterator(T* thePosition = 0, int theIndex = 0, int theSize = 0) { 66 | position = thePosition; 67 | index = theIndex; 68 | size = theSize; 69 | } 70 | 71 | // 解引用操作符 72 | T& operator*() const {return *(position + index);} 73 | T* operator->() const {return &*(position + index);} 74 | 75 | // 迭代器的值增加 76 | iterator& operator++() {index = (index + 1) % size; return *this;} // 前置 77 | iterator operator++(int){ // 后置 78 | iterator old = *this; 79 | index = (index + 1) % size; 80 | return old; 81 | } 82 | iterator operator+(int n){ 83 | // +运算符, 实现随机访问 84 | iterator old = *this; 85 | old.index = (old.index + n) % size; 86 | return old; 87 | } 88 | iterator& operator+=(int n){index = (index + n) % size; return *this;} 89 | 90 | // 迭代器减少 91 | iterator& operator--() {index = (index - 1 + size) % size; return *this;} // 前置 92 | iterator operator--(int){ // 后置 93 | iterator old = *this; 94 | index = (index - 1 + size) % size;; 95 | return old; 96 | } 97 | iterator operator-(int n){ 98 | // -运算符,实现随机访问 99 | iterator old = *this; 100 | old.position = (old.index - n + size) % size; 101 | return old; 102 | } 103 | iterator& operator-=(int n) {index = (index - n + size) % size; return *this;} 104 | 105 | //测试是否相等 106 | bool operator!=(const iterator right) const {return (position + index) != (right.position + right.index);} 107 | bool operator==(const iterator right) const {return (position + index) == (right.position + right.index);} 108 | private: 109 | T *position; //指针 110 | int index, size; //相对位置,容量 111 | }; 112 | 113 | //返回首元素迭代器和尾元素下一个位置的迭代器 114 | iterator begin() { return iterator(deque, dequeFront, arrayLength);} 115 | iterator end() { return iterator(deque, dequeEnd, arrayLength);} 116 | 117 | private: 118 | void extend(); //数组装满时扩容,容量加倍 119 | int dequeFront; //首元素的下标 120 | int dequeEnd; //尾元素的下一个位置 121 | int arrayLength; //数组容量 122 | T* deque; //数组 123 | }; 124 | 125 | //构造函数 126 | template 127 | arrayDeque::arrayDeque(int initCapacity) { 128 | if (initCapacity < 1) { 129 | ostringstream s; 130 | s << "Initial capacity = " << initCapacity << " Must be > 0"; 131 | throw illegalParameterValue(s.str()); 132 | } 133 | arrayLength = initCapacity; 134 | deque = new T[arrayLength]; 135 | dequeFront = dequeEnd = 0; 136 | } 137 | 138 | //数组容量用完时进行扩展 139 | template 140 | void arrayDeque::extend() { 141 | //分配新的数组空间 142 | T* newDeque = new T[2 * arrayLength]; 143 | 144 | //把原数组的元素复制到新的数组中 145 | if (dequeFront < 2) 146 | //元素环不会被0位置截断 147 | copy(deque + dequeFront, deque + dequeFront + arrayLength - 1, newDeque); 148 | else { 149 | //元素环被0位置截断 150 | copy(deque + dequeFront, deque + arrayLength, newDeque); //复制前半部分 151 | copy(deque, deque + dequeEnd, newDeque + arrayLength - dequeFront); //复制后半部分 152 | } 153 | 154 | //设置新数组的首尾位置 155 | dequeFront = 0; 156 | dequeEnd = arrayLength - 1; 157 | arrayLength *= 2; 158 | delete [] deque; 159 | deque = newDeque; 160 | } 161 | 162 | //头部插入元素 163 | template 164 | void arrayDeque::push_front(const T &theElement) { 165 | //队列已满,扩容 166 | if ((dequeFront - 1 + arrayLength) % arrayLength == dequeEnd) 167 | extend(); 168 | 169 | //dequeFront前移,插入元素 170 | dequeFront = (dequeFront - 1 + arrayLength) % arrayLength; 171 | deque[dequeFront] = theElement; 172 | } 173 | 174 | //头部删除元素 175 | template 176 | void arrayDeque::pop_front() { 177 | if (dequeFront == dequeEnd) 178 | throw dequeEmpty(); 179 | deque[dequeFront % arrayLength].~T(); 180 | dequeFront = (dequeFront + 1) % arrayLength; 181 | } 182 | 183 | //尾部插入元素 184 | template 185 | void arrayDeque::push_back(const T &theElement) { 186 | //队列已满,扩容 187 | if ((dequeEnd + 1) % arrayLength == dequeFront) 188 | extend(); 189 | 190 | //插入元素,dequeEnd后移 191 | deque[dequeEnd] = theElement; 192 | dequeEnd = (dequeEnd + 1) % arrayLength; 193 | } 194 | 195 | //尾部删除元素 196 | template 197 | void arrayDeque::pop_back() { 198 | if (dequeFront == dequeEnd) 199 | throw dequeEmpty(); 200 | dequeEnd = (dequeEnd - 1 +arrayLength) % arrayLength; 201 | deque[dequeEnd].~T(); 202 | } 203 | 204 | 205 | #endif //DSACPP_ARRAYDEQUE_H 206 | -------------------------------------------------------------------------------- /Chap9_Queue/arrayQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/6. 3 | // 4 | 5 | #ifndef DSACPP_ARRAYQUEUE_H 6 | #define DSACPP_ARRAYQUEUE_H 7 | 8 | #include 9 | #include 10 | #include "queue.h" 11 | #include "../MyExceptions.h" 12 | 13 | //数组描述的队列,环形队列 14 | template 15 | class arrayQueue : public Queue { 16 | public: 17 | //构造和析构函数 18 | arrayQueue(int initCapacity = 10); 19 | ~arrayQueue() {delete [] queue;} 20 | 21 | //判断队列是否为空 22 | bool empty() const { return (queueFront == queueBack);} 23 | 24 | //队列元素的个数 25 | int size() const { return (queueBack - queueFront + arrayLength) % arrayLength;} 26 | 27 | //队首元素的引用 28 | T& front() { 29 | //队空,抛出异常 30 | if (queueFront == queueBack) 31 | throw queueEmpty(); 32 | return queue[(queueFront + 1) % arrayLength]; 33 | } 34 | 35 | //队尾元素的引用 36 | T& back() { 37 | //队空,抛出异常 38 | if (queueFront == queueBack) 39 | throw queueEmpty(); 40 | return queue[queueBack]; 41 | } 42 | 43 | //删除队首元素 44 | void pop() { 45 | if (queueFront == queueBack) 46 | throw queueEmpty(); 47 | queueFront = (queueFront + 1) % arrayLength; 48 | queue[queueFront].~T(); 49 | }; 50 | 51 | //在队尾插入元素 52 | void push(const T& theElement); 53 | private: 54 | int queueFront; //队首元素前一个位置的下标 55 | int queueBack; //队尾元素的下标 56 | int arrayLength; //队列的容量 57 | T* queue; //元素数组 58 | }; 59 | 60 | //构造函数 61 | template 62 | arrayQueue::arrayQueue(int initCapacity) { 63 | if (initCapacity < 1) { 64 | ostringstream s; 65 | s << "Initial capacity = " << initCapacity << " Must be > 0"; 66 | throw illegalParameterValue(s.str()); 67 | } 68 | arrayLength = initCapacity; 69 | queue = new T[arrayLength]; 70 | queueFront = queueBack = 0; 71 | } 72 | 73 | //插入元素 74 | template 75 | void arrayQueue::push(const T &theElement) { 76 | //队满,数组容量加倍 77 | if ((queueBack + 1) % arrayLength == queueFront) { 78 | //分配新的数组空间 79 | T* newQueue = new T[2 * arrayLength]; 80 | 81 | //将原数组元素复制到新数组 82 | int start = (queueFront + 1) % arrayLength; 83 | if (start < 2) 84 | //元素环不包含0位置 85 | copy(queue + start, queue + start + arrayLength - 1, newQueue); 86 | else { 87 | //分成前后两部分复制 88 | copy(queue + start, queue + arrayLength, newQueue); 89 | copy(queue, queue + queueBack + 1, newQueue + arrayLength - start); 90 | } 91 | 92 | //设置新数组的首和尾的元素位置 93 | queueFront = 2 *arrayLength - 1; 94 | queueBack = arrayLength - 2; 95 | arrayLength *= 2; 96 | delete [] queue; 97 | queue = newQueue; 98 | } 99 | 100 | //插入到队列尾部 101 | queueBack = (queueBack + 1) % arrayLength; 102 | queue[queueBack] = theElement; 103 | } 104 | 105 | #endif //DSACPP_ARRAYQUEUE_H 106 | -------------------------------------------------------------------------------- /Chap9_Queue/deque.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/7. 3 | // 4 | 5 | #ifndef DSACPP_DEQUE_H 6 | #define DSACPP_DEQUE_H 7 | 8 | //双端队列的抽象类 9 | template 10 | class Deque { 11 | public: 12 | //虚析构 13 | virtual ~Deque() {} 14 | 15 | //判断双端队列是否为空 16 | virtual bool empty() const = 0; 17 | 18 | //返回双端队列中元素个数 19 | virtual int size() const = 0; 20 | 21 | //双端队列首元素的引用 22 | virtual T& front() = 0; 23 | 24 | //双端队列尾元素的引用 25 | virtual T& back() = 0; 26 | 27 | //在双端队列的头部插入 28 | virtual void push_front(const T& theElement) = 0; 29 | 30 | //在双端队列的头部删除元素 31 | virtual void pop_front() = 0; 32 | 33 | //在双端队列的尾部插入 34 | virtual void push_back(const T& theElement) = 0; 35 | 36 | //在双端队列的尾部删除元素 37 | virtual void pop_back() = 0; 38 | 39 | //清空队列 40 | virtual void clear() = 0; 41 | }; 42 | 43 | 44 | #endif //DSACPP_DEQUE_H 45 | -------------------------------------------------------------------------------- /Chap9_Queue/linkedQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/7. 3 | // 4 | 5 | #ifndef DSACPP_LINKEDQUEUE_H 6 | #define DSACPP_LINKEDQUEUE_H 7 | 8 | #include "queue.h" 9 | #include "../Chap6_LinkedList/chainNode.h" 10 | #include "../MyExceptions.h" 11 | 12 | //链表描述的队列 13 | template 14 | class linkedQueue : public Queue { 15 | public: 16 | //构造和析构函数 17 | linkedQueue(int initCapacity = 10) {queueFront = NULL; queueSize = 0;} 18 | ~linkedQueue(); 19 | 20 | //判断是否为空 21 | bool empty() const { return queueSize == 0;} 22 | 23 | //返回元素个数 24 | int size() const { return queueSize;} 25 | 26 | //返回首元素的引用 27 | T& front() { 28 | if (queueSize == 0) 29 | throw queueEmpty(); 30 | return queueFront->element; 31 | } 32 | 33 | //返回尾元素的引用 34 | T& back() { 35 | if (queueSize == 0) 36 | throw queueEmpty(); 37 | return queueBack->element; 38 | } 39 | 40 | //插入和删除元素 41 | void push(const T& theElement); 42 | void pop(); 43 | private: 44 | chainNode *queueFront, *queueBack; //队列的首尾结点 45 | int queueSize; //元素个数 46 | }; 47 | 48 | //析构函数 49 | template 50 | linkedQueue::~linkedQueue() { 51 | while (queueFront != NULL) { 52 | chainNode *nextNode = queueFront->next; 53 | delete queueFront; 54 | queueFront = nextNode; 55 | } 56 | } 57 | 58 | //在队尾插入元素 59 | template 60 | void linkedQueue::push(const T &theElement) { 61 | //申请新元素结点 62 | chainNode *newNode = new chainNode(theElement, NULL); 63 | 64 | //把新结点插入队尾 65 | if (queueSize == 0) 66 | queueFront = newNode; 67 | else 68 | queueBack->next = newNode; 69 | queueBack = newNode; 70 | 71 | ++queueSize; 72 | } 73 | 74 | //删除元素 75 | template 76 | void linkedQueue::pop() { 77 | if (queueFront == NULL) 78 | throw queueEmpty(); 79 | 80 | chainNode *nextNode = queueFront->next; 81 | delete queueFront; 82 | queueFront = nextNode; 83 | --queueSize; 84 | } 85 | 86 | #endif //DSACPP_LINKEDQUEUE_H 87 | -------------------------------------------------------------------------------- /Chap9_Queue/queue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/6. 3 | // 4 | 5 | #ifndef DSACPP_QUEUE_H 6 | #define DSACPP_QUEUE_H 7 | 8 | //队列的抽象类 9 | template 10 | class Queue { 11 | public: 12 | virtual ~Queue() {} 13 | 14 | //队列为空,返回true 15 | virtual bool empty() const = 0; 16 | 17 | //返回队列里的元素个数 18 | virtual int size() const = 0; 19 | 20 | //返回队头元素的引用 21 | virtual T& front() = 0; 22 | 23 | //返回尾元素的引用 24 | virtual T& back() = 0; 25 | 26 | //删除首元素 27 | virtual void pop() = 0; 28 | 29 | //把元素theElement插入队尾 30 | virtual void push(const T& theElement) = 0; 31 | }; 32 | 33 | #endif //DSACPP_QUEUE_H 34 | -------------------------------------------------------------------------------- /Chap9_Queue/test_Queue.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/6. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "arrayQueue.h" 9 | #include "linkedQueue.h" 10 | 11 | using namespace std; 12 | 13 | int main() { 14 | chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now(); 15 | queue s1; 16 | for (int i = 0; i < 1000000; ++i) 17 | s1.push(i); 18 | chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now(); 19 | chrono::duration time_used = chrono::duration_cast>(t2 - t1)*1000; 20 | cout << "Push 1 million integers using queue: " << time_used.count() << " ms" << endl; 21 | 22 | t1 = chrono::high_resolution_clock::now(); 23 | arrayQueue s2; 24 | for (int i = 0; i < 1000000; ++i) 25 | s2.push(i); 26 | t2 = chrono::high_resolution_clock::now(); 27 | time_used = chrono::duration_cast>(t2 - t1)*1000; 28 | cout << "Push 1 million integers using arrayQueue: " << time_used.count() << " ms" << endl; 29 | 30 | t1 = chrono::high_resolution_clock::now(); 31 | linkedQueue s3; 32 | for (int i = 0; i < 1000000; ++i) 33 | s3.push(i); 34 | t2 = chrono::high_resolution_clock::now(); 35 | time_used = chrono::duration_cast>(t2 - t1)*1000; 36 | cout << "Push 1 million integers using linkedQueue: " << time_used.count() << " ms" << endl; 37 | 38 | t1 = chrono::high_resolution_clock::now(); 39 | for (int i = 0; i < 1000000; ++i) 40 | s1.pop(); 41 | t2 = chrono::high_resolution_clock::now(); 42 | time_used = chrono::duration_cast>(t2 - t1)*1000; 43 | cout << "Pop 1 million integers using queue: " << time_used.count() << " ms" << endl; 44 | 45 | t1 = chrono::high_resolution_clock::now(); 46 | for (int i = 0; i < 1000000; ++i) 47 | s2.pop(); 48 | t2 = chrono::high_resolution_clock::now(); 49 | time_used = chrono::duration_cast>(t2 - t1)*1000; 50 | cout << "Pop 1 million integers using arrayQueue: " << time_used.count() << " ms" << endl; 51 | 52 | t1 = chrono::high_resolution_clock::now(); 53 | for (int i = 0; i < 1000000; ++i) 54 | s3.pop(); 55 | t2 = chrono::high_resolution_clock::now(); 56 | time_used = chrono::duration_cast>(t2 - t1)*1000; 57 | cout << "Pop 1 million integers using linkedQueue: " << time_used.count() << " ms" << endl; 58 | return 0; 59 | } -------------------------------------------------------------------------------- /Chap9_Queue/test_arrayDeque.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019/11/7. 3 | // 4 | 5 | #include 6 | #include "arrayDeque.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | arrayDeque de; 12 | for(int i = 0; i < 25; ++i) { 13 | de.push_front(25 - i - 1); 14 | de.push_back(25 + i); 15 | } 16 | 17 | for (auto i = de.begin(); i != de.end(); ++i) 18 | cout << *i << " "; 19 | cout << endl; 20 | for (int i = 0; i < 5; ++i) { 21 | de.pop_front(); 22 | de.pop_back(); 23 | } 24 | 25 | for (auto i = de.begin(); i != de.end(); ++i) 26 | cout << *i << " "; 27 | return 0; 28 | } -------------------------------------------------------------------------------- /MyExceptions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by perry on 2019-09-04. 3 | // 4 | 5 | #ifndef DSACPP_MYEXCEPTIONS_H 6 | #define DSACPP_MYEXCEPTIONS_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | // illegal parameter value 14 | class illegalParameterValue 15 | { 16 | public: 17 | illegalParameterValue(string theMessage = "Illegal parameter value") 18 | {message = theMessage;} 19 | void outputMessage() {cout << message << endl;} 20 | private: 21 | string message; 22 | }; 23 | 24 | // illegal input data 25 | class illegalInputData 26 | { 27 | public: 28 | illegalInputData(string theMessage = "Illegal data input") 29 | {message = theMessage;} 30 | void outputMessage() {cout << message << endl;} 31 | private: 32 | string message; 33 | }; 34 | 35 | // illegal index 36 | class illegalIndex 37 | { 38 | public: 39 | illegalIndex(string theMessage = "Illegal index") 40 | {message = theMessage;} 41 | void outputMessage() {cout << message << endl;} 42 | private: 43 | string message; 44 | }; 45 | 46 | // matrix index out of bounds 47 | class matrixIndexOutOfBounds 48 | { 49 | public: 50 | matrixIndexOutOfBounds 51 | (string theMessage = "Matrix index out of bounds") 52 | {message = theMessage;} 53 | void outputMessage() {cout << message << endl;} 54 | private: 55 | string message; 56 | }; 57 | 58 | // matrix size mismatch 59 | class matrixSizeMismatch 60 | { 61 | public: 62 | matrixSizeMismatch(string theMessage = 63 | "The size of the two matrics doesn't match") 64 | {message = theMessage;} 65 | void outputMessage() {cout << message << endl;} 66 | private: 67 | string message; 68 | }; 69 | 70 | // stack is empty 71 | class stackEmpty 72 | { 73 | public: 74 | stackEmpty(string theMessage = 75 | "Invalid operation on empty stack") 76 | {message = theMessage;} 77 | void outputMessage() {cout << message << endl;} 78 | private: 79 | string message; 80 | }; 81 | 82 | // queue is empty 83 | class queueEmpty 84 | { 85 | public: 86 | queueEmpty(string theMessage = 87 | "Invalid operation on empty queue") 88 | {message = theMessage;} 89 | void outputMessage() {cout << message << endl;} 90 | private: 91 | string message; 92 | }; 93 | 94 | // deque is empty 95 | class dequeEmpty 96 | { 97 | public: 98 | dequeEmpty(string theMessage = 99 | "Invalid operation on empty queue") 100 | {message = theMessage;} 101 | void outputMessage() {cout << message << endl;} 102 | private: 103 | string message; 104 | }; 105 | 106 | // hash table is full 107 | class hashTableFull 108 | { 109 | public: 110 | hashTableFull(string theMessage = 111 | "The hash table is full") 112 | {message = theMessage;} 113 | void outputMessage() {cout << message << endl;} 114 | private: 115 | string message; 116 | }; 117 | 118 | // edge weight undefined 119 | class undefinedEdgeWeight 120 | { 121 | public: 122 | undefinedEdgeWeight(string theMessage = 123 | "No edge weights defined") 124 | {message = theMessage;} 125 | void outputMessage() {cout << message << endl;} 126 | private: 127 | string message; 128 | }; 129 | 130 | // method undefined 131 | class undefinedMethod 132 | { 133 | public: 134 | undefinedMethod(string theMessage = 135 | "This method is undefined") 136 | {message = theMessage;} 137 | void outputMessage() {cout << message << endl;} 138 | private: 139 | string message; 140 | }; 141 | 142 | #endif //DSACPP_MYEXCEPTIONS_H 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | ![](images/dsa_a.jpg)![](images/dsa_b.jpg) 3 | 4 | - 章节目录 5 | 6 | ``` 7 | . 8 | ├── Chap10_SkipAndHashTable 9 | │   ├── dictionary.h 10 | │   ├── hashChain.h 11 | │   ├── hashTable.h 12 | │   ├── skipList.h 13 | │   └── sortedChain.h 14 | ├── Chap11_BinaryTree 15 | │   ├── advancedUnion.h 16 | │   ├── binaryTree.h 17 | │   └── linkedBinaryTree.h 18 | ├── Chap12_PriorityQueue 19 | │   ├── heapSort.h 20 | │   ├── huffmanTree.h 21 | │   ├── maxHblt.h 22 | │   ├── maxHeap.h 23 | │   ├── maxPriorityQueue.h 24 | │   ├── maxWblt.h 25 | │   └── minHeap.h 26 | ├── Chap13_TouranmentTree 27 | │   ├── completeWinnerTree.h 28 | │   └── winnerTree.h 29 | ├── Chap14_SearchTree 30 | │   ├── binarySearchTree.h 31 | │   ├── bsTree.h 32 | │   ├── indexBSTree.h 33 | │   └── indexBinarySearchTree.h 34 | ├── Chap5_ArrayList 35 | │   ├── arrayList.h 36 | │   ├── linearList.h 37 | │   └── vectorList.h 38 | ├── Chap6_LinkedList 39 | │   ├── chain.h 40 | │   ├── circularListWithHeader.h 41 | │   ├── doublyLinkedListWithHeader.h 42 | │   ├── extendedChain.h 43 | │   └── extendedLinearList.h 44 | ├── Chap7_Matrix 45 | │   ├── matrix.h 46 | │   └── spareMatrix.h 47 | ├── Chap8_Stack 48 | │   ├── arrayStack.h 49 | │   ├── linkedStack.h 50 | │   └── stack.h 51 | ├── Chap9_Queue 52 | │   ├── arrayDeque.h 53 | │   ├── arrayQueue.h 54 | │   ├── deque.h 55 | │   ├── linkedQueue.h 56 | │   └── queue.h 57 | └── MyExceptions.h 58 | ``` 59 | 60 | - 欢迎大家指出我代码中的错误。 61 | 62 | # PDF资源 63 | 64 | ### 中文PDF 65 | 66 | - 链接:https://pan.baidu.com/s/1IiQhaZJlUnvXlUJbFUpeiQ 提取码: 2d6t 67 | 68 | ### 英文PDF 69 | 70 | - 链接:https://pan.baidu.com/s/1yTWwV8HXwljabvafY6UbPA 提取码:sqgg 71 | 72 | -------------------------------------------------------------------------------- /images/dsa_a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Perry961002/DSACPP/7e79bd9e49fac8b8e4d17f2ec2faac8f6acf5f72/images/dsa_a.jpg -------------------------------------------------------------------------------- /images/dsa_b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Perry961002/DSACPP/7e79bd9e49fac8b8e4d17f2ec2faac8f6acf5f72/images/dsa_b.jpg --------------------------------------------------------------------------------