├── .gitignore ├── README.md ├── lib ├── dsexceptions.h ├── matrix.h ├── my_random.cpp ├── my_random.h └── uniform_random.h ├── part1 ├── CMakeLists.txt ├── IntCell.cpp ├── IntCell.h ├── IntCellTest.cpp ├── LambdaExample.cpp ├── findMax.cpp ├── matrix.h ├── matrixTest.cpp ├── printDigits.cpp ├── square.h └── squareTest.cpp ├── part10 ├── CMakeLists.txt ├── is_prime.cpp ├── random.hpp └── random_test.cpp ├── part11 ├── CMakeLists.txt ├── splay_tree.hpp └── splay_tree_test.cpp ├── part12 ├── CMakeLists.txt ├── kd_tree.hpp ├── kd_tree_test.cpp ├── pairing_heap.hpp ├── pairing_heap_test.cpp ├── rb_tree.hpp ├── rb_tree_test.cpp ├── treap.hpp └── treap_test.cpp ├── part2 ├── CMakeLists.txt ├── binarySearch.h ├── binarySearchTest.cpp ├── maxSumTest.cpp └── pow.cpp ├── part3 ├── CMakeLists.txt ├── List.h ├── Queue.h ├── Stack.h ├── Vector.h ├── VectorTest.cpp ├── finalTest.cpp ├── remove2.cpp └── removeEveryOtherItem.cpp ├── part4 ├── CMakeLists.txt ├── avl_tree.hpp ├── avl_tree_test.cpp ├── binary_search_tree.hpp ├── binary_search_tree_test.cpp ├── dict.txt └── word_ladder.cpp ├── part5 ├── CMakeLists.txt ├── cuckoo_hash.hpp ├── cuckoo_hash_test.cpp ├── quadratic_probing.hpp ├── quadratic_probing_test.cpp ├── separate_chaining.hpp ├── separate_chaining_test.cpp └── use_of_unordered_set.cpp ├── part6 ├── CMakeLists.txt ├── binary_heap.hpp ├── binary_heap_test.cpp ├── binomial_queue.hpp ├── binomial_queue_test.cpp ├── left_heap.hpp ├── left_heap_test.cpp └── priority_queue_test.cpp ├── part7 ├── CMakeLists.txt ├── radix_sort.cpp ├── sort.hpp └── sort_test.cpp ├── part8 ├── CMakeLists.txt ├── disjoint_set.hpp └── disjoint_set_test.cpp └── part9 ├── CMakeLists.txt ├── dict.txt └── word_ladder.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *build*/ 2 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data Structures And Algorithm Analysis in C++ (4th) 2 | - 数据结构与算法分析第四版(C++) 3 | - 参考源码,数据结构实现与理解 4 | - Mark Allen Weiss 5 | - [Source Code 书源码](https://users.cs.fiu.edu/~weiss/dsaa_c++4/code/) 6 | - [红黑树分析](https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/03.01.md) -------------------------------------------------------------------------------- /lib/dsexceptions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/8/25. 3 | // 4 | 5 | #ifndef __DS_EXCEPTIONS_H__ 6 | #define __DS_EXCEPTIONS_H__ 7 | 8 | namespace DS 9 | { 10 | class UnderflowException { }; 11 | class IllegalArgumentException { }; 12 | class ArrayIndexOutOfBoundsException { }; 13 | class IteratorOutOfBoundsException { }; 14 | class IteratorMismatchException { }; 15 | class IteratorUninitializedException { }; 16 | } 17 | 18 | #endif //__DS_EXCEPTIONS_H__ 19 | -------------------------------------------------------------------------------- /lib/matrix.h: -------------------------------------------------------------------------------- 1 | /// @file matrix.h 2 | /// @date 2019-02-24 17:38:08 3 | 4 | #ifndef __MATRIX_H__ 5 | #define __MATRIX_H__ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | template 12 | class Matrix 13 | { 14 | public: 15 | Matrix(int rows, int cols) 16 | :array_(rows, std::vector(cols, Object{})) 17 | {} 18 | 19 | Matrix(std::initializer_list> lst) 20 | :array_(lst.size()) 21 | { 22 | int i = 0; 23 | for(auto& v : lst) 24 | array_[i++] = std::move(v); 25 | } 26 | 27 | Matrix(const std::vector>& v) 28 | :array_{v} 29 | {} 30 | 31 | Matrix(std::vector>&& v) 32 | :array_{std::move(v)} 33 | {} 34 | 35 | ~Matrix() = default; 36 | 37 | const std::vector& operator[] (int row) const 38 | { 39 | return array_[row]; 40 | } 41 | 42 | std::vector& operator[] (int row) 43 | { 44 | return array_[row]; 45 | } 46 | 47 | std::size_t numrows() const 48 | { 49 | return array_.size(); 50 | } 51 | 52 | std::size_t numcols() const 53 | { 54 | return numrows() ? array_[0].size() : 0; 55 | } 56 | 57 | private: 58 | std::vector> array_; 59 | }; 60 | 61 | template 62 | std::ostream& operator<< (std::ostream& os, const Matrix& mat) 63 | { 64 | os << '[' << std::endl; 65 | for(std::size_t row = 0; row < mat.numrows(); ++row) 66 | { 67 | os << " " << '['; 68 | for(std::size_t col = 0; col < mat.numcols(); ++col) 69 | { 70 | os << mat[row][col] << ' '; 71 | } 72 | os << ']' << std::endl; 73 | } 74 | os << ']'; 75 | return os; 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /lib/my_random.cpp: -------------------------------------------------------------------------------- 1 | #include "my_random.h" 2 | 3 | namespace DS 4 | { 5 | static const int A = 48271; 6 | static const int M = 2147483647; 7 | static const int Q = M / A; 8 | static const int R = M % A; 9 | 10 | // Construct with initialValue for the state. 11 | Random::Random(int init_val) 12 | { 13 | if(init_val < 0) 14 | init_val += M; 15 | state = init_val; 16 | if(state == 0) 17 | state = 1; 18 | } 19 | 20 | // Return a pseudorandom int, and change the internal state 21 | int Random::randomInt() 22 | { 23 | int tmp_state = A * (state % Q) - R * (state / Q); 24 | if(tmp_state >= 0) 25 | state = tmp_state; 26 | else 27 | state = tmp_state + M; 28 | return state; 29 | } 30 | 31 | // Return an int in the closed range [low,high], and 32 | // change the internal state. This is a poor implementation and 33 | // will be biased toward some numbers, especially if the range is large. 34 | int Random::randomInt(int low, int high) 35 | { 36 | double partition_size = static_cast(M) / (high - low + 1); 37 | return static_cast(randomInt() / partition_size) + low; 38 | } 39 | 40 | // Return a pseudorandom double in the open range 0..1 41 | // and change the internal state. 42 | double Random::random() 43 | { 44 | return static_cast(randomInt()) / M; 45 | } 46 | 47 | // Return a pseudorandom int, and change the 48 | // internal state. DOES NOT WORK. 49 | int Random::randomIntWRONG() 50 | { 51 | return state = (A * state) % M; 52 | } 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /lib/my_random.h: -------------------------------------------------------------------------------- 1 | #ifndef _MY_RANDOM_H 2 | #define _MY_RANDOM_H 3 | 4 | #include 5 | // Random class 6 | // This code assumes 32-bit ints 7 | // 8 | // CONSTRUCTION: with (a) no initializer or (b) an integer 9 | // that specifies the initial state of the generator 10 | // 11 | // ******************PUBLIC OPERATIONS********************* 12 | // Return a random number according to some distribution: 13 | // int randomInt( ) --> Uniform, 1 to 2^31-1 14 | // int random( ) --> Uniform, 0 to 1 15 | // int randomInt( int low, int high ) --> Uniform low..high 16 | 17 | namespace DS 18 | { 19 | class Random 20 | { 21 | public: 22 | explicit Random(int init_val = 1); 23 | int randomInt(); // Uniform, 1 to 2^31-1 24 | int randomInt(int low, int high); // Uniform [low..high] 25 | double random(); // Uniform, [0, 1] 26 | int randomIntWRONG(); 27 | private: 28 | int state; 29 | }; 30 | } 31 | #endif //_MY_RANDOM_H 32 | -------------------------------------------------------------------------------- /lib/uniform_random.h: -------------------------------------------------------------------------------- 1 | #ifndef UNIFORM_RANDOM 2 | #define UNIFORM_RANDOM 3 | 4 | //#include 5 | //using namespace std; 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | // UniformRandom class 14 | // 15 | // CONSTRUCTION: with (a) no initializer or (b) a long 16 | // that specifies the initial state of the generator. 17 | // This random number generator is similar to 18 | // drand48 in C/C++. 19 | // 20 | // ******************PUBLIC OPERATIONS********************* 21 | // Return a random number according to some distribution: 22 | // int nextInt( ) --> Uniform 23 | // int nextDouble( ) --> Uniform, [0 to 1) 24 | // int nextInt( int high ) --> Uniform [0..high) 25 | // int nextInt( int low, int high ) --> Uniform [low..high) 26 | // long nextLong( ) --> Uniform 27 | 28 | /** 29 | * Uniform Random Number generator class, using a 48-bit 30 | * linear congruential generator. 31 | */ 32 | namespace DS { 33 | 34 | class Random48 { 35 | private: 36 | static long long currentTimeMicroSeconds() { 37 | auto now = chrono::high_resolution_clock::now().time_since_epoch(); 38 | return (chrono::duration_cast(now)).count(); 39 | } 40 | 41 | public: 42 | /** 43 | * Construct this Random object with specified initial state 44 | */ 45 | Random48(long long initialValue = currentTimeMicroSeconds()) { 46 | state = initialValue & MASK; 47 | } 48 | 49 | 50 | /** 51 | * Return a pseudorandom int, and change the 52 | * internal state. 53 | */ 54 | int nextInt() { 55 | return next(32); 56 | } 57 | 58 | /** 59 | * Return a pseudorandom int in range [0..high), 60 | * and change the internal state. 61 | */ 62 | int nextInt(int high) { 63 | return static_cast( abs(nextLong() % high)); 64 | } 65 | 66 | /** 67 | * Return a pseudorandom double in the range [0..1) 68 | * and change the internal state. 69 | */ 70 | double nextDouble() { 71 | return ((static_cast((next(26))) << 27) + next(27)) 72 | / static_cast( 1LL << 53 ); 73 | } 74 | 75 | /** 76 | * Return an int in the closed range [low,high], and 77 | * change the internal state. 78 | */ 79 | int nextInt(int low, int high) { 80 | return nextInt(high - low + 1) + low; 81 | } 82 | 83 | /** 84 | * Return a 64-bit long, and change the internal state. 85 | * Note that all longs can be generated. 86 | */ 87 | long long nextLong() { 88 | return ((static_cast( next(32))) << 32) + next(32); 89 | } 90 | 91 | private: 92 | long long state; 93 | 94 | static const long long A = 25214903917LL; 95 | static const long long C = 11; 96 | static const long long M = (1LL << 48); 97 | static const long long MASK = M - 1; 98 | 99 | /** 100 | * Return specified number of random bits 101 | */ 102 | int next(int bits) { 103 | state = (A * state + C) & MASK; 104 | 105 | return state >> (48 - bits); 106 | } 107 | }; 108 | 109 | // UniformRandom class 110 | // 111 | // CONSTRUCTION: with (a) no initializer or (b) a int 112 | // that specifies the initial state of the generator. 113 | // This random number generator uses the 32-bit Mersenne Twister 114 | // 115 | // ******************PUBLIC OPERATIONS********************* 116 | // Return a random number according to some distribution: 117 | // int nextInt( ) --> Uniform 118 | // int nextDouble( ) --> Uniform, [0 to 1) 119 | // int nextInt( int high ) --> Uniform [0..high) 120 | // int nextInt( int low, int high ) --> Uniform [low..high) 121 | 122 | 123 | static int currentTimeSeconds() { 124 | auto now = chrono::high_resolution_clock::now().time_since_epoch(); 125 | return chrono::duration_cast(now).count(); 126 | } 127 | 128 | /** 129 | * Uniform Random Number generator class, using C++ Mersenne Twister. 130 | */ 131 | class UniformRandom { 132 | public: 133 | UniformRandom(int seed = currentTimeSeconds()) : generator{seed} { 134 | } 135 | 136 | /** 137 | * Return a pseudorandom int. 138 | */ 139 | int nextInt() { 140 | static uniform_int_distribution distribution; 141 | return distribution(generator); 142 | } 143 | 144 | /** 145 | * Return a pseudorandom int in range [0..high). 146 | */ 147 | int nextInt(int high) { 148 | return nextInt(0, high - 1); 149 | } 150 | 151 | /** 152 | * Return a pseudorandom double in the range [0..1). 153 | */ 154 | double nextDouble() { 155 | static uniform_real_distribution distribution(0, 1); 156 | return distribution(generator); 157 | } 158 | 159 | /** 160 | * Return an int in the closed range [low,high]. 161 | */ 162 | int nextInt(int low, int high) { 163 | uniform_int_distribution distribution(low, high); 164 | return distribution(generator); 165 | } 166 | 167 | private: 168 | mt19937 generator; 169 | }; 170 | } 171 | #endif 172 | 173 | -------------------------------------------------------------------------------- /part1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART1) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") 5 | 6 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 7 | 8 | # find_max 9 | set(DEMO "findMax") 10 | add_executable(${DEMO} ${DEMO}.cpp) 11 | 12 | # IntCell 13 | set(DEMO "IntCell") 14 | set(SOURCE 15 | ${DEMO}Test.cpp 16 | ${DEMO}.h 17 | ${DEMO}.cpp) 18 | add_executable(${DEMO} ${SOURCE}) 19 | 20 | # LambdaExample 21 | set(DEMO "LambdaExample") 22 | set(SOURCE ${DEMO}.cpp) 23 | add_executable(${DEMO} ${SOURCE}) 24 | 25 | # matrix 26 | set(DEMO "matrix") 27 | set(SOURCE 28 | ${DEMO}Test.cpp 29 | ${DEMO}.h) 30 | add_executable(${DEMO} ${SOURCE}) 31 | 32 | # printDigits 33 | add_executable(printDigits printDigits.cpp) 34 | 35 | # square 36 | set(DEMO "square") 37 | set(SOURCE 38 | ${DEMO}Test.cpp 39 | ${DEMO}.h) 40 | add_executable(${DEMO} ${SOURCE}) -------------------------------------------------------------------------------- /part1/IntCell.cpp: -------------------------------------------------------------------------------- 1 | /// @file IntCell.cpp 2 | 3 | #include "IntCell.h" 4 | #include 5 | 6 | /* construct */ 7 | IntCell::IntCell(int initialValue): 8 | storedValue_{initialValue} 9 | {} 10 | 11 | /* read */ 12 | int IntCell::read() const 13 | { 14 | return storedValue_; 15 | } 16 | 17 | /* stored */ 18 | void IntCell::write(int x) 19 | { 20 | storedValue_ = x; 21 | } 22 | 23 | // version 2 24 | // construction 25 | IntCellPtr::IntCellPtr(int initialValue): 26 | storedValue_{new int{initialValue}} 27 | {} 28 | // deconstructor 29 | IntCellPtr::~IntCellPtr() 30 | { 31 | delete storedValue_; 32 | } 33 | // copy 34 | IntCellPtr::IntCellPtr(const IntCellPtr& rhs): 35 | storedValue_{new int{*rhs.storedValue_}} 36 | {} 37 | // move 38 | IntCellPtr::IntCellPtr(IntCellPtr&& rhs): 39 | storedValue_{rhs.storedValue_} 40 | { 41 | rhs.storedValue_ = nullptr; 42 | } 43 | // = copy 44 | IntCellPtr& IntCellPtr::operator= (const IntCellPtr& rhs) 45 | { 46 | if(this != &rhs) // self copy 47 | *storedValue_ = *rhs.storedValue_; 48 | return *this; 49 | } 50 | // = move 51 | IntCellPtr& IntCellPtr::operator= (IntCellPtr&& rhs) 52 | { 53 | std::swap(storedValue_, rhs.storedValue_); 54 | return *this; 55 | } 56 | // read 57 | int IntCellPtr::read() const 58 | { 59 | return *storedValue_; 60 | } 61 | // store 62 | void IntCellPtr::write(int x) 63 | { 64 | *storedValue_ = x; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /part1/IntCell.h: -------------------------------------------------------------------------------- 1 | /// @file IntCell.h 2 | 3 | #ifndef __INTCELL_H__ 4 | #define __INTCELL_H__ 5 | 6 | /** 7 | * 一个模拟整数单元的类 8 | */ 9 | class IntCell 10 | { 11 | public: 12 | // 使用explicit禁止隐式类型转换 13 | // int->IntCell 是禁止的 14 | explicit IntCell(int initialValue = 0); 15 | int read() const; 16 | void write(int x); 17 | 18 | private: 19 | int storedValue_; 20 | }; 21 | 22 | // version 2 23 | class IntCellPtr 24 | { 25 | public: 26 | explicit IntCellPtr(int initialValue = 0); 27 | ~IntCellPtr(); 28 | IntCellPtr(const IntCellPtr& rhs); 29 | IntCellPtr(IntCellPtr&& rhs); 30 | IntCellPtr& operator= (const IntCellPtr& rhs); 31 | IntCellPtr& operator= (IntCellPtr&& rhs); 32 | int read() const; 33 | void write(int x); 34 | private: 35 | int *storedValue_; 36 | }; 37 | #endif 38 | -------------------------------------------------------------------------------- /part1/IntCellTest.cpp: -------------------------------------------------------------------------------- 1 | /// @file TestIntCell.cpp 2 | 3 | #include "IntCell.h" 4 | #include 5 | 6 | using std::cin; 7 | using std::cout; 8 | using std::endl; 9 | 10 | int main(int argc, char **argv) 11 | { 12 | IntCell m; 13 | m.write(5); 14 | cout << "Cell contents: " << m.read() << endl; 15 | IntCellPtr pm; 16 | cout << "Cell ptr contents: " << pm.read() << endl; 17 | pm.write(3); 18 | IntCellPtr pm2{pm}; 19 | cout << "Cell ptr contents: " << pm2.read() << endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /part1/LambdaExample.cpp: -------------------------------------------------------------------------------- 1 | /// @file LambdaExample.cpp 2 | 3 | // copy from source code 4 | // using lambda 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using std::cin; 12 | using std::cout; 13 | using std::endl; 14 | using std::vector; 15 | using std::string; 16 | 17 | // Generic findMax, with a function object, C++ style. 18 | template 19 | const Object& findMax( const vector & arr, Comparator isLessThan ) 20 | { 21 | int maxIndex = 0; 22 | 23 | for( std::size_t i = 1; i < arr.size( ); ++i ) 24 | if( isLessThan( arr[ maxIndex ], arr[ i ] ) ) 25 | maxIndex = i; 26 | 27 | return arr[ maxIndex ]; 28 | 29 | } 30 | 31 | template 32 | const Object& findMax( const vector & arr ) 33 | { 34 | return findMax( arr, std::less( ) ); 35 | } 36 | 37 | int main(int argc, char** argv) 38 | { 39 | vector arr = { "ZEBRA", "alligator", "crocodile" }; 40 | cout << findMax(arr, 41 | [](const string& lhs, const string& rhs) {return strcmp(lhs.c_str(), rhs.c_str()) < 0; }) 42 | << endl; 43 | cout << findMax(arr) << endl; 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /part1/findMax.cpp: -------------------------------------------------------------------------------- 1 | /// @file findMax.cpp 2 | /// @date 2019-02-24 16:59:45 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using std::cin; 9 | using std::cout; 10 | using std::endl; 11 | using std::string; 12 | using std::vector; 13 | 14 | template 15 | const Comparable& findMax(const vector& a) 16 | { 17 | int max_idx = 0; 18 | for(std::size_t i = 1; i < a.size(); ++i) 19 | if(a[max_idx] < a[i]) 20 | max_idx = i; 21 | return a[max_idx]; 22 | } 23 | 24 | int main(int argc, char** argv) 25 | { 26 | vector v1 = { 3, 5, 8, 2, 4 }; 27 | vector v2 = { 2.9, 5.4, 2.1, 3.3 }; 28 | vector v3 = { "hello", "world", "apple" }; 29 | /* 30 | * vector v4(75)p 31 | * can't use findMax(v4) 32 | * because IntCellPtr need to define operator 33 | * as it member storedValue is int* 34 | */ 35 | 36 | cout << findMax(v1) << endl; 37 | cout << findMax(v2) << endl; 38 | cout << findMax(v3) << endl; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /part1/matrix.h: -------------------------------------------------------------------------------- 1 | /// @file matrix.h 2 | /// @date 2019-02-24 17:38:08 3 | 4 | #ifndef __MATRIX_H__ 5 | #define __MATRIX_H__ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | template 12 | class Matrix 13 | { 14 | public: 15 | Matrix(int rows, int cols) 16 | :array_(rows, std::vector(cols, Object{})) 17 | {} 18 | 19 | Matrix(std::initializer_list> lst) 20 | :array_(lst.size()) 21 | { 22 | int i = 0; 23 | for(auto& v : lst) 24 | array_[i++] = std::move(v); 25 | } 26 | 27 | Matrix(const std::vector>& v) 28 | :array_{v} 29 | {} 30 | 31 | Matrix(std::vector>&& v) 32 | :array_{std::move(v)} 33 | {} 34 | 35 | ~Matrix() = default; 36 | 37 | const std::vector& operator[] (int row) const 38 | { 39 | return array_[row]; 40 | } 41 | 42 | std::vector& operator[] (int row) 43 | { 44 | return array_[row]; 45 | } 46 | 47 | std::size_t numrows() const 48 | { 49 | return array_.size(); 50 | } 51 | 52 | std::size_t numcols() const 53 | { 54 | return numrows() ? array_[0].size() : 0; 55 | } 56 | 57 | private: 58 | std::vector> array_; 59 | }; 60 | 61 | template 62 | std::ostream& operator<< (std::ostream& os, const Matrix& mat) 63 | { 64 | os << '[' << std::endl; 65 | for(std::size_t row = 0; row < mat.numrows(); ++row) 66 | { 67 | os << " " << '['; 68 | for(std::size_t col = 0; col < mat.numcols(); ++col) 69 | { 70 | os << mat[row][col] << ' '; 71 | } 72 | os << ']' << std::endl; 73 | } 74 | os << ']'; 75 | return os; 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /part1/matrixTest.cpp: -------------------------------------------------------------------------------- 1 | /// @file matrixTest.cpp 2 | /// @date 2019-02-24 18:11:52 3 | 4 | #include "matrix.h" 5 | #include 6 | 7 | using std::cin; 8 | using std::cout; 9 | using std::endl; 10 | 11 | int main(int argc, char** argv) 12 | { 13 | Matrix mat(4,4); 14 | Matrix mat2({ 15 | {1,2,3,4}, 16 | {5,6,7,8}, 17 | {9,10,11,12}, 18 | {13,14,15,16} 19 | }); 20 | cout << mat << endl; 21 | cout << mat2 << endl; 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /part1/printDigits.cpp: -------------------------------------------------------------------------------- 1 | /// @file 1_02.cpp 2 | 3 | #include 4 | using std::cin; 5 | using std::cout; 6 | using std::endl; 7 | 8 | inline void printDigit(int n) 9 | { 10 | cout << n; 11 | } 12 | 13 | void printOut(int n) 14 | { 15 | if(n >= 10) 16 | printOut(n / 10); 17 | printDigit(n % 10); 18 | } 19 | 20 | int main(int argc, char** argv) 21 | { 22 | printOut(1369); 23 | cout << endl; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /part1/square.h: -------------------------------------------------------------------------------- 1 | /// @file square.h 2 | 3 | #ifndef __SQUARE_H__ 4 | #define __SQUARE_H__ 5 | 6 | #include 7 | #include 8 | 9 | class Square 10 | { 11 | public: 12 | explicit Square(double s = 0.0) 13 | :side_{s} 14 | {} 15 | 16 | double getSide() const 17 | { return side_; } 18 | 19 | double getArea() const 20 | { return side_ * side_; } 21 | 22 | double getPerimeter() const 23 | { return 4 * side_; } 24 | 25 | void print(std::ostream& os = std::cout) const 26 | { os << "(square" << getSide() << ")"; } 27 | 28 | bool operator< (const Square& rhs) const 29 | { return getSide() < rhs.getSide(); } 30 | 31 | bool operator> (const Square& rhs) const 32 | { return getSide() > rhs.getSide(); } 33 | 34 | private: 35 | double side_; 36 | }; 37 | 38 | std::ostream& operator<< (std::ostream& out, const Square& rhs) 39 | { 40 | rhs.print(out); 41 | return out; 42 | } 43 | 44 | // swap -> 使用move机制 45 | void mySwap(Square& lhs, Square& rhs) 46 | { 47 | Square tmp = static_cast(lhs); 48 | lhs = static_cast(rhs); 49 | rhs = static_cast(tmp); 50 | } 51 | 52 | template 53 | const Comparable& findMax(const std::vector& a) 54 | { 55 | int maxIdx = 0; 56 | for(std::size_t i = 0; i < a.size(); ++i) 57 | { 58 | if(a[maxIdx] < a[i]) 59 | maxIdx = i; 60 | } 61 | return a[maxIdx]; 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /part1/squareTest.cpp: -------------------------------------------------------------------------------- 1 | /// @file square_test.cpp 2 | /// @date 2019-02-24 20:49:13 3 | #include "square.h" 4 | #include 5 | #include 6 | 7 | using std::cin; 8 | using std::cout; 9 | using std::endl; 10 | using std::vector; 11 | 12 | int main( ) 13 | { 14 | vector v = { Square{ 3.0 }, Square{ 2.0 }, Square{ 2.5 } }; 15 | cout << "Largest square: " << findMax( v ) << endl; 16 | for(std::size_t i = 0; i < v.size(); ++i) 17 | { 18 | cout << v[i] << " "; 19 | } 20 | cout << endl; 21 | mySwap(v[0], v[1]); 22 | for(std::size_t i = 0; i < v.size(); ++i) 23 | { 24 | cout << v[i] << " "; 25 | } 26 | cout << endl; 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /part10/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART10) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | elseif(${CMAKE_BUILD_TYPE} MATCHES Release) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Using [Release] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # random 15 | add_executable(random random.hpp random_test.cpp) 16 | 17 | add_executable(is_prime is_prime.cpp random.hpp) 18 | -------------------------------------------------------------------------------- /part10/is_prime.cpp: -------------------------------------------------------------------------------- 1 | // 书P395 2 | // 素性判断 3 | #include 4 | #include "random.hpp" 5 | 6 | using namespace std; 7 | 8 | typedef long long HugeNum; 9 | 10 | // 实现基本的素性测试函数 11 | // 如果witness不返回1,n肯定是一个合数 12 | // 通过计算a^i(mod n)并随时查看1的非平凡的平方根得到 13 | HugeNum witness(const HugeNum& a, const HugeNum& i, const HugeNum& n) 14 | { 15 | if(i == 0) 16 | return 1; 17 | HugeNum x = witness(a, i / 2, n); 18 | if(x == 0) // 如果n递归为合数,停止 19 | return 0; 20 | 21 | // 如果我们找到1的一个非平凡平方根,则n不是素数 22 | HugeNum y = (x * x) % n; 23 | if(y == 1 && x != 1 && x != n - 1) 24 | return 0; 25 | if(i % 2 != 0) 26 | y = (a * y) % n; 27 | return y; 28 | } 29 | 30 | // 在随机化测试中所查询的witness次数 31 | const int TRIALS = 5; 32 | 33 | // 随机化素性测试 34 | // 调整TRIALS以增加可信度 35 | // n是要测试的数 36 | // 如果返回值false,n肯定不是素数 37 | // 返回true,n很可能是素数 38 | bool isPrime(const HugeNum& n) 39 | { 40 | DS::Random r; 41 | for(int counter = 0; counter < TRIALS; ++counter) 42 | { 43 | if(witness(r.randomInt(2, n - 2), n - 1, n) != 1) 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | int main() 50 | { 51 | for(int i = 101; i < 200; i += 2) 52 | if(isPrime(i)) 53 | cout << i << " is prime" << endl; 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /part10/random.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RANDOM_HPP 2 | #define RANDOM_HPP 3 | 4 | // 随机数生成器 5 | // Random class 6 | // This code assumes 32-bit ints, 7 | // which are standard on modern compilers. 8 | // 9 | // CONSTRUCTION: with (a) no initializer or (b) an integer 10 | // that specifies the initial state of the generator 11 | // 12 | // ******************PUBLIC OPERATIONS********************* 13 | // Return a random number according to some distribution: 14 | // int randomInt( ) --> Uniform, 1 to 2^31-1 15 | // int random0_1( ) --> Uniform, 0 to 1 16 | // int randomInt( int low, int high ) --> Uniform low..high 17 | 18 | namespace DS 19 | { 20 | class Random 21 | { 22 | public: 23 | static const int A = 48271; 24 | static const int M = 2147483647; 25 | static const int Q = M / A; 26 | static const int R = M % A; 27 | 28 | explicit Random(int init = 1) 29 | { 30 | if(init < 0) 31 | init += M; 32 | state_ = init; 33 | if(state_ == 0) 34 | state_ = 1; 35 | } 36 | 37 | int randomInt() 38 | { 39 | int tmp = A * (state_ % Q) - R * (state_ / Q); 40 | if(tmp >= 0) 41 | state_ = tmp; 42 | else 43 | state_ = tmp + M; 44 | return state_; 45 | } 46 | 47 | // 可能溢出 48 | int randomIntWrong() 49 | { 50 | return state_ = (A * state_) % M; 51 | } 52 | 53 | double random0_1() 54 | { 55 | return static_cast(randomInt()) / M; 56 | } 57 | 58 | int randomInt(int low, int high) 59 | { 60 | double partition_size = static_cast(M) / (high - low + 1); 61 | return static_cast(randomInt() / partition_size) + low; 62 | } 63 | 64 | private: 65 | int state_; 66 | }; 67 | } 68 | #endif //RANDOM_HPP 69 | -------------------------------------------------------------------------------- /part10/random_test.cpp: -------------------------------------------------------------------------------- 1 | #include "random.hpp" 2 | #include 3 | using namespace std; 4 | using DS::Random; 5 | 6 | // Test program 7 | int main() 8 | { 9 | Random r{1}; 10 | 11 | for (int i = 0; i < 20; ++i) 12 | cout << r.randomInt() << endl; 13 | 14 | return 0; 15 | } -------------------------------------------------------------------------------- /part11/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART11) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | elseif(${CMAKE_BUILD_TYPE} MATCHES Release) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Using [Release] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # 摊还分析 伸展树 15 | add_executable(splay_tree splay_tree_test.cpp splay_tree.hpp) 16 | -------------------------------------------------------------------------------- /part11/splay_tree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SPLAY_TREE_HPP 2 | #define SPLAY_TREE_HPP 3 | 4 | #include 5 | #include "../lib/dsexceptions.h" 6 | 7 | // 区别于二叉搜索树BST和平衡二叉树AVL,伸展树本质在BST基础上还规定类每次访问之后将访问的节点变成根节点, 8 | // 这样使得被访问过的节点尽可能靠近根节点,这样下次再次访问时更快定位。 9 | // 因此不像AVL那样需要保存高度信息节省了存储空间,具有二叉查找树的所有性质,在性能上又比普通的二叉查找树有所改进。 10 | // 普通的二叉查找树在最坏情况下的查找操作的时间复杂度为O(n)(当二叉树退化成一条链的时候) 11 | // 而伸展树在任何情况下的平摊时间复杂度均为 O(logN) 12 | 13 | // 变换形式,相比AVL增加一字型旋转 14 | 15 | // SplayTree class 16 | // 17 | // CONSTRUCTION: with no parameters 18 | // 19 | // ******************PUBLIC OPERATIONS********************* 20 | // void insert( x ) --> Insert x 21 | // void remove( x ) --> Remove x 22 | // bool contains( x ) --> Return true if x is present 23 | // Comparable findMin( ) --> Return smallest item 24 | // Comparable findMax( ) --> Return largest item 25 | // bool empty( ) --> Return true if empty; else false 26 | // void clear( ) --> Remove all items 27 | // void print( ) --> Print tree in sorted order 28 | // ******************ERRORS******************************** 29 | // Throws UnderflowException as warranted 30 | 31 | namespace DS 32 | { 33 | template 34 | class SplayTree 35 | { 36 | public: 37 | SplayTree() 38 | { 39 | null_node_ = new TreeNode{}; 40 | null_node_->left_ = null_node_->right_ = null_node_; 41 | root_ = null_node_; 42 | } 43 | 44 | SplayTree(const SplayTree& rhs) 45 | { 46 | null_node_ = new TreeNode{}; 47 | null_node_->left_ = null_node_->right_ = null_node_; 48 | clone(root_, rhs.root_); 49 | } 50 | 51 | SplayTree(SplayTree&& rhs) noexcept 52 | : root_{rhs.root_}, null_node_{rhs.null_node_} 53 | { 54 | rhs.root_ = nullptr; 55 | rhs.null_node_ = nullptr; 56 | } 57 | 58 | ~SplayTree() 59 | { 60 | clear(); 61 | delete null_node_; 62 | null_node_ = nullptr; 63 | } 64 | 65 | SplayTree& operator=(const SplayTree& rhs) 66 | { 67 | SplayTree copy{rhs}; 68 | std::swap(*this, copy); 69 | return *this; 70 | } 71 | 72 | SplayTree& operator=(SplayTree&& rhs) noexcept 73 | { 74 | std::swap(root_, rhs.root_); 75 | std::swap(null_node_, rhs.null_node_); 76 | return *this; 77 | } 78 | 79 | bool empty() const 80 | { 81 | return root_ == null_node_; 82 | } 83 | 84 | bool contains(const Object& x) 85 | { 86 | if(empty()) 87 | return false; 88 | splay(x, root_); 89 | return root_->element_ == x; 90 | } 91 | 92 | void print() const 93 | { 94 | if(empty()) 95 | std::cout << "Empty tree" << std::endl; 96 | else 97 | print(root_); 98 | } 99 | 100 | /* Not the most efficient implementation (uses two passes), 101 | * but has correct amortized behavior. 102 | * A good alternative is to first call find with parameter 103 | * smaller than any item in the tree, then call findMin. 104 | * Return the smallest item or throw UnderflowException if empty. 105 | */ 106 | const Object& findMin() 107 | { 108 | if(empty()) 109 | throw UnderflowException{}; 110 | TreeNode* ptr = root_; 111 | while(ptr->left_ != null_node_) 112 | ptr = ptr->left_; 113 | 114 | splay(ptr->element_, root_); 115 | return ptr->element_; 116 | } 117 | 118 | const Object& findMax() 119 | { 120 | if(empty()) 121 | throw UnderflowException{}; 122 | TreeNode* ptr = root_; 123 | while(ptr->right_ != null_node_) 124 | ptr = ptr->right_; 125 | 126 | splay(ptr->element_, root_); 127 | return ptr->element_; 128 | } 129 | 130 | void clear() 131 | { 132 | while(!empty()) 133 | { 134 | findMax(); // splay max item to root 135 | remove(root_->element_); 136 | } 137 | } 138 | 139 | void insert(const Object& x) 140 | { 141 | TreeNode* new_node = nullptr; 142 | new_node = new TreeNode{x}; 143 | 144 | if(root_ == null_node_) 145 | { 146 | new_node->left_ = new_node->right_ = null_node_; 147 | root_ = new_node; 148 | } else{ 149 | splay(x, root_); 150 | if(x < root_->element_) 151 | { 152 | new_node->left_ = root_->left_; 153 | new_node->right_ = root_; 154 | root_->left_ = null_node_; 155 | root_ = new_node; 156 | } else if(root_->element_ < x){ 157 | new_node->right_ = root_->right_; 158 | new_node->left_ = root_; 159 | root_->right_ = null_node_; 160 | root_ = new_node; 161 | } else{ 162 | return; 163 | } 164 | } 165 | } 166 | 167 | void remove(const Object& x) 168 | { 169 | if(!contains(x)) // 调用contain的同时,如果x存在,会被放在root节点 170 | return; 171 | 172 | TreeNode* new_tree; // 保存root的子树 173 | 174 | if(root_->left_ == null_node_) 175 | new_tree = root_->right_; 176 | else 177 | { 178 | // 找左子树的最大节点 179 | // 将其splay到new_tree的根 180 | new_tree = root_->left_; 181 | splay(x, new_tree); 182 | new_tree->right_ = root_->right_; 183 | } 184 | delete root_; // 删除旧根 185 | root_ = new_tree; 186 | } 187 | 188 | private: 189 | class TreeNode 190 | { 191 | public: 192 | Object element_; 193 | TreeNode* left_; 194 | TreeNode* right_; 195 | 196 | TreeNode() 197 | :element_{Object()}, left_{nullptr}, right_{nullptr} 198 | {} 199 | 200 | explicit TreeNode(const Object& element, TreeNode* lt = nullptr, TreeNode* rt = nullptr) 201 | : element_{element}, left_{lt}, right_{rt} 202 | {} 203 | }; 204 | 205 | TreeNode* root_; 206 | TreeNode* null_node_; // 空节点指示标志 207 | 208 | TreeNode* clone(TreeNode*& node, TreeNode* new_node) const 209 | { 210 | if(new_node == new_node->left_) 211 | node = null_node_; 212 | else 213 | { 214 | node = new TreeNode(new_node->element_, new_node->left_, new_node->right_); 215 | clone(node->left_, new_node->left_); 216 | clone(node->right_, new_node->right_); 217 | } 218 | } 219 | 220 | void print(TreeNode* node) const 221 | { 222 | if(node != node->left_) 223 | { 224 | print(node->left_); 225 | std::cout << node->element_ << std::endl; 226 | print(node->right_); 227 | } 228 | } 229 | 230 | void rotateWithLeftChild(TreeNode*& k2) 231 | { 232 | TreeNode* k1 = k2->left_; 233 | k2->left_ = k1->right_; 234 | k1->right_ = k2; 235 | k2 = k1; 236 | } 237 | 238 | void rotateWithRightChild(TreeNode*& k1) 239 | { 240 | TreeNode* k2 = k1->right_; 241 | k1->right_ = k2->left_; 242 | k2->left_ = k1; 243 | k1 = k2; 244 | } 245 | 246 | /* 247 | * Internal method to perform a top-down splay. 248 | * The last accessed node becomes the new root. 249 | * This method may be overridden to use a different 250 | * splaying algorithm, however, the splay tree code 251 | * depends on the accessed item going to the root. 252 | * x is the target item to splay around. 253 | * t is the root of the subtree to splay 254 | */ 255 | void splay(const Object& x, TreeNode*& node) 256 | { 257 | // header/left_max/right_min的作用和变化结合下方while部分代码图解比较好理解 258 | TreeNode* left_max; 259 | TreeNode* right_min; 260 | TreeNode header; 261 | header.left_ = header.right_ = null_node_; 262 | left_max = right_min = &header; 263 | 264 | null_node_->element_ = x; // 作为退出条件 265 | 266 | while(true) 267 | { 268 | if(x < node->element_) // 含x的节点位于左子树 269 | { 270 | if(x < node->left_->element_) // 含x的节点位于左子树的左子树 271 | rotateWithLeftChild(node); 272 | if(node->left_ == null_node_) // 含x的节点不存在 273 | break; 274 | right_min->left_ = node; 275 | right_min = node; 276 | node = node->left_; 277 | } else if(node->element_ < x) // 含x的节点位于右子树 278 | { 279 | if(node->right_->element_ < x) // 含x的节点位于右子树的右子树 280 | rotateWithRightChild(node); 281 | if(node->right_ == null_node_) // 含x的节点不存在 282 | break; 283 | left_max->right_ = node; 284 | left_max = node; 285 | node = node->right_; 286 | } else{ // == x 或者是 == null_node_ 287 | break; 288 | } 289 | } 290 | // 经过while过程,找到了包含x的节点(如果存在的话) 291 | // node指向x 292 | left_max->right_ = node->left_; 293 | right_min->left_ = node->right_; 294 | node->left_ = header.right_; 295 | node->right_ = header.left_; 296 | } 297 | }; 298 | } 299 | #endif //SPLAY_TREE_HPP 300 | -------------------------------------------------------------------------------- /part11/splay_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "splay_tree.hpp" 3 | 4 | using namespace std; 5 | using DS::SplayTree; 6 | 7 | // Test program 8 | int main() 9 | { 10 | SplayTree t; 11 | int NUMS = 30000; 12 | const int GAP = 37; 13 | int i; 14 | 15 | cout << "Checking... (no more output means success)" << endl; 16 | 17 | for (i = GAP; i != 0; i = (i + GAP) % NUMS) 18 | t.insert(i); 19 | 20 | for (i = 1; i < NUMS; i += 2) 21 | t.remove(i); 22 | 23 | if (NUMS < 40) 24 | t.print(); 25 | if (t.findMin() != 2 || t.findMax() != NUMS - 2) 26 | cout << "FindMin or FindMax error!" << endl; 27 | 28 | for (i = 2; i < NUMS; i += 2) 29 | if (!t.contains(i)) 30 | cout << "Find error1!" << endl; 31 | 32 | for (i = 1; i < NUMS; i += 2) 33 | { 34 | if (t.contains(i)) 35 | cout << "Find error2!" << endl; 36 | } 37 | 38 | SplayTree t2; 39 | t2 = t; 40 | 41 | for (i = 2; i < NUMS; i += 2) 42 | if (!t2.contains(i)) 43 | cout << "Find error1!" << endl; 44 | 45 | for (i = 1; i < NUMS; i += 2) 46 | { 47 | if (t2.contains(i)) 48 | cout << "Find error2!" << endl; 49 | } 50 | 51 | cout << "Test completed." << endl; 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /part12/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART12) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | elseif(${CMAKE_BUILD_TYPE} MATCHES Release) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Using [Release] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # 高级数据结构 15 | # RedBlackTree 红黑树 16 | set(DEMO rb_tree) 17 | set(LIB ../lib) 18 | set(SOURCE 19 | ${DEMO}.hpp 20 | ${DEMO}_test.cpp 21 | ${LIB}) 22 | add_executable(${DEMO} ${SOURCE}) 23 | 24 | # Treap 树堆 25 | set(DEMO treap) 26 | set(LIB ../lib) 27 | set(SOURCE 28 | ${DEMO}.hpp 29 | ${DEMO}_test.cpp 30 | ${LIB}) 31 | add_executable(${DEMO} ${SOURCE}) 32 | 33 | # KdTree k维搜索树 34 | set(DEMO kd_tree) 35 | set(LIB ../lib) 36 | set(SOURCE 37 | ${DEMO}.hpp 38 | ${DEMO}_test.cpp 39 | ${LIB}) 40 | add_executable(${DEMO} ${SOURCE}) 41 | 42 | # PairingHeap 配对堆 43 | set(DEMO pairing_heap) 44 | set(LIB ../lib) 45 | set(SOURCE 46 | ${DEMO}.hpp 47 | ${DEMO}_test.cpp 48 | ${LIB}) 49 | add_executable(${DEMO} ${SOURCE}) 50 | 51 | 52 | -------------------------------------------------------------------------------- /part12/kd_tree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef KD_TREE_HPP 2 | #define KD_TREE_HPP 3 | 4 | // k-d tree d维搜索树 5 | // 此处实现的是二维搜索树 6 | // 如果在建树时采用中值优化(保证根值是分割维度集合的中值)会建立一棵更加平衡的树 7 | 8 | #include 9 | #include "../lib/dsexceptions.h" 10 | 11 | namespace DS 12 | { 13 | template 14 | class KdTree 15 | { 16 | private: 17 | class TreeNode 18 | { 19 | public: 20 | std::vector data_; 21 | TreeNode* left_; 22 | TreeNode* right_; 23 | 24 | explicit TreeNode(const std::vector& item) 25 | : data_{item}, left_{nullptr}, right_{nullptr} 26 | {} 27 | }; 28 | 29 | TreeNode* root_; 30 | 31 | void clear(TreeNode*& root) 32 | { 33 | if(root) 34 | { 35 | TreeNode* lp = root->left_; 36 | TreeNode* rp = root->right_; 37 | delete root; 38 | root = nullptr; 39 | clear(lp); 40 | clear(rp); 41 | } 42 | } 43 | 44 | void clone(TreeNode*& node, TreeNode* rhs) 45 | { 46 | if(rhs) 47 | { 48 | node = new TreeNode{rhs->data_}; 49 | clone(node->left_, rhs->left_); 50 | clone(node->right_, rhs->right_); 51 | } 52 | } 53 | 54 | void printRange(const std::vector& low, const std::vector& high, 55 | TreeNode* node, int level) const 56 | { 57 | if(node) 58 | { 59 | if(low[0] <= node->data_[0] && high[0] >= node->data_[0] && \ 60 | low[1] <= node->data_[1] && high[1] >= node->data_[1]) 61 | std::cout << "(" << node->data_[0] << "," << node->data_[1] << ")" << std::endl; 62 | if(low[level] <= node->data_[level]) 63 | printRange(low, high, node->left_, 1 - level); 64 | if(high[level] >= node->data_[level]) 65 | printRange(low, high, node->right_, 1 - level); 66 | } 67 | } 68 | 69 | void insert(const std::vector& x, TreeNode*& node, int level) 70 | { 71 | if(node == nullptr) 72 | node = new TreeNode(x); 73 | else if(x[level] > node->data_[level]) 74 | insert(x, node->right_, 1 - level); 75 | else if(x[level] < node->data_[level] || x[1 - level] != node->data_[1 - level]) 76 | insert(x, node->left_, 1 - level); 77 | } 78 | 79 | bool contain(const std::vector& item, TreeNode* node, int level) 80 | { 81 | if(item == nullptr) 82 | return false; 83 | else if(item[level] > node->data_[level]) 84 | return contain(item, node->right_, 1 - level); 85 | else if(item[level] < node->data_[level] || item[1 - level] != node->data_[1 - level]) 86 | contain(item, node->left_, 1 - level); 87 | else 88 | return true; 89 | } 90 | 91 | public: 92 | KdTree() 93 | : root_(nullptr) 94 | {} 95 | 96 | KdTree(const KdTree& rhs) 97 | : root_(nullptr) 98 | { 99 | clone(root_, rhs.root_); 100 | } 101 | 102 | KdTree(KdTree&& rhs) noexcept 103 | : root_{rhs.root_} 104 | { 105 | rhs.root_ = nullptr; 106 | } 107 | 108 | ~KdTree() 109 | { 110 | clear(); 111 | } 112 | 113 | KdTree& operator=(const KdTree& rhs) 114 | { 115 | KdTree copy{rhs}; 116 | std::swap(*this, copy); 117 | return *this; 118 | } 119 | 120 | KdTree& operator=(KdTree&& rhs) noexcept 121 | { 122 | std::swap(root_, rhs.root_); 123 | return *this; 124 | } 125 | 126 | bool empty() const 127 | { 128 | return root_ == nullptr; 129 | } 130 | 131 | void clear() 132 | { 133 | if(!empty()) 134 | clear(root_); 135 | } 136 | 137 | // 打印low~high范围内的点 138 | void printRange(const std::vector& low, const std::vector& high) const 139 | { 140 | printRange(low, high, root_, 0); 141 | } 142 | 143 | void insert(const std::vector& x) 144 | { 145 | insert(x, root_, 0); 146 | } 147 | 148 | bool contain(const std::vector& item) const 149 | { 150 | if(empty()) 151 | return false; 152 | return contain(item, root_, 0); 153 | } 154 | }; 155 | } 156 | 157 | #endif //KD_TREE_HPP 158 | -------------------------------------------------------------------------------- /part12/kd_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "kd_tree.hpp" 3 | 4 | using namespace std; 5 | using DS::KdTree; 6 | 7 | int main() 8 | { 9 | KdTree t; 10 | 11 | cout << "Starting program" << endl; 12 | for (int i = 300; i < 370; ++i) 13 | { 14 | vector it(2); 15 | it[0] = i; 16 | it[1] = 2500 - i; 17 | t.insert(it); 18 | } 19 | 20 | vector low(2), high(2); 21 | low[0] = 70; 22 | low[1] = 2186; 23 | high[0] = 1200; 24 | high[1] = 2200; 25 | 26 | t.printRange(low, high); 27 | 28 | return 0; 29 | } -------------------------------------------------------------------------------- /part12/pairing_heap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PAIRING_HEAP_HPP 2 | #define PAIRING_HEAP_HPP 3 | 4 | #include 5 | #include 6 | #include "../lib/dsexceptions.h" 7 | 8 | // Pairing heap class 9 | // 适合decreaseKey修改节点关键字值的场景 10 | // 小根堆 11 | // CONSTRUCTION: with no parameters 12 | // 13 | // ******************PUBLIC OPERATIONS********************* 14 | // PairNode & insert( x ) --> Insert x 15 | // pop( minItem ) --> Remove (and optionally return) top item 16 | // Comparable top( ) --> Return top item 17 | // bool empty( ) --> Return true if empty; else false 18 | // void clear( ) --> Remove all items 19 | // void decreaseKey( Position p, newVal ) 20 | // --> Decrease value in Position p 21 | // ******************ERRORS******************************** 22 | // Throws UnderflowException as warranted 23 | 24 | namespace DS 25 | { 26 | template 27 | class PairingHeap 28 | { 29 | private: 30 | class PairNode 31 | { 32 | public: 33 | Object element_; 34 | PairNode* first_child_; 35 | PairNode* next_sibling_; 36 | PairNode* prev_; 37 | 38 | explicit PairNode(const Object& e, PairNode* fc = nullptr, PairNode* ns = nullptr, PairNode* p = nullptr) 39 | : element_{e}, first_child_{fc}, next_sibling_{ns}, prev_{p} 40 | {} 41 | 42 | explicit PairNode(Object&& e, PairNode* fc = nullptr, PairNode* ns = nullptr, PairNode* p = nullptr) 43 | : element_{std::move(e)}, first_child_{fc}, next_sibling_{ns}, prev_{p} 44 | {} 45 | }; 46 | 47 | PairNode* root_; 48 | 49 | void clone(PairNode*& root, PairNode* other) 50 | { 51 | if(nullptr == other) 52 | return; 53 | root = new PairNode{other->element_}; 54 | if(other->first_child_) 55 | { 56 | clone(root->first_child_, other->first_child_); 57 | root->first_child_->prev_ = root; 58 | } 59 | if(other->next_sibling_) 60 | { 61 | clone(root->next_sibling_, other->next_sibling_); 62 | root->next_sibling_->prev_ = root; 63 | } 64 | } 65 | 66 | void clear(PairNode* root) 67 | { 68 | if(nullptr == root) 69 | return; 70 | PairNode *fc = root->first_child_; 71 | PairNode *ns = root->next_sibling_; 72 | delete root; 73 | clear(fc); 74 | clear(ns); 75 | } 76 | 77 | // 将first和second连接在一起以满足堆序 78 | // first是树1的根,它可以不是nullptr 79 | // first->next_sibling_ 在接入时必须是nullptr 80 | // 所以root节点是唯一的,没有兄弟 81 | // second是树2的根,可以是nullptr 82 | // 合并结果到first上 83 | void compareAndLink(PairNode*& first, PairNode* second) 84 | { 85 | if(second == nullptr) 86 | return; 87 | if(second->element_ < first->element_) 88 | { 89 | // first 成为second的第一个儿子 90 | second->prev_ = first->prev_; 91 | first->next_sibling_ = second->first_child_; 92 | first->prev_ = second; 93 | if(first->next_sibling_ != nullptr) 94 | first->next_sibling_->prev_ = first; 95 | second->first_child_ = first; 96 | first = second; 97 | } else { 98 | // second 变成 first的第一个儿子 99 | second->prev_ = first; 100 | first->next_sibling_ = second->next_sibling_; 101 | if(first->next_sibling_) 102 | first->next_sibling_->prev_ = first; 103 | second->next_sibling_ = first->first_child_; 104 | if(second->next_sibling_) 105 | second->next_sibling_->prev_ = second; 106 | first->first_child_ = second; 107 | } 108 | } 109 | 110 | // 实现两趟合并的方法 111 | // firstSibling是合并后树的根,假设不是nullptr 112 | PairNode* combineSiblings(PairNode* firstSibling) 113 | { 114 | if(firstSibling->next_sibling_ == nullptr) 115 | return firstSibling; 116 | // 保存子树用 117 | static std::vector tree_array(5); 118 | // 遍历firstSibling和其所有兄弟,保存子树 119 | int n_siblings = 0; 120 | for(; firstSibling != nullptr; ++n_siblings) 121 | { 122 | if(n_siblings == tree_array.size()) 123 | tree_array.resize(n_siblings * 2); 124 | tree_array[n_siblings] = firstSibling; 125 | firstSibling = firstSibling->next_sibling_; 126 | } 127 | if(n_siblings == tree_array.size()) 128 | tree_array.resize(n_siblings + 1); 129 | tree_array[n_siblings] = nullptr; 130 | 131 | // 由于在合并时,每个子树的根的兄弟会被舍弃(视为nullptr) 132 | // 所以用tree_array保存树根的兄弟,并用于后续合并 133 | // combine 134 | int i = 0; 135 | for(; i + 1 < n_siblings; i += 2) // 两两合并 136 | compareAndLink(tree_array[i], tree_array[i + 1]); 137 | int j = i - 2; 138 | if(j == n_siblings - 3) // n_siblings 为奇数,合并遗漏的一棵子树 139 | compareAndLink(tree_array[j], tree_array[j + 2]); 140 | for(; j >= 2; j -= 2) // 将上一步合并的树一一合并 141 | compareAndLink(tree_array[j - 2], tree_array[j]); 142 | return tree_array[0]; 143 | } 144 | 145 | public: 146 | typedef PairNode* Position; 147 | 148 | explicit PairingHeap() 149 | : root_{nullptr} 150 | {} 151 | 152 | ~PairingHeap() 153 | { 154 | clear(); 155 | } 156 | 157 | PairingHeap(const PairingHeap& rhs) 158 | : root_{nullptr} 159 | { 160 | if(rhs.root_) 161 | clone(root_, rhs.root_); 162 | } 163 | 164 | PairingHeap(PairingHeap&& rhs) noexcept 165 | : root_{rhs.root_} 166 | { 167 | rhs.root_ = nullptr; 168 | } 169 | 170 | PairingHeap& operator=(const PairingHeap& rhs) 171 | { 172 | PairingHeap copy{rhs}; 173 | std::swap(*this, copy); 174 | return *this; 175 | } 176 | 177 | PairingHeap& operator=(PairingHeap&& rhs) noexcept 178 | { 179 | std::swap(root_, rhs.root_); 180 | return *this; 181 | } 182 | 183 | bool empty() const 184 | { 185 | return root_ == nullptr; 186 | } 187 | 188 | const Object& top() const 189 | { 190 | if(empty()) 191 | throw UnderflowException{}; 192 | return root_->element_; 193 | } 194 | 195 | void pop() 196 | { 197 | if(empty()) 198 | throw UnderflowException{}; 199 | PairNode* old_root = root_; 200 | if(root_->first_child_ == nullptr) 201 | root_ = nullptr; 202 | else 203 | root_ = combineSiblings(root_->first_child_); 204 | delete old_root; 205 | } 206 | 207 | void pop(Object& item) 208 | { 209 | item = top(); 210 | pop(); 211 | } 212 | 213 | void clear() 214 | { 215 | clear(root_); 216 | root_ = nullptr; 217 | } 218 | 219 | PairNode* insert(const Object& x) 220 | { 221 | PairNode* new_node = nullptr; 222 | new_node = new PairNode(x); 223 | if(nullptr == root_) 224 | root_ = new_node; 225 | else 226 | compareAndLink(root_, new_node); 227 | return new_node; 228 | } 229 | 230 | PairNode* insert(Object&& x) 231 | { 232 | PairNode* new_node = nullptr; 233 | new_node = new PairNode{std::move(x)}; 234 | if(nullptr == root_) 235 | root_ = new_node; 236 | else 237 | compareAndLink(root_, new_node); 238 | return new_node; 239 | } 240 | 241 | // 减小key的值 242 | void decreaseKey(PairNode* p, const Object& new_val) 243 | { 244 | if(p->element_ < new_val) 245 | throw std::invalid_argument("new val should be not large than old val"); 246 | if(new_val < p->element_) 247 | { 248 | p->element_ = new_val; // 点p改值后可能小于所属的父节点 249 | if (p != root_) // p不是根 250 | { 251 | // p有兄弟的话,p兄弟的prev连接p的prev 252 | if (p->next_sibling_ != nullptr) 253 | p->next_sibling_->prev_ = p->prev_; 254 | if (p->prev_->first_child_ == p) // 如果p是父节点的第一个儿子 255 | p->prev_->first_child_ = p->next_sibling_; 256 | else // 否则p的上一个(prev)兄弟直连p的下一个兄弟 257 | p->prev_->next_sibling_ = p->next_sibling_; 258 | p->next_sibling_ = nullptr; 259 | compareAndLink(root_, p); 260 | } 261 | } 262 | } 263 | 264 | // 减小key的值 265 | void decreaseKey(PairNode* p, Object&& new_val) 266 | { 267 | if(p->element_ < new_val) 268 | throw std::invalid_argument("new val should be not large than old val"); 269 | if(new_val < p->element_) 270 | { 271 | p->element_ = std::move(new_val); // 点p改值后可能小于所属的父节点 272 | if (p != root_) // p不是根 273 | { 274 | // p有兄弟的话,p兄弟的prev连接p的prev 275 | if (p->next_sibling_ != nullptr) 276 | p->next_sibling_->prev_ = p->prev_; 277 | if (p->prev_->first_child_ == p) // 如果p是父节点的第一个儿子 278 | p->prev_->first_child_ = p->next_sibling_; 279 | else // 否则p的上一个(prev)兄弟直连p的下一个兄弟 280 | p->prev_->next_sibling_ = p->next_sibling_; 281 | p->next_sibling_ = nullptr; 282 | compareAndLink(root_, p); 283 | } 284 | } 285 | } 286 | }; 287 | } 288 | #endif //PAIRING_HEAP_HPP 289 | -------------------------------------------------------------------------------- /part12/pairing_heap_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "pairing_heap.hpp" 4 | 5 | using namespace std; 6 | using DS::PairingHeap; 7 | 8 | // Test program 9 | int main() 10 | { 11 | PairingHeap h; 12 | 13 | int numItems = 4000; 14 | int i = 37; 15 | int j; 16 | 17 | cout << "Checking; no bad output is good" << endl; 18 | for (i = 37; i != 0; i = (i + 37) % numItems) 19 | h.insert(i); 20 | 21 | for (i = 1; i < numItems; ++i) 22 | { 23 | int x; 24 | h.pop(x); 25 | if (x != i) 26 | cout << "Oops! " << i << endl; 27 | } 28 | 29 | vector::Position> p(numItems); 30 | for (i = 0, j = numItems / 2; i < numItems; ++i, j = (j + 71) % numItems) 31 | p[j] = h.insert(j + numItems); 32 | for (i = 0, j = numItems / 2; i < numItems; ++i, j = (j + 53) % numItems) 33 | h.decreaseKey(p[j], j); 34 | i = -1; 35 | 36 | PairingHeap h2; 37 | 38 | h2 = h; 39 | while (!h2.empty()) 40 | { 41 | int x; 42 | h2.pop(x); 43 | if (x != ++i) 44 | cout << "Oops! " << i << endl; 45 | } 46 | 47 | cout << "Check completed" << endl; 48 | return 0; 49 | } -------------------------------------------------------------------------------- /part12/rb_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rb_tree.hpp" 3 | using namespace std; 4 | using DS::RedBlackTree; 5 | 6 | // Test program 7 | int main() 8 | { 9 | RedBlackTree t; 10 | int NUMS = 400000; 11 | // int NUMS = 1000; 12 | const int GAP = 37; 13 | int i; 14 | 15 | cout << "Checking... (no more output means success)" << endl; 16 | 17 | cout << "Build check" << endl; 18 | for (i = GAP; i != 0; i = (i + GAP) % NUMS) 19 | { 20 | t.insert(i); 21 | } 22 | if (NUMS < 1000) 23 | t.print(); 24 | if (t.findMin() != 1) 25 | cout << "FindMin error!" << endl; 26 | if(t.findMax() != NUMS - 1) 27 | cout << "FindMax error!" << endl; 28 | 29 | for (i = 1; i < NUMS; ++i) 30 | if (!t.contains(i)) 31 | cout << "Find error1!" << endl; 32 | if (t.contains(0)) 33 | cout << "Oops!" << endl; 34 | 35 | cout << "============" << endl; 36 | cout << "Clone check" << endl; 37 | RedBlackTree t2; 38 | t2 = t; 39 | 40 | for (i = 1; i < NUMS; ++i) 41 | if (!t2.contains(i)) 42 | cout << "Find error1!" << endl; 43 | if (t2.contains(0)) 44 | cout << "Oops!" << endl; 45 | 46 | cout << "============" << endl; 47 | cout << "Remove check" << endl; 48 | for(i = 1; i < NUMS; i += 2) 49 | t.remove(i); 50 | for(i = 1; i < NUMS; i += 2) 51 | if(t.contains(i)) 52 | cout << "Find error2!" << endl; 53 | for(i = 2; i < NUMS; i += 2) 54 | if(!t.contains(i)) 55 | cout << "Find error3!" << endl; 56 | if (NUMS < 1000) 57 | t.print(); 58 | 59 | cout << "Test complete..." << endl; 60 | return 0; 61 | } -------------------------------------------------------------------------------- /part12/treap.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/11/5. 3 | // 4 | 5 | #ifndef TREAP_HPP 6 | #define TREAP_HPP 7 | 8 | #include 9 | #include 10 | #include "../lib/uniform_random.h" 11 | #include "../lib/dsexceptions.h" 12 | 13 | // Treap class 14 | // 树堆 15 | // ******************PUBLIC OPERATIONS********************* 16 | // void insert( x ) --> Insert x 17 | // void remove( x ) --> Remove x (unimplemented) 18 | // bool contains( x ) --> Return true if x is present 19 | // Comparable findMin( ) --> Return smallest item 20 | // Comparable findMax( ) --> Return largest item 21 | // bool empty( ) --> Return true if empty; else false 22 | // void clear( ) --> Remove all items 23 | // void print( ) --> Print tree in sorted order 24 | // ******************ERRORS******************************** 25 | // Throws UnderflowException as warranted 26 | 27 | namespace DS 28 | { 29 | template 30 | class Treap 31 | { 32 | public: 33 | Treap() 34 | { 35 | null_node_ = new TreeNode{}; 36 | null_node_->left_ = null_node_->right_ = null_node_; 37 | null_node_->priority_ = INT32_MAX; 38 | root_ = null_node_; 39 | } 40 | 41 | Treap(const Treap& rhs) 42 | { 43 | null_node_ = new TreeNode{}; 44 | null_node_->left_ = null_node_->right_ = null_node_; 45 | null_node_->priority_ = INT32_MAX; 46 | clone(root_, rhs.root_); 47 | } 48 | 49 | Treap(Treap&& rhs) noexcept 50 | : root_{rhs.root_}, null_node_{rhs.null_node_} 51 | { 52 | rhs.root_ = nullptr; 53 | rhs.null_node_ = nullptr; 54 | } 55 | 56 | ~Treap() 57 | { 58 | clear(); 59 | delete null_node_; 60 | } 61 | 62 | Treap& operator=(const Treap& rhs) 63 | { 64 | Treap copy{rhs}; 65 | std::swap(*this, copy); 66 | return *this; 67 | } 68 | 69 | Treap& operator=(Treap&& rhs) noexcept 70 | { 71 | std::swap(root_, rhs.root_); 72 | std::swap(null_node_, rhs.null_node_); 73 | return *this; 74 | } 75 | 76 | bool empty() const 77 | { 78 | return root_ == null_node_; 79 | } 80 | 81 | const Object& findMin() const 82 | { 83 | if(empty()) 84 | throw UnderflowException{}; 85 | TreeNode* ptr = root_; 86 | while(ptr->left_ != null_node_) 87 | ptr = ptr->left_; 88 | return ptr->element_; 89 | } 90 | 91 | const Object& findMax() const 92 | { 93 | if(empty()) 94 | throw UnderflowException{}; 95 | TreeNode* ptr = root_; 96 | while(ptr->right_ != null_node_) 97 | ptr = ptr->right_; 98 | return ptr->element_; 99 | } 100 | 101 | bool contains(const Object& x) const 102 | { 103 | TreeNode* current = root_; 104 | null_node_->element_ = x; 105 | while(true) 106 | { 107 | if(x < current->element_) 108 | current = current->left_; 109 | else if(x > current->element_) 110 | current = current->right_; 111 | else 112 | return current != null_node_; 113 | } 114 | } 115 | 116 | void clear() 117 | { 118 | clear(root_); 119 | } 120 | 121 | void print() const 122 | { 123 | if(empty()) 124 | std::cout << "Empty tree" << std::endl; 125 | else 126 | print(root_); 127 | } 128 | 129 | void insert(const Object& x) 130 | { 131 | insert(x, root_); 132 | } 133 | 134 | void insert(Object&& x) 135 | { 136 | insert(std::move(x), root_); 137 | } 138 | 139 | void remove(const Object& x) 140 | { 141 | remove(x, root_); 142 | } 143 | 144 | 145 | private: 146 | class TreeNode 147 | { 148 | public: 149 | Object element_; 150 | TreeNode* left_; 151 | TreeNode* right_; 152 | int priority_; // 优先级 153 | 154 | TreeNode() 155 | : element_{Object()}, left_{nullptr}, right_{nullptr}, priority_{INT32_MAX} 156 | {} 157 | 158 | TreeNode(const Object& e, int pr, TreeNode* lt = nullptr, TreeNode* rt = nullptr) 159 | : element_{e}, left_{lt}, right_{rt}, priority_{pr} 160 | {} 161 | 162 | TreeNode(Object&& e, int pr, TreeNode* lt = nullptr, TreeNode* rt = nullptr) 163 | : element_{std::move(e)}, left_{lt}, right_{rt}, priority_{pr} 164 | {} 165 | }; 166 | 167 | TreeNode* root_; 168 | TreeNode* null_node_; 169 | UniformRandom random_; 170 | 171 | void clone(TreeNode*& root, TreeNode* node) 172 | { 173 | if(node == node->left_) 174 | root = null_node_; 175 | else 176 | { 177 | root = new TreeNode(node->element_, node->priority_); 178 | clone(root->left_, node->left_); 179 | clone(root->right_, node->right_); 180 | } 181 | } 182 | 183 | void clear(TreeNode*& root) 184 | { 185 | if(root != null_node_) 186 | { 187 | TreeNode* lt = root->left_; 188 | TreeNode* rt = root->right_; 189 | delete root; 190 | root = null_node_; 191 | clear(lt); 192 | clear(rt); 193 | } 194 | } 195 | 196 | void print(TreeNode* node) const 197 | { 198 | if(node != null_node_) 199 | { 200 | print(node->left_); 201 | std::cout << node->element_ << std::endl; 202 | print(node->right_); 203 | } 204 | } 205 | 206 | void insert(const Object& x, TreeNode*& node) 207 | { 208 | // 以随机数作为优先级分配 209 | if(node == null_node_) 210 | node = new TreeNode(x, random_.nextInt(), null_node_, null_node_); 211 | else if(x < node->element_) 212 | { 213 | insert(x, node->left_); 214 | // 优先级调整 215 | if(node->left_->priority_ < node->priority_) 216 | rotateWithLeftChild(node); 217 | } else if (x > node->element_) 218 | { 219 | insert(x, node->right_); 220 | // 优先级调整 221 | if(node->right_->priority_ < node->priority_) 222 | rotateWithRightChild(node); 223 | } 224 | // else duplicate: do nothing 225 | } 226 | 227 | void insert(Object&& x, TreeNode*& node) 228 | { 229 | // 以随机数作为优先级分配 230 | if(node == null_node_) 231 | node = new TreeNode(std::move(x), random_.nextInt(), null_node_, null_node_); 232 | else if(x < node->element_) 233 | { 234 | insert(std::move(x), node->left_); 235 | // 优先级调整 236 | if(node->left_->priority_ < node->priority_) 237 | rotateWithLeftChild(node); 238 | } else if (x > node->element_) 239 | { 240 | insert(std::move(x), node->right_); 241 | // 优先级调整 242 | if(node->right_->priority_ < node->priority_) 243 | rotateWithRightChild(node); 244 | } 245 | // else duplicate: do nothing 246 | } 247 | 248 | void remove(const Object& x, TreeNode*& node) 249 | { 250 | if(node != null_node_) 251 | { 252 | if(x < node->element_) 253 | remove(x, node->left_); 254 | else if(x > node->element_) 255 | remove(x, node->right_); 256 | else // match 257 | { 258 | if(node->left_->priority_ < node->right_->priority_) 259 | rotateWithLeftChild(node); 260 | else 261 | rotateWithRightChild(node); 262 | if(node != null_node_) // 不是叶子节点 263 | remove(x, node); 264 | else // 是叶子节点 265 | { 266 | delete node->left_; 267 | node->left_ = null_node_; 268 | } 269 | } 270 | } 271 | } 272 | 273 | void rotateWithLeftChild(TreeNode*& k2) 274 | { 275 | TreeNode* k1 = k2->left_; 276 | k2->left_ = k1->right_; 277 | k1->right_ = k2; 278 | k2 = k1; 279 | } 280 | 281 | void rotateWithRightChild(TreeNode*& k1) 282 | { 283 | TreeNode *k2 = k1->right_; 284 | k1->right_ = k2->left_; 285 | k2->left_ = k1; 286 | k1 = k2; 287 | } 288 | }; 289 | } 290 | #endif //TREAP_HPP 291 | -------------------------------------------------------------------------------- /part12/treap_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "treap.hpp" 3 | 4 | using namespace std; 5 | using DS::Treap; 6 | 7 | // Test program 8 | int main() 9 | { 10 | Treap t; 11 | int NUMS = 200000; 12 | const int GAP = 37; 13 | int i; 14 | 15 | cout << "Checking... (no more output means success)" << endl; 16 | 17 | for (i = GAP; i != 0; i = (i + GAP) % NUMS) 18 | t.insert(i); 19 | for (i = 1; i < NUMS; i += 2) 20 | t.remove(i); 21 | 22 | if (NUMS < 40) 23 | t.print(); 24 | if (t.findMin() != 2 || t.findMax() != NUMS - 2) 25 | cout << "FindMin or FindMax error!" << endl; 26 | 27 | for (i = 2; i < NUMS; i += 2) 28 | if (!t.contains(i)) 29 | cout << "Find error1!" << endl; 30 | 31 | for (i = 1; i < NUMS; i += 2) 32 | { 33 | if (t.contains(i)) 34 | cout << "Find error2!" << endl; 35 | } 36 | 37 | 38 | Treap t2; 39 | t2 = t; 40 | 41 | for (i = 2; i < NUMS; i += 2) 42 | if (!t2.contains(i)) 43 | cout << "Find error1!" << endl; 44 | 45 | for (i = 1; i < NUMS; i += 2) 46 | { 47 | if (t2.contains(i)) 48 | cout << "Find error2!" << endl; 49 | } 50 | 51 | cout << "Test finished" << endl; 52 | return 0; 53 | } -------------------------------------------------------------------------------- /part2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART2) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") 5 | 6 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 7 | 8 | # binarySearch 9 | set(DEMO "binarySearch") 10 | set(SOURCE 11 | ${DEMO}Test.cpp 12 | ${DEMO}.h) 13 | add_executable(${DEMO} ${SOURCE}) 14 | 15 | # pow 16 | set(DEMO "pow") 17 | set(SOURCE ${DEMO}.cpp) 18 | add_executable(${DEMO} ${SOURCE}) 19 | 20 | # maxSum 21 | set(DEMO "maxSum") 22 | set(SOURCE ${DEMO}Test.cpp) 23 | add_executable(${DEMO} ${SOURCE}) -------------------------------------------------------------------------------- /part2/binarySearch.h: -------------------------------------------------------------------------------- 1 | /// @file binarySearch.h 2 | 3 | #ifndef __BINARYSEARCH_H__ 4 | #define __BINARYSEARCH_H__ 5 | 6 | #include 7 | 8 | #define NOT_FOUND -1 9 | // return index, if not found, return -1 10 | template 11 | int binarySearch(const std::vector& array, const Object& key) 12 | { 13 | std::size_t low = 0, high = array.size() - 1; 14 | std::size_t mid = low + (high - low) / 2; 15 | while(low <= high) 16 | { 17 | if(array[mid] > key) 18 | high = mid - 1; 19 | else if(array[mid] < key) 20 | low = mid + 1; 21 | else 22 | return mid; 23 | mid = low + (high - low) / 2; 24 | } 25 | return NOT_FOUND; 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /part2/binarySearchTest.cpp: -------------------------------------------------------------------------------- 1 | /// @file binarySearch_test.cpp 2 | 3 | #include "binarySearch.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using std::cin; 11 | using std::cout; 12 | using std::endl; 13 | using std::sort; 14 | using std::vector; 15 | 16 | int main(int argc, char** argv) 17 | { 18 | std::srand(std::time(nullptr)); // use current time as seed for random generator 19 | vector vec100, vec1000, vec10000, vec100000; 20 | for(int i = 0; i < 100000; ++i) 21 | { 22 | if(i < 100) 23 | { 24 | vec100.push_back(1 + std::rand() % 100); 25 | vec1000.push_back(1 + std::rand() % 1000); 26 | vec10000.push_back(1 + std::rand() % 10000); 27 | vec100000.push_back(1 + std::rand() % 100000); 28 | } 29 | else if(i < 1000) 30 | { 31 | vec1000.push_back(1 + std::rand() % 1000); 32 | vec10000.push_back(1 + std::rand() % 10000); 33 | vec100000.push_back(1 + std::rand() % 100000); 34 | } 35 | else if(i < 10000) 36 | { 37 | vec10000.push_back(1 + std::rand() % 10000); 38 | vec100000.push_back(1 + std::rand() % 100000); 39 | } 40 | else 41 | vec100000.push_back(1 + std::rand() % 100000); 42 | } 43 | sort(vec100.begin(), vec100.end()); 44 | sort(vec1000.begin(), vec1000.end()); 45 | sort(vec10000.begin(), vec10000.end()); 46 | sort(vec100000.begin(), vec100000.end()); 47 | // analysis 48 | time_t start, end; 49 | start = std::clock(); 50 | cout << binarySearch(vec100, 50) << " "; 51 | end = std::clock(); 52 | cout << "size 100, time cost: " << double(end - start) / CLOCKS_PER_SEC << endl; 53 | start = std::clock(); 54 | cout << binarySearch(vec1000, 500) << " "; 55 | end = std::clock(); 56 | cout << "size 1000, time cost: " << double(end - start) / CLOCKS_PER_SEC << endl; 57 | start = std::clock(); 58 | cout << binarySearch(vec10000, 5000) << " "; 59 | end = std::clock(); 60 | cout << "size 10000, time cost: " << double(end - start) / CLOCKS_PER_SEC << endl; 61 | start = std::clock(); 62 | cout << binarySearch(vec100000, 50000) << " "; 63 | end = std::clock(); 64 | cout << "size 100000, time cost: " << double(end - start) / CLOCKS_PER_SEC << endl; 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /part2/maxSumTest.cpp: -------------------------------------------------------------------------------- 1 | /// @file maxSumTest.cpp 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | /** 8 | * * Cubic maximum contiguous subsequence sum algorithm. 9 | * */ 10 | int maxSubSum1( const vector & a ) 11 | { 12 | int maxSum = 0; 13 | 14 | for( std::size_t i = 0; i < a.size( ); ++i ) 15 | for( std::size_t j = i; j < a.size( ); ++j ) 16 | { 17 | int thisSum = 0; 18 | 19 | for( std::size_t k = i; k <= j; ++k ) 20 | thisSum += a[ k ]; 21 | 22 | if( thisSum > maxSum ) 23 | maxSum = thisSum; 24 | } 25 | 26 | return maxSum; 27 | } 28 | 29 | 30 | /** 31 | * * Quadratic maximum contiguous subsequence sum algorithm. 32 | * */ 33 | int maxSubSum2( const vector & a ) 34 | { 35 | int maxSum = 0; 36 | 37 | for( std::size_t i = 0; i < a.size( ); ++i ) 38 | { 39 | int thisSum = 0; 40 | for( std::size_t j = i; j < a.size( ); ++j ) 41 | { 42 | thisSum += a[ j ]; 43 | 44 | if( thisSum > maxSum ) 45 | maxSum = thisSum; 46 | } 47 | } 48 | 49 | return maxSum; 50 | } 51 | 52 | /** 53 | * * Return maximum of three integers. 54 | * */ 55 | int max3( int a, int b, int c ) 56 | { 57 | return a > b ? a > c ? a : c : b > c ? b : c; 58 | } 59 | 60 | /** 61 | * * Recursive maximum contiguous subsequence sum algorithm. 62 | * * Finds maximum sum in subarray spanning a[left..right]. 63 | * * Does not attempt to maintain actual best sequence. 64 | * */ 65 | int maxSumRec( const vector & a, int left, int right ) 66 | { 67 | if( left == right ) // Base case 68 | { 69 | if (a[left] > 0) 70 | return a[left]; 71 | else 72 | return 0; 73 | } 74 | 75 | int center = ( left + right ) / 2; 76 | int maxLeftSum = maxSumRec( a, left, center ); 77 | int maxRightSum = maxSumRec( a, center + 1, right ); 78 | 79 | int maxLeftBorderSum = 0, leftBorderSum = 0; 80 | for( int i = center; i >= left; --i ) 81 | { 82 | leftBorderSum += a[ i ]; 83 | if( leftBorderSum > maxLeftBorderSum ) 84 | maxLeftBorderSum = leftBorderSum; 85 | } 86 | 87 | int maxRightBorderSum = 0, rightBorderSum = 0; 88 | for( int j = center + 1; j <= right; ++j ) 89 | { 90 | rightBorderSum += a[ j ]; 91 | if( rightBorderSum > maxRightBorderSum ) 92 | maxRightBorderSum = rightBorderSum; 93 | } 94 | 95 | return max3( maxLeftSum, maxRightSum, 96 | maxLeftBorderSum + maxRightBorderSum ); 97 | } 98 | 99 | /** 100 | * * Driver for divide-and-conquer maximum contiguous 101 | * * subsequence sum algorithm. 102 | * */ 103 | int maxSubSum3( const vector & a ) 104 | { 105 | return maxSumRec( a, 0, a.size( ) - 1 ); 106 | } 107 | 108 | /** 109 | * * Linear-time maximum contiguous subsequence sum algorithm. 110 | * */ 111 | int maxSubSum4( const vector & a ) 112 | { 113 | int maxSum = 0, thisSum = 0; 114 | 115 | for( std::size_t j = 0; j < a.size( ); ++j ) 116 | { 117 | thisSum += a[ j ]; 118 | 119 | if( thisSum > maxSum ) 120 | maxSum = thisSum; 121 | else if( thisSum < 0 ) 122 | thisSum = 0; 123 | } 124 | 125 | return maxSum; 126 | } 127 | 128 | /** 129 | * * Simple test program. 130 | * */ 131 | int main( ) 132 | { 133 | vector a { 4, -3, 5, -2, -1, 2, 6, -2 }; 134 | int maxSum; 135 | 136 | maxSum = maxSubSum1( a ); 137 | cout << "Max sum is " << maxSum << endl; 138 | maxSum = maxSubSum2( a ); 139 | cout << "Max sum is " << maxSum << endl; 140 | maxSum = maxSubSum3( a ); 141 | cout << "Max sum is " << maxSum << endl; 142 | maxSum = maxSubSum4( a ); 143 | cout << "Max sum is " << maxSum << endl; 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /part2/pow.cpp: -------------------------------------------------------------------------------- 1 | /// @file pow.cpp 2 | 3 | #include 4 | using std::cin; 5 | using std::cout; 6 | using std::endl; 7 | 8 | bool isEven(int n) 9 | { 10 | return n % 2 == 0; 11 | } 12 | 13 | long long pow(long long x, int n) 14 | { 15 | if(n == 0) 16 | return 1; 17 | if(n == 1) 18 | return x; 19 | if(isEven(n)) 20 | return pow(x * x, n / 2); 21 | else 22 | return pow(x * x, n / 2) * x; 23 | } 24 | 25 | int main(int argc, char** argv) 26 | { 27 | cout << "2^61 = " << pow(2, 61) << endl; 28 | cout << "2^62 = " << pow(2, 62) << endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /part3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART3) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | else() 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Not using [Debug] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 13 | 14 | # remove every other item 15 | add_executable(removeEveryOtherItem removeEveryOtherItem.cpp) 16 | 17 | # Vector 18 | set(DEMO Vector) 19 | set(LIB ../lib/dsexceptions.h) 20 | set(SOURCE 21 | ${DEMO}Test.cpp 22 | ${DEMO}.h 23 | ${LIB}) 24 | add_executable(${DEMO} ${SOURCE}) 25 | 26 | # remove demo with own List 27 | set(DEMO remove2) 28 | set(SOURCE 29 | ${DEMO}.cpp 30 | List.h) 31 | add_executable(${DEMO} ${SOURCE}) 32 | 33 | # final test 34 | set(DEMO final) 35 | set(SOURCE 36 | ${DEMO}Test.cpp 37 | List.h 38 | Vector.h 39 | Stack.h 40 | Queue.h) 41 | add_executable(${DEMO} ${SOURCE}) -------------------------------------------------------------------------------- /part3/List.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/8/30. 3 | // 4 | 5 | #ifndef __LIST_H__ 6 | #define __LIST_H__ 7 | 8 | #include 9 | 10 | // 数据结构与算法分析 第四版 第三章 list 11 | // 双向链表 包含头指针 尾指针 12 | 13 | namespace DS 14 | { 15 | template 16 | class List 17 | { 18 | 19 | private: 20 | // list 节点 21 | struct Node 22 | { 23 | Object data_; 24 | Node* prev_; 25 | Node* next_; 26 | 27 | explicit Node(const Object& data = Object{}, Node* prev = nullptr, Node* next = nullptr): 28 | data_{data}, prev_{prev}, next_{next} 29 | {} 30 | // 移动构造 31 | explicit Node(Object&& data, Node* prev = nullptr, Node* next = nullptr): 32 | data_{std::move(data)}, prev_{prev}, next_{next} 33 | {} 34 | }; 35 | 36 | int the_size_; 37 | Node *head_; 38 | Node *tail_; 39 | 40 | public: 41 | // 常量迭代器 42 | class const_iterator 43 | { 44 | friend class List; 45 | public: 46 | const_iterator(): 47 | current_{nullptr} 48 | {} 49 | 50 | const Object& operator*() const 51 | { return retrieve(); } 52 | 53 | const_iterator& operator++() 54 | { 55 | current_ = current_->next_; 56 | return *this; 57 | } 58 | 59 | const_iterator operator++(int) 60 | { 61 | const_iterator old = *this; 62 | ++(*this); 63 | return old; 64 | } 65 | 66 | const_iterator& operator--() 67 | { 68 | current_ = current_->prev_; 69 | return *this; 70 | } 71 | 72 | const_iterator operator--(int) 73 | { 74 | const_iterator old = *this; 75 | --(*this); 76 | return old; 77 | } 78 | 79 | bool operator==(const const_iterator& rhs) const 80 | { return current_ == rhs.current_; } 81 | 82 | bool operator!=(const const_iterator& rhs) const 83 | { return current_ != rhs.current_; } 84 | 85 | protected: 86 | Node* current_; 87 | 88 | Object& retrieve() const 89 | { return current_->data_; } 90 | 91 | const_iterator(Node* p): 92 | current_{p} 93 | {} 94 | }; 95 | // 迭代器 96 | class iterator: public const_iterator 97 | { 98 | friend class List; 99 | public: 100 | iterator() = default; 101 | 102 | Object& operator*() 103 | { return const_iterator::retrieve(); } 104 | 105 | const Object& operator*() const 106 | { return const_iterator::operator*(); } 107 | 108 | iterator& operator++() 109 | { 110 | this->current_ = this->current_->next_; 111 | return *this; 112 | } 113 | 114 | iterator operator++(int) 115 | { 116 | iterator old = *this; 117 | ++(*this); 118 | return old; 119 | } 120 | 121 | iterator& operator--() 122 | { 123 | this->current_ = this->current_->prev_; 124 | return *this; 125 | } 126 | 127 | iterator operator--(int) 128 | { 129 | iterator old = *this; 130 | --(*this); 131 | return old; 132 | } 133 | 134 | bool operator== (const iterator & rhs) const 135 | { return this->current_ == rhs.current_; } 136 | 137 | bool operator!= (const iterator & rhs) const 138 | { return !(*this == rhs); } 139 | 140 | protected: 141 | iterator(Node* p): 142 | const_iterator{p} 143 | {} 144 | }; 145 | 146 | List(): 147 | the_size_{0}, head_{new Node}, tail_{new Node} 148 | { 149 | head_->next_ = tail_; 150 | tail_->prev_ = head_; 151 | } 152 | 153 | ~List() 154 | { 155 | clear(); 156 | delete head_; 157 | delete tail_; 158 | } 159 | 160 | List(const List& rhs): 161 | the_size_{0}, head_{new Node}, tail_{new Node} 162 | { 163 | // 拷贝构造函数需要对头尾指针进行初处理 164 | head_->next_ = tail_; 165 | tail_->prev_ = head_; 166 | for(auto& x : rhs) 167 | push_back(x); 168 | } 169 | 170 | List& operator= (const List& rhs) 171 | { 172 | List copy(rhs); 173 | std::swap(*this, copy); 174 | return *this; 175 | } 176 | 177 | List(List&& rhs) noexcept: 178 | the_size_{rhs.the_size_}, head_{rhs.head_}, tail_{rhs.tail_} 179 | { 180 | rhs.the_size_ = 0; 181 | // 将rhs的head和tail置空,使得rhs链表中的表节点不被delete 182 | rhs.head_ = nullptr; 183 | rhs.tail_ = nullptr; 184 | } 185 | 186 | List& operator= (List&& rhs) noexcept 187 | { 188 | // 同Vector类似,交换后不置空,由rhs调用析构函数 189 | std::swap(the_size_, rhs.the_size_); 190 | std::swap(head_, rhs.head_); 191 | std::swap(tail_, rhs.tail_); 192 | return *this; 193 | } 194 | 195 | iterator begin() 196 | { return iterator(head_->next_); } 197 | 198 | const_iterator begin() const 199 | { return const_iterator(head_->next_); } 200 | 201 | // 返回末尾元素后一个 202 | iterator end() 203 | { return iterator(tail_); } 204 | 205 | const_iterator end() const 206 | { return const_iterator(tail_); } 207 | 208 | int size() const 209 | { return the_size_; } 210 | 211 | bool empty() const 212 | { return size() == 0; } 213 | 214 | void clear() 215 | { 216 | if(!empty()) 217 | erase(begin(), end()); 218 | } 219 | 220 | Object& front() 221 | { return *begin(); } 222 | 223 | const Object& front() const 224 | { return *begin(); } 225 | 226 | Object& back() 227 | { return *--end(); } 228 | 229 | const Object& back() const 230 | { return *--end(); } 231 | 232 | void push_front(const Object& x) 233 | { insert(begin(), x); } 234 | 235 | void push_back(const Object& x) 236 | { insert(end(), x); } 237 | 238 | void push_front(Object&& x) 239 | { insert(begin(), std::move(x)); } 240 | 241 | void push_back(Object&& x) 242 | { insert(end(), std::move(x)); } 243 | 244 | void pop_front() 245 | { erase(begin()); } 246 | 247 | void pop_back() 248 | { erase(--end()); } 249 | 250 | // 在目标点之前插入节点,返回插入点 251 | iterator insert(iterator iter, const Object& x) 252 | { 253 | Node* p = iter.current_; 254 | ++the_size_; 255 | return iterator(p->prev_ = p->prev_->next_ = new Node{x, p->prev_, p}); 256 | } 257 | // 在目标点之前插入节点,返回插入点 258 | iterator insert(iterator iter, Object&& x) 259 | { 260 | Node* p = iter.current_; 261 | ++the_size_; 262 | return iterator(p->prev_ = p->prev_->next_ = new Node{std::move(x), p->prev, p}); 263 | } 264 | 265 | // 清除目标点,返回目标点的下一个点 266 | iterator erase(iterator iter) 267 | { 268 | if(iter == end()) // 如果是end(),则什么也不做,返回end() 269 | return end(); 270 | Node* p = iter.current_; 271 | iterator ret_val(p->next_); // 返回值 272 | p->prev_->next_ = p->next_; 273 | p->next_->prev_ = p->prev_; 274 | delete p; 275 | --the_size_; 276 | 277 | return ret_val; 278 | } 279 | 280 | // 删除到to之前一个node,返回to(或者list.end()) 281 | iterator erase(iterator from, iterator to) 282 | { 283 | iterator itr = from; 284 | for(; itr != to && itr != end();) 285 | itr = erase(itr); // itr更新为删除点的下一个节点 286 | return itr; 287 | } 288 | }; 289 | } 290 | 291 | #endif //__LIST_H__ -------------------------------------------------------------------------------- /part3/Queue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/8/31. 3 | // 4 | 5 | #ifndef __QUEUE_H__ 6 | #define __QUEUE_H__ 7 | 8 | #include "List.h" 9 | #include 10 | #include 11 | 12 | namespace DS 13 | { 14 | template 15 | class Queue 16 | { 17 | public: 18 | bool empty() const 19 | { return queue_.empty(); } 20 | 21 | const Object& front() const 22 | { return queue_.front(); } 23 | 24 | const Object& back() const 25 | { return queue_.back(); } 26 | 27 | void enQueue(const Object& x) 28 | { queue_.push_back(x); } 29 | 30 | void deQueue() 31 | { queue_.pop_front(); } 32 | 33 | private: 34 | List queue_; 35 | }; 36 | } 37 | 38 | #endif //__QUEUE_H__ 39 | -------------------------------------------------------------------------------- /part3/Stack.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/8/31. 3 | // 4 | 5 | #ifndef __STACK_H__ 6 | #define __STACK_H__ 7 | 8 | #include "List.h" 9 | #include 10 | 11 | namespace DS 12 | { 13 | template 14 | class Stack 15 | { 16 | public: 17 | bool empty() const 18 | { return stack_.empty(); } 19 | 20 | void push(const Object& x) 21 | { stack_.push_back(x); } 22 | 23 | const Object& top() const 24 | { return stack_.back(); } 25 | 26 | void pop() 27 | { stack_.pop_back(); } 28 | 29 | private: 30 | List stack_; 31 | }; 32 | 33 | } 34 | 35 | #endif //__STACK_H__ 36 | -------------------------------------------------------------------------------- /part3/Vector.h: -------------------------------------------------------------------------------- 1 | /// @file Vector.h 2 | 3 | #ifndef __VECTOR_H__ 4 | #define __VECTOR_H__ 5 | 6 | #define CHECK 7 | 8 | #include 9 | #include 10 | 11 | #include "../lib/dsexceptions.h" 12 | 13 | namespace DS 14 | { 15 | template 16 | class Vector 17 | { 18 | public: 19 | // const params 20 | static const unsigned int SPACE_CAPACITY = 16; 21 | // typedef 22 | typedef unsigned int size_t; 23 | 24 | explicit Vector(size_t init_size = 0): 25 | the_size_{init_size}, the_capacity_{init_size + SPACE_CAPACITY}, 26 | array_{new Object[the_capacity_]} 27 | {} 28 | 29 | Vector(const Vector& rhs): 30 | the_size_{rhs.the_size_}, the_capacity_{rhs.the_capacity_}, 31 | array_{new Object[the_capacity_]} 32 | { 33 | for(size_t idx = 0; idx < the_size_; ++idx) 34 | array_[idx] = rhs.array_[idx]; 35 | } 36 | 37 | Vector& operator= (const Vector& rhs) 38 | { 39 | Vector copy = rhs; 40 | std::swap(*this, copy); 41 | printf("Call copy =\n"); 42 | return *this; 43 | } 44 | 45 | Vector(Vector&& rhs) noexcept: 46 | the_size_{rhs.the_size_}, the_capacity_{rhs.the_capacity_}, 47 | array_{rhs.array_} 48 | { 49 | // 由于是移动构造函数,所以rhs得array被完全交付给新的类对象 50 | // 需要将临时类对象rhs.array_置空 51 | rhs.array_ = nullptr; 52 | } 53 | 54 | Vector& operator= (Vector&& rhs) noexcept 55 | { 56 | // 由于是移动赋值,当前对象得成员值被交换到临时对象rhs 57 | // 交换结束后,rhs.array_不置空,因为需要rhs得析构函数去清理rhs的array_ 58 | std::swap(the_size_, rhs.the_size_); 59 | std::swap(the_capacity_, rhs.the_capacity_); 60 | std::swap(array_, rhs.array_); 61 | printf("Call move =\n"); 62 | return *this; 63 | } 64 | 65 | ~Vector() 66 | { delete []array_; } 67 | 68 | // other items 69 | void resize(size_t new_size) 70 | { 71 | if(new_size > the_capacity_) 72 | reserve(new_size * 2); 73 | the_size_ = new_size; 74 | } 75 | 76 | void reserve(size_t new_capacity) 77 | { 78 | if(new_capacity < the_size_) 79 | return; 80 | 81 | Object* new_array = new Object[new_capacity]; 82 | for(size_t idx = 0; idx < the_size_; ++idx) 83 | new_array[idx] = std::move(array_[idx]); 84 | 85 | the_capacity_ = new_capacity; 86 | std::swap(array_, new_array); 87 | delete []new_array; 88 | } 89 | 90 | // functions 91 | Object& operator[](size_t index) 92 | { 93 | #ifdef CHECK 94 | if(index > size()) // 检查上界溢出 95 | throw ArrayIndexOutOfBoundsException{ }; 96 | #endif 97 | return array_[index]; 98 | } 99 | 100 | const Object& operator[](size_t index) const 101 | { 102 | #ifdef CHECK 103 | if(index > size()) // 检查上界溢出 104 | throw ArrayIndexOutOfBoundsException{ }; 105 | #endif 106 | return array_[index]; 107 | } 108 | 109 | bool empty() const 110 | { return size() == 0; } 111 | 112 | size_t size() const 113 | { return the_size_; } 114 | 115 | int capacity() const 116 | { return the_capacity_; } 117 | 118 | void push_back(const Object& x) 119 | { 120 | if(the_size_ == the_capacity_) 121 | reserve(2 * the_capacity_ + 1); 122 | array_[the_size_++] = x; 123 | } 124 | 125 | void push_back(Object&& x) 126 | { 127 | if(the_size_ == the_capacity_) 128 | reserve(2 * the_capacity_ + 1); // +1考虑到end()和cend()指向最后一个元素的后一位 129 | array_[the_size_++] = std::move(x); 130 | } 131 | 132 | void pop_back() // 并非真正的弹出,而是size标志-1 133 | { 134 | if(empty()) // 检查下界溢出 135 | throw UnderflowException{ }; 136 | --the_size_; 137 | } 138 | 139 | const Object& back() const 140 | { 141 | if(empty()) // 检查下界溢出 142 | throw UnderflowException{ }; 143 | return array_[the_size_ - 1]; } 144 | 145 | typedef Object* iterator; 146 | typedef const Object* const_iterator; 147 | 148 | iterator begin() 149 | { return &array_[0]; } 150 | const_iterator cbegin() const 151 | { return &array_[0]; } 152 | iterator end() // 返回最后一个元素的后一个 153 | { return &array_[size()]; } 154 | const_iterator cend() const 155 | { return &array_[size()]; } 156 | 157 | 158 | private: 159 | size_t the_size_; 160 | size_t the_capacity_; 161 | Object* array_; 162 | }; 163 | } 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /part3/VectorTest.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/8/25. 3 | // 4 | #include "Vector.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using std::cin; 11 | using std::cout; 12 | using std::endl; 13 | using DS::Vector; 14 | 15 | template 16 | void print( const Vector>& arr ) 17 | { 18 | int n_vecs = arr.size( ); 19 | 20 | for(int i = 0; i < n_vecs; ++i) 21 | { 22 | cout << "arr[" << i << "]:"; 23 | for(size_t j = 0; j < arr[i].size(); ++j) 24 | cout << " " << arr[i][j]; 25 | cout << endl; 26 | } 27 | } 28 | 29 | class CompareVector 30 | { 31 | public: 32 | bool operator() (const Vector& lhs, const Vector& rhs) 33 | { return lhs.size() < rhs.size(); } 34 | }; 35 | 36 | int main() 37 | { 38 | const int N = 20; 39 | Vector> arr(N); 40 | Vector v; 41 | 42 | for(int i = N - 1; i > 0; --i) 43 | { 44 | v.push_back(i); 45 | arr[i] = v; // 此处执行的是拷贝过程(v仍旧要使用),copy =过程调用swap,调用了两次move 46 | } 47 | 48 | print(arr); 49 | 50 | clock_t start = clock(); 51 | std::sort(arr.begin(), arr.end(), CompareVector{ }); 52 | clock_t end = clock(); 53 | printf("Sorting time: %ld\n", end - start); 54 | 55 | print(arr); 56 | 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /part3/finalTest.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/8/31. 3 | // 4 | 5 | #include "Vector.h" 6 | #include "List.h" 7 | #include "Stack.h" 8 | #include "Queue.h" 9 | #include 10 | #include 11 | 12 | using std::cin; 13 | using std::cout; 14 | using std::endl; 15 | using DS::Vector; 16 | using DS::List; 17 | using DS::Stack; 18 | using DS::Queue; 19 | 20 | static const int NUMS_PER_LINE = 14; 21 | 22 | template 23 | void printCollection(const Collection& c) 24 | { 25 | cout << "Collection contains: " << c.size() << " items" << endl; 26 | int i = 1; 27 | 28 | if(c.empty()) 29 | cout << "Empty container." << endl; 30 | else 31 | { 32 | for(auto x : c) 33 | { 34 | cout << x << " "; 35 | if(i++ % NUMS_PER_LINE == 0) 36 | cout << endl; 37 | } 38 | cout << endl; 39 | 40 | if(c.size() > NUMS_PER_LINE) 41 | return; 42 | cout << "In reverse: " << endl; 43 | for(auto ritr = std::end( c ); ritr != std::begin( c );) 44 | cout << *(--ritr) << " "; 45 | cout << endl << endl; 46 | } 47 | } 48 | 49 | int jos( int people, int passes, List & order ) 50 | { 51 | List theList; 52 | List::iterator p = std::begin( theList ); 53 | List::iterator tmp; 54 | Stack s; 55 | Queue q; 56 | 57 | order = List{ }; 58 | 59 | int i; 60 | for( i = people; i >= 1; --i ) 61 | p = theList.insert( p, i ); 62 | 63 | while( people-- != 1 ) 64 | { 65 | for( i = 0; i < passes; ++i ) 66 | if( ++p == std::end( theList ) ) 67 | p = std::begin( theList ); 68 | 69 | order.push_back( *p ); 70 | s.push( *p ); 71 | q.enQueue( *p ); 72 | tmp = p; 73 | if( ++p == std::end( theList ) ) 74 | p = std::begin( theList); 75 | theList.erase( tmp ); 76 | } 77 | 78 | if( order.size( ) % 2 == 0 ) 79 | { 80 | s.push( 0 ); 81 | q.enQueue( 0 ); 82 | } 83 | 84 | while( !s.empty( ) && !q.empty( ) ) 85 | { 86 | int x, y; 87 | s.pop(); 88 | x = s.top(); 89 | q.deQueue(); 90 | y = q.front(); 91 | if( x == y ) 92 | cout << "Middle removed is " << x << endl; 93 | } 94 | cout << "Only unremoved is "; 95 | return *std::begin( theList ); 96 | } 97 | 98 | void print(const Vector>& arr) 99 | { 100 | int n_total = arr.size(); 101 | for(int i = 0; i < n_total; ++i) 102 | { 103 | cout << "arr[" << i << "]:"; 104 | for(auto x : arr[i]) 105 | cout << " " << x; 106 | cout << endl; 107 | } 108 | } 109 | 110 | void nonsense(int people, int passes) 111 | { 112 | List last_few, the_list; 113 | cout << jos(people, passes, last_few) << endl; 114 | 115 | cout << "(Removal order)"; 116 | printCollection(last_few); 117 | } 118 | 119 | // 定义自己的比较函数 120 | class CompareList 121 | { 122 | public: 123 | bool operator() (const List& lhs, const List& rhs) const 124 | { return lhs.size() < rhs.size(); } 125 | }; 126 | 127 | int main() 128 | { 129 | const int N = 20; 130 | Vector> arr(N); 131 | List lst; 132 | 133 | for(int i = N - 1; i > 0; --i) 134 | { 135 | lst.push_back(i); 136 | arr[i] = lst; 137 | } 138 | 139 | print(arr); 140 | 141 | clock_t start = clock(); 142 | std::sort(std::begin(arr), std::end(arr), CompareList{}); 143 | clock_t end = clock(); 144 | cout << "Sorting time: " << (end - start) << endl; 145 | 146 | print(arr); 147 | 148 | nonsense(12, 0); 149 | nonsense(12, 1); 150 | 151 | return 0; 152 | } -------------------------------------------------------------------------------- /part3/remove2.cpp: -------------------------------------------------------------------------------- 1 | #include "List.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using std::cin; 7 | using std::cout; 8 | using std::endl; 9 | using std::vector; 10 | using DS::List; 11 | 12 | // 从第一个元素开始,间隔删除 13 | template 14 | void removeEveryOtherItem(Container& lst) 15 | { 16 | // using decltype to infer the iterator type 17 | auto itr = lst.begin(); 18 | while(itr != lst.end()) 19 | { 20 | itr = lst.erase(itr); 21 | if(itr != lst.end()) 22 | ++itr; 23 | } 24 | } 25 | 26 | template 27 | void print(const Container& c, std::ostream& out = cout) 28 | { 29 | if(c.empty()) 30 | out << "(empty)" << endl; 31 | else 32 | { 33 | auto itr = c.begin(); 34 | out << "[ " << *itr++; 35 | while(itr != c.end()) 36 | { 37 | out << ", " << *itr++; 38 | } 39 | out << " ]" << endl; 40 | } 41 | } 42 | 43 | int main(int argc, char** argv) 44 | { 45 | List lst; 46 | for(int i = 0; i < 9; ++i) 47 | lst.push_back( i ); 48 | 49 | removeEveryOtherItem(lst); 50 | print(lst, cout); 51 | 52 | clock_t start, end; 53 | 54 | for( int N = 1001; N <= 5000; N *= 2 ) 55 | { 56 | List list1; 57 | vector vec; 58 | 59 | for( int i = 0; i < N; ++i ) 60 | { 61 | list1.push_back( i ); 62 | vec.push_back( i ); 63 | } 64 | 65 | start = clock( ); 66 | removeEveryOtherItem( list1 ); 67 | end = clock( ); 68 | cout << "list " << N << " " << double(end-start)/CLOCKS_PER_SEC << endl; 69 | 70 | start = clock( ); 71 | removeEveryOtherItem( vec ); 72 | end = clock( ); 73 | cout << "vector " << N << " " << double(end-start)/CLOCKS_PER_SEC << endl; 74 | } 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /part3/removeEveryOtherItem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::cin; 7 | using std::cout; 8 | using std::endl; 9 | using std::list; 10 | using std::vector; 11 | 12 | // 从第一个元素开始,间隔删除 13 | template 14 | void removeEveryOtherItem(Container& lst) 15 | { 16 | // using decltype to infer the iterator type 17 | decltype(lst.begin()) itr = lst.begin(); 18 | while(itr != lst.end()) 19 | { 20 | itr = lst.erase(itr); 21 | if(itr != lst.end()) 22 | ++itr; 23 | } 24 | } 25 | 26 | template 27 | void print(const Container& c, std::ostream& out = cout) 28 | { 29 | if(c.empty()) 30 | out << "(empty)" << endl; 31 | else 32 | { 33 | auto itr = std::begin(c); 34 | out << "[ " << *itr++; 35 | while(itr != std::end(c)) 36 | out << ", " << *itr++; 37 | out << " ]" << endl; 38 | } 39 | } 40 | 41 | int main(int argc, char** argv) 42 | { 43 | list lst; 44 | for(int i = 0; i < 9; ++i) 45 | lst.push_back( i ); 46 | 47 | removeEveryOtherItem(lst); 48 | print(lst, cout); 49 | 50 | clock_t start, end; 51 | 52 | for( int N = 100001; N <= 1000000; N *= 2 ) 53 | { 54 | list list1; 55 | vector vec; 56 | 57 | for( int i = 0; i < N; ++i ) 58 | { 59 | list1.push_back( i ); 60 | vec.push_back( i ); 61 | } 62 | 63 | start = clock( ); 64 | removeEveryOtherItem( list1 ); 65 | end = clock( ); 66 | cout << "list " << N << " " << double(end-start)/CLOCKS_PER_SEC << endl; 67 | 68 | start = clock( ); 69 | removeEveryOtherItem( vec ); 70 | end = clock( ); 71 | cout << "vector " << N << " " << double(end-start)/CLOCKS_PER_SEC << endl; 72 | } 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /part4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART3) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | else() 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Not using [Debug] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 13 | 14 | # binary_search_tree 15 | set(DEMO binary_search_tree) 16 | set(LIB ../lib/dsexceptions.h) 17 | set(SOURCE 18 | ${DEMO}_test.cpp 19 | ${DEMO}.hpp 20 | ${LIB}) 21 | add_executable(${DEMO} ${SOURCE}) 22 | 23 | # avl_tree 24 | set(DEMO avl_tree) 25 | set(LIB ../lib/dsexceptions.h) 26 | set(SOURCE 27 | ${DEMO}_test.cpp 28 | ${DEMO}.hpp 29 | ${LIB}) 30 | add_executable(${DEMO} ${SOURCE}) 31 | 32 | # word_ladder: the use of map 33 | set(DEMO word_ladder) 34 | set(SOURCE ${DEMO}.cpp) 35 | add_executable(${DEMO} ${SOURCE}) -------------------------------------------------------------------------------- /part4/avl_tree.hpp: -------------------------------------------------------------------------------- 1 | // 平衡树 2 | 3 | #ifndef __AVL_TREE_HPP__ 4 | #define __AVL_TREE_HPP__ 5 | 6 | #include "../lib/dsexceptions.h" 7 | #include 8 | 9 | // AVL Tree ADT 10 | // 二叉平衡树 11 | // 非优化平衡树,平衡调节通过旋转,每次插入删除均进行平衡调整 12 | // 需要实现的功能 13 | // 14 | // ******************PUBLIC OPERATIONS********************* 15 | // void insert( x ) --> Insert x 16 | // void remove( x ) --> Remove x 17 | // bool contains( x ) --> Return true if x is present 18 | // Object findMin( ) --> Return smallest item 19 | // Object findMax( ) --> Return largest item 20 | // bool empty( ) --> Return true if empty; else false 21 | // void clear( ) --> Remove all items 22 | // void printTree( ) --> Print tree in sorted order 23 | // int height() --> the height of the tree 24 | // ******************ERRORS******************************** 25 | // Throws UnderflowException as warranted 26 | 27 | namespace DS 28 | { 29 | template 30 | class AVLTree 31 | { 32 | private: 33 | class TreeNode 34 | { 35 | public: 36 | Object element_; 37 | TreeNode* left_; 38 | TreeNode* right_; 39 | int height_; 40 | 41 | explicit TreeNode(const Object& element, TreeNode* lt = nullptr, TreeNode* rt = nullptr, int h = 0) 42 | : element_{element}, left_{lt}, right_{rt}, height_{h} 43 | {} 44 | 45 | explicit TreeNode(Object&& element, TreeNode* lt = nullptr, TreeNode* rt = nullptr, int h = 0) 46 | : element_{std::move(element)}, left_{lt}, right_{rt}, height_{h} 47 | {} 48 | }; 49 | 50 | // 返回节点node的高度 51 | int height(TreeNode* node) const 52 | { return (nullptr == node) ? -1 : node->height_; } 53 | 54 | void adjustHeight(TreeNode*& node) 55 | { 56 | int h_l = height(node->left_), h_r = height(node->right_); 57 | node->height_ = (h_l > h_r ? h_l : h_r) + 1; 58 | } 59 | 60 | TreeNode* cloneTree(TreeNode* root) const 61 | { 62 | if(root) // 树深拷贝,递归复制树的左子树,右子树 63 | return new TreeNode(root->element_, cloneTree(root->left_), cloneTree(root->right_)); 64 | else 65 | return nullptr; 66 | } 67 | 68 | void clearTree(TreeNode*& node) // 删除树,递归删除树左右子树 69 | { 70 | if(node) 71 | { 72 | clearTree(node->left_); 73 | clearTree(node->right_); 74 | delete node; 75 | } 76 | node = nullptr; // 安全处理,防止脏内存 77 | } 78 | 79 | TreeNode* findMinProcess(TreeNode* node) const 80 | { 81 | if(node == nullptr) 82 | return nullptr; 83 | while(node->left_) 84 | node = node->left_; 85 | return node; 86 | } 87 | 88 | TreeNode* findMaxProcess(TreeNode* node) const 89 | { 90 | if(node == nullptr) 91 | return nullptr; 92 | while(node->right_) 93 | node = node->right_; 94 | return node; 95 | } 96 | 97 | bool containsProcess(const Object& x, TreeNode* node) const 98 | { 99 | if(node == nullptr) 100 | return false; 101 | else if(node->element_ > x) 102 | return containsProcess(x, node->left_); 103 | else if(node->element_ < x) 104 | return containsProcess(x, node->right_); 105 | else 106 | return true; 107 | } 108 | 109 | void printTreeReverseProcess(TreeNode* node, std::ostream& out = std::cout) const 110 | { 111 | if(node == nullptr) 112 | return; 113 | printTreeReverseProcess(node->right_); 114 | out << node->element_ << std::endl; 115 | printTreeReverseProcess(node->left_); 116 | } 117 | 118 | void printTreeProcess(TreeNode* node, std::ostream& out = std::cout) const 119 | { 120 | if(node == nullptr) 121 | return; 122 | printTreeProcess(node->left_); 123 | out << node->element_ << std::endl; 124 | printTreeProcess(node->right_); 125 | } 126 | 127 | // 在插入后进行平衡调整 128 | // 递归进行平衡调整 129 | void insertProcess(const Object& x, TreeNode*& node) 130 | { 131 | if(node == nullptr) 132 | node = new TreeNode(x); 133 | else if(x > node->element_) 134 | insertProcess(x, node->right_); 135 | else if(x < node->element_) 136 | insertProcess(x, node->left_); 137 | balance(node); 138 | } 139 | 140 | // 在插入后进行平衡调整 141 | // 递归进行平衡调整 142 | void insertProcess(Object&& x, TreeNode*& node) 143 | { 144 | if(node == nullptr) 145 | node = new TreeNode(std::move(x)); 146 | else if(x > node->element_) 147 | insertProcess(std::move(x), node->right_); 148 | else if(x < node->element_) 149 | insertProcess(std::move(x), node->left_); 150 | balance(node); 151 | } 152 | 153 | // 在删除后进行平衡调整 154 | // 递归进行平衡调整 155 | void removeProcess(const Object& x, TreeNode*& node) 156 | { 157 | if(node == nullptr) 158 | return; 159 | if(node->element_ > x) 160 | removeProcess(x, node->left_); 161 | else if(node->element_ < x) 162 | removeProcess(x, node->right_); 163 | else 164 | { 165 | if(node->left_ == nullptr || node->right_ == nullptr) 166 | { 167 | TreeNode* old_node = node; 168 | // x存在空子树 169 | // 设置成非空子树的根,或者置空 170 | node = (node->left_ == nullptr) ? node->right_ : node->left_; 171 | delete old_node; 172 | } 173 | else 174 | { 175 | // 如果x左右均非空,将x换成左子树的最大点(或者右子树的最小点) 176 | // 递归删除左子树最大点(右子树最小点) 177 | node->element_ = findMaxProcess(node->left_)->element_; 178 | removeProcess(node->element_, node->left_); 179 | } 180 | } 181 | balance(node); 182 | } 183 | 184 | static const int ALLOWED_IMBALANCE = 1; 185 | 186 | void balance(TreeNode*& node) 187 | { 188 | if(node == nullptr) 189 | return; 190 | if(height(node->left_) - height(node->right_) > ALLOWED_IMBALANCE) // 左端失衡 191 | { 192 | if(height(node->left_->left_) >= height(node->left_->right_)) // 左左,向右单次旋转 193 | rotateWithLeftChild(node); 194 | else // 左右,双旋转 左旋->右旋 195 | doubleWithLeftChild(node); 196 | } 197 | else if(height(node->right_) - height(node->left_) > ALLOWED_IMBALANCE) // 右端失衡 198 | { 199 | if(height(node->right_->right_) >= height(node->right_->left_)) // 右右,向左单次旋转 200 | rotateWithRightChild(node); 201 | else // 右左,双旋转 右旋->左旋 202 | doubleWithRightChild(node); 203 | } 204 | adjustHeight(node); 205 | } 206 | 207 | void rotateWithLeftChild(TreeNode*& root) 208 | { 209 | // new_root 作为新的 root 210 | // root 作为 new_root->right 211 | TreeNode* new_root = root->left_; 212 | root->left_ = new_root->right_; 213 | new_root->right_ = root; 214 | // adjust height 215 | adjustHeight(root); // 先调整 root(new_root的子树) 216 | adjustHeight(new_root); // 再调整 new_root 217 | root = new_root; // 修改parent指针 218 | } 219 | 220 | void rotateWithRightChild(TreeNode*& root) 221 | { 222 | // new_root 作为新的 root 223 | // root 作为 new_root->left 224 | TreeNode* new_root = root->right_; 225 | root->right_ = new_root->left_; 226 | new_root->left_ = root; 227 | // adjust height 228 | adjustHeight(root); // 先调整 root(new_root的子树) 229 | adjustHeight(new_root); // 再调整 new_root 230 | root = new_root; // 修改parent指针 231 | } 232 | 233 | void doubleWithLeftChild(TreeNode*& root) 234 | { 235 | rotateWithRightChild(root->left_); 236 | rotateWithLeftChild(root); 237 | } 238 | 239 | void doubleWithRightChild(TreeNode*& root) 240 | { 241 | rotateWithLeftChild(root->right_); 242 | rotateWithRightChild(root); 243 | } 244 | 245 | TreeNode* root_; 246 | 247 | public: 248 | AVLTree() 249 | : root_{nullptr} 250 | {} 251 | 252 | // 拷贝,由于并没有使用智能指针,需要进行完全复制深拷贝clone 253 | AVLTree(const AVLTree& rhs) 254 | : root_{nullptr} 255 | { root_ = cloneTree(rhs.root_); } 256 | 257 | AVLTree(AVLTree&& rhs) noexcept 258 | : root_{rhs.root_} 259 | { rhs.root_ = nullptr; } 260 | 261 | ~AVLTree() 262 | { clear(); } 263 | 264 | AVLTree& operator=(const AVLTree& rhs) 265 | { 266 | AVLTree copy(rhs); 267 | std::swap(*this, copy); 268 | return *this; 269 | } 270 | 271 | AVLTree& operator=(AVLTree&& rhs) noexcept 272 | { 273 | std::swap(root_, rhs.root_); 274 | return *this; 275 | } 276 | 277 | // 判断空树 278 | bool empty() const 279 | { return root_ == nullptr; } 280 | 281 | // 判断树是否包含x 282 | bool contains(const Object& x) const 283 | { 284 | return containsProcess(x, root_); 285 | } 286 | 287 | const Object& findMin() const 288 | { 289 | if(empty()) 290 | throw UnderflowException{}; 291 | return findMinProcess(root_)->element_; 292 | } 293 | 294 | const Object& findMax() const 295 | { 296 | if(empty()) 297 | throw UnderflowException{}; 298 | return findMaxProcess(root_)->element_; 299 | } 300 | 301 | // 按照排序顺序打印所有节点值,默认升序 302 | void printTree(std::ostream& out = std::cout, bool reverse = false) const 303 | { 304 | if(empty()) 305 | out << "Empty tree" << std::endl; 306 | else if(reverse) 307 | printTreeReverseProcess(root_, out); 308 | else 309 | printTreeProcess(root_, out); 310 | } 311 | 312 | void clear() 313 | { clearTree(root_); } 314 | 315 | // 插入,重复项不考虑 316 | void insert(const Object& x) 317 | { 318 | insertProcess(x, root_); 319 | } 320 | 321 | // 插入,重复项不考虑 322 | void insert(Object&& x) 323 | { 324 | insertProcess(std::move(x), root_); 325 | } 326 | 327 | // 删除x,存在则删除,不存在则不进行操作 328 | void remove(const Object& x) 329 | { 330 | removeProcess(x, root_); 331 | } 332 | }; 333 | } 334 | #endif //__AVL_TREE_HPP__ 335 | -------------------------------------------------------------------------------- /part4/avl_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "avl_tree.hpp" 3 | using namespace std; 4 | using DS::AVLTree; 5 | 6 | // Test program 7 | int main() 8 | { 9 | AVLTree t; 10 | int NUMS = 20000; 11 | const int GAP = 37; 12 | int i; 13 | 14 | cout << "Checking... (no more output means success)" << endl; 15 | 16 | for(i = GAP; i != 0; i = (i + GAP) % NUMS) 17 | t.insert(i); 18 | t.remove(0); 19 | for(i = 1; i < NUMS; i += 2) 20 | t.remove(i); 21 | 22 | if(NUMS < 40) 23 | t.printTree(); 24 | if(t.findMin() != 2 || t.findMax() != NUMS - 2) 25 | cout << "FindMin or FindMax error!" << endl; 26 | 27 | for(i = 2; i < NUMS; i += 2) 28 | if(!t.contains(i)) 29 | cout << "Find error1: " << i << endl; 30 | 31 | for(i = 1; i < NUMS; i += 2) 32 | { 33 | if(t.contains(i)) 34 | cout << "Find error2: " << i << endl; 35 | } 36 | 37 | AVLTree t2; 38 | t2 = t; 39 | 40 | for(i = 2; i < NUMS; i += 2) 41 | if(!t2.contains(i)) 42 | cout << "Find error1: " << i << endl; 43 | 44 | for(i = 1; i < NUMS; i += 2) 45 | { 46 | if(t2.contains(i)) 47 | cout << "Find error2: " << i << endl; 48 | } 49 | 50 | cout << "End of test..." << endl; 51 | return 0; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /part4/binary_search_tree.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/9/5. 3 | // 4 | #ifndef __BINARY_SEARCH_TREE_HPP__ 5 | #define __BINARY_SEARCH_TREE_HPP__ 6 | 7 | #include "../lib/dsexceptions.h" 8 | #include 9 | 10 | // BinarySearchTree ADT 11 | // 二叉搜索(排序)树 12 | // 需要实现的功能 13 | // 14 | // ******************PUBLIC OPERATIONS********************* 15 | // void insert( x ) --> Insert x 16 | // void remove( x ) --> Remove x 17 | // bool contains( x ) --> Return true if x is present 18 | // Object findMin( ) --> Return smallest item 19 | // Object findMax( ) --> Return largest item 20 | // bool empty( ) --> Return true if empty; else false 21 | // void clear( ) --> Remove all items 22 | // void printTree( ) --> Print tree in sorted order 23 | // ******************ERRORS******************************** 24 | // Throws UnderflowException as warranted 25 | // 插入方案: 26 | // 插入的x > 节点值, 插入到右子树,x < 节点值, 插入到左子树,不考虑x = 节点值的情况 27 | // 删除节点方案: 28 | // 寻找x,如果没找到,什么都不做 29 | // 如果找到x 30 | // 如果x是叶节点,直接删除 31 | // 如果x不是叶节点,将x换成左子树的最大点(或者右子树的最小点) 32 | // 递归删除左子树最大点(右子树最小点) 33 | 34 | namespace DS 35 | { 36 | template 37 | class BinarySearchTree 38 | { 39 | private: 40 | class TreeNode 41 | { 42 | public: 43 | Object element_; 44 | TreeNode* left_; 45 | TreeNode* right_; 46 | 47 | explicit TreeNode(const Object& element, TreeNode* lt = nullptr, TreeNode* rt = nullptr) 48 | : element_{element}, left_{lt}, right_{rt} 49 | {} 50 | 51 | explicit TreeNode(Object&& element, TreeNode* lt = nullptr, TreeNode* rt = nullptr) 52 | : element_{std::move(element)}, left_{lt}, right_{rt} 53 | {} 54 | }; 55 | 56 | TreeNode* cloneTree(TreeNode* root) const 57 | { 58 | if(root) // 树深拷贝,递归复制树的左子树,右子树 59 | return new TreeNode(root->element_, cloneTree(root->left_), cloneTree(root->right_)); 60 | else 61 | return nullptr; 62 | } 63 | 64 | void clearTree(TreeNode*& node) // 删除树,递归删除树左右子树 65 | { 66 | if(node) 67 | { 68 | clearTree(node->left_); 69 | clearTree(node->right_); 70 | delete node; 71 | } 72 | node = nullptr; // 安全处理,防止脏内存 73 | } 74 | 75 | TreeNode* findMinProcess(TreeNode* node) const 76 | { 77 | if(node == nullptr) 78 | return nullptr; 79 | while(node->left_) 80 | node = node->left_; 81 | return node; 82 | } 83 | 84 | TreeNode* findMaxProcess(TreeNode* node) const 85 | { 86 | if(node == nullptr) 87 | return nullptr; 88 | while(node->right_) 89 | node = node->right_; 90 | return node; 91 | } 92 | 93 | bool containsProcess(const Object& x, TreeNode* node) const 94 | { 95 | if(node == nullptr) 96 | return false; 97 | else if(node->element_ > x) 98 | return containsProcess(x, node->left_); 99 | else if(node->element_ < x) 100 | return containsProcess(x, node->right_); 101 | else 102 | return true; 103 | } 104 | 105 | void printTreeReverseProcess(TreeNode* node, std::ostream& out = std::cout) const 106 | { 107 | if(node == nullptr) 108 | return; 109 | printTreeReverseProcess(node->right_); 110 | out << node->element_ << std::endl; 111 | printTreeReverseProcess(node->left_); 112 | } 113 | 114 | void printTreeProcess(TreeNode* node, std::ostream& out = std::cout) const 115 | { 116 | if(node == nullptr) 117 | return; 118 | printTreeProcess(node->left_); 119 | out << node->element_ << std::endl; 120 | printTreeProcess(node->right_); 121 | } 122 | 123 | // 由于需要永久修改节点指针指向的元素 124 | // 所以采用TreeNode*&,指针的引用 / 或者 TreeNode** 125 | void insertProcess(const Object& x, TreeNode*& node) 126 | { 127 | if(node == nullptr) 128 | node = new TreeNode(x); 129 | else if(x > node->element_) 130 | insertProcess(x, node->right_); 131 | else if(x < node->element_) 132 | insertProcess(x, node->left_); 133 | } 134 | 135 | // 由于需要永久修改节点指针指向的元素 136 | // 所以采用TreeNode*&,指针的引用 / 或者 TreeNode** 137 | void insertProcess(Object&& x, TreeNode*& node) 138 | { 139 | if(node == nullptr) 140 | node = new TreeNode(std::move(x)); 141 | else if(x > node->element_) 142 | insertProcess(std::move(x), node->right_); 143 | else if(x < node->element_) 144 | insertProcess(std::move(x), node->left_); 145 | } 146 | 147 | // 由于需要永久修改节点指针指向的元素 148 | // 所以采用TreeNode*&,指针的引用 / 或者 TreeNode** 149 | void removeProcess(const Object& x, TreeNode*& node) 150 | { 151 | if(node == nullptr) 152 | return; 153 | if(node->element_ > x) 154 | removeProcess(x, node->left_); 155 | else if(node->element_ < x) 156 | removeProcess(x, node->right_); 157 | else 158 | { 159 | if(node->left_ == nullptr || node->right_ == nullptr) 160 | { 161 | TreeNode* old_node = node; 162 | // x存在空子树 163 | // 设置成非空子树的根,或者置空 164 | node = (node->left_ == nullptr) ? node->right_ : node->left_; 165 | delete old_node; 166 | } 167 | else 168 | { 169 | // 如果x左右均非空,将x换成左子树的最大点(或者右子树的最小点) 170 | // 递归删除左子树最大点(右子树最小点) 171 | node->element_ = findMaxProcess(node->left_)->element_; 172 | removeProcess(node->element_, node->left_); 173 | // node->element_ = findMinProcess(node->right_)->element_; 174 | // removeProcess(node->element_, node->right_); 175 | } 176 | } 177 | } 178 | 179 | TreeNode* root_; 180 | 181 | public: 182 | BinarySearchTree() 183 | : root_{nullptr} 184 | {} 185 | 186 | // 拷贝,由于并没有使用智能指针,需要进行完全复制深拷贝clone 187 | BinarySearchTree(const BinarySearchTree& rhs) 188 | : root_{nullptr} 189 | { root_ = cloneTree(rhs.root_); } 190 | 191 | BinarySearchTree(BinarySearchTree&& rhs) noexcept 192 | : root_{rhs.root_} 193 | { rhs.root_ = nullptr; } 194 | 195 | ~BinarySearchTree() 196 | { clear(); } 197 | 198 | BinarySearchTree& operator=(const BinarySearchTree& rhs) 199 | { 200 | BinarySearchTree copy(rhs); 201 | std::swap(*this, copy); 202 | return *this; 203 | } 204 | 205 | BinarySearchTree& operator=(BinarySearchTree&& rhs) noexcept 206 | { 207 | std::swap(root_, rhs.root_); 208 | return *this; 209 | } 210 | 211 | // 判断空树 212 | bool empty() const 213 | { return root_ == nullptr; } 214 | 215 | // 判断树是否包含x 216 | bool contains(const Object& x) const 217 | { 218 | return containsProcess(x, root_); 219 | } 220 | 221 | const Object& findMin() const 222 | { 223 | if(empty()) 224 | throw UnderflowException{}; 225 | return findMinProcess(root_)->element_; 226 | } 227 | 228 | const Object& findMax() const 229 | { 230 | if(empty()) 231 | throw UnderflowException{}; 232 | return findMaxProcess(root_)->element_; 233 | } 234 | 235 | // 按照排序顺序打印所有节点值,默认升序 236 | void printTree(std::ostream& out = std::cout, bool reverse = false) const 237 | { 238 | if(empty()) 239 | out << "Empty tree" << std::endl; 240 | else if(reverse) 241 | printTreeReverseProcess(root_, out); 242 | else 243 | printTreeProcess(root_, out); 244 | } 245 | 246 | void clear() 247 | { clearTree(root_); } 248 | 249 | // 插入,重复项不考虑 250 | void insert(const Object& x) 251 | { 252 | insertProcess(x, root_); 253 | } 254 | 255 | // 插入,重复项不考虑 256 | void insert(Object&& x) 257 | { 258 | insertProcess(std::move(x), root_); 259 | } 260 | 261 | // 删除x,存在则删除,不存在则不进行操作 262 | void remove(const Object& x) 263 | { 264 | removeProcess(x, root_); 265 | } 266 | }; 267 | } 268 | #endif //__BINARY_SEARCH_TREE_HPP__ 269 | -------------------------------------------------------------------------------- /part4/binary_search_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "binary_search_tree.hpp" 3 | using namespace std; 4 | using DS::BinarySearchTree; 5 | 6 | // Test program 7 | int main() 8 | { 9 | BinarySearchTree t; 10 | int NUMS = 20000; 11 | const int GAP = 37; 12 | int i; 13 | 14 | cout << "Checking... (no more output means success)" << endl; 15 | 16 | for(i = GAP; i != 0; i = (i + GAP) % NUMS) 17 | t.insert(i); 18 | t.remove(0); 19 | for(i = 1; i < NUMS; i += 2) 20 | t.remove(i); 21 | 22 | if(NUMS < 40) 23 | t.printTree(); 24 | if(t.findMin() != 2 || t.findMax() != NUMS - 2) 25 | cout << "FindMin or FindMax error!" << endl; 26 | 27 | for(i = 2; i < NUMS; i += 2) 28 | if(!t.contains(i)) 29 | cout << "Find error1: " << i << endl; 30 | 31 | for(i = 1; i < NUMS; i += 2) 32 | { 33 | if(t.contains(i)) 34 | cout << "Find error2: " << i << endl; 35 | } 36 | 37 | BinarySearchTree t2; 38 | t2 = t; 39 | 40 | for(i = 2; i < NUMS; i += 2) 41 | if(!t2.contains(i)) 42 | cout << "Find error1: " << i << endl; 43 | 44 | for(i = 1; i < NUMS; i += 2) 45 | { 46 | if(t2.contains(i)) 47 | cout << "Find error2: " << i << endl; 48 | } 49 | 50 | cout << "End of test..." << endl; 51 | return 0; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /part4/word_ladder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/10/7. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | void readWords(ifstream& in, vector& container) 15 | { 16 | string line; 17 | while(in >> line) 18 | container.push_back(line); 19 | } 20 | 21 | // Computes a map in which the keys are words and values are vectors of words 22 | // that differ in only one character from the corresponding key. 23 | // Uses an efficient algorithm that is O(N log N) with a map, or 24 | // O(N) is a hash_map is used. 25 | void computeAdjacentWords(const vector& words, map>& adj_words) 26 | { 27 | map> words_by_length; 28 | 29 | // 根据单词长度划分分组 30 | for(auto & word : words) 31 | words_by_length[word.size()].push_back(word); 32 | 33 | // 对于每个分组 34 | for(auto & entry : words_by_length) 35 | { 36 | const vector & group_words{entry.second}; 37 | int word_length = entry.first; 38 | 39 | // 对单词的每一个位置 40 | for(int i = 0; i < word_length; ++i) 41 | { 42 | // Remove one character in specified position, computing representative. 43 | // Words with same representatives are adjacent 44 | map> rep_to_word; 45 | for(auto & word : group_words) 46 | { 47 | string rep = word; 48 | rep.erase(i, 1); 49 | rep_to_word[rep].push_back(word); 50 | } 51 | 52 | // and then look for map values with more than one string 53 | for(auto & word : rep_to_word) 54 | { 55 | const vector & clique = word.second; 56 | if(clique.size() > 1) 57 | { 58 | // 单词两两之间配对,加入adj_words 59 | for(size_t p = 0; p < clique.size(); ++p) 60 | { 61 | for(size_t q = p + 1; q < clique.size(); ++q) 62 | { 63 | adj_words[clique[p]].push_back(clique[q]); 64 | adj_words[clique[q]].push_back(clique[p]); 65 | } 66 | } 67 | } 68 | } 69 | } 70 | } 71 | } 72 | 73 | void printHighChangeables(const map>& adj_word, int min_words = 15) 74 | { 75 | if(min_words <= 0) 76 | return; 77 | for(auto & entry : adj_word) 78 | { 79 | const vector& words = entry.second; 80 | if(words.size() >= min_words) 81 | { 82 | cout << entry.first << " (" << words.size() << "):"; 83 | for(auto & str : words) 84 | cout << " " << str; 85 | cout << endl; 86 | } 87 | } 88 | } 89 | 90 | int main() 91 | { 92 | clock_t start, end; 93 | ifstream file("../../dict.txt"); 94 | if (!file.is_open()) 95 | { 96 | cout << "Error opening file"; 97 | exit (1); 98 | } 99 | vector words(32, string{}); 100 | // read words from dict.txt 101 | readWords(file, words); 102 | 103 | map> adjacent_words; 104 | 105 | start = clock(); 106 | computeAdjacentWords(words, adjacent_words); 107 | end = clock(); 108 | cout << "Elapsed time FAST: " << double(end - start) / CLOCKS_PER_SEC << endl; 109 | 110 | printHighChangeables(adjacent_words, 15); 111 | } -------------------------------------------------------------------------------- /part5/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART5) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | else() 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Not using [Debug] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # three type hash table 三种hash方案 15 | 16 | # separate chaining 分离链接型 17 | set(DEMO separate_chaining) 18 | set(LIB ../lib/dsexceptions.h) 19 | set(SOURCE 20 | ${DEMO}_test.cpp 21 | ${DEMO}.hpp 22 | ${LIB}) 23 | add_executable(${DEMO} ${SOURCE}) 24 | 25 | # quadratic probing 二次再探型 26 | set(DEMO quadratic_probing) 27 | set(LIB ../lib/dsexceptions.h) 28 | set(SOURCE 29 | ${DEMO}_test.cpp 30 | ${DEMO}.hpp 31 | ${LIB}) 32 | add_executable(${DEMO} ${SOURCE}) 33 | 34 | # cuckoo hash family 35 | set(DEMO cuckoo_hash) 36 | set(LIB ../lib) 37 | set(SOURCE 38 | ${DEMO}_test.cpp 39 | ${DEMO}.hpp 40 | ${LIB}) 41 | add_executable(${DEMO} ${SOURCE}) 42 | 43 | # use_of_unordered_set 44 | set(DEMO use_of_unordered_set) 45 | set(SOURCE ${DEMO}.cpp) 46 | add_executable(${DEMO} ${SOURCE}) 47 | -------------------------------------------------------------------------------- /part5/cuckoo_hash.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 二次再探型 hash table 3 | * key出现冲突时采用二次再探法寻找下一个key 4 | * 出现冲突按照链表形式在key后增加元素 5 | */ 6 | 7 | #ifndef CUCKOO_HASH_HPP 8 | #define CUCKOO_HASH_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../lib/uniform_random.h" 17 | 18 | #define MAX_LOAD 0.40 19 | 20 | namespace DS 21 | { 22 | // 判断素数 23 | bool isPrime(int n) 24 | { 25 | if (n < 2 || (n & 1) == 0) 26 | return false; 27 | if (n == 2 || n == 3) 28 | return true; 29 | for (int i = 3; i * i <= n; i += 2) { 30 | if (n % i == 0) 31 | return false; 32 | } 33 | return true; 34 | } 35 | 36 | int nextPrime(int n) 37 | { 38 | if(n < 1) 39 | return 2; 40 | if((n & 1) == 0) 41 | ++n; 42 | for(; !isPrime(n); n += 2) 43 | ; 44 | return n; 45 | } 46 | 47 | // hash function for string 48 | int hashCode(const std::string& key) 49 | { 50 | int hashVal = 0; 51 | for(auto ch : key) 52 | hashVal = 37 * hashVal + ch; 53 | return hashVal; 54 | } 55 | 56 | int hashCode(int key) 57 | { return key; } 58 | 59 | template 60 | class CuckooHashFamily 61 | { 62 | public: 63 | virtual std::size_t hash(const AnyType & x, int which) const = 0; 64 | virtual int getNumberOfFunctions() = 0; 65 | virtual void generateNewFunctions() = 0; 66 | }; 67 | 68 | template 69 | class StringHashFamily : public CuckooHashFamily 70 | { 71 | public: 72 | StringHashFamily() 73 | : MULTIPLIERS_(count) 74 | { 75 | generateNewFunctions(); 76 | } 77 | 78 | int getNumberOfFunctions() override 79 | { return count; } 80 | 81 | void generateNewFunctions() override 82 | { 83 | for(auto& mult : MULTIPLIERS_) 84 | mult = r_.nextInt(); 85 | } 86 | 87 | // 根据which, 使用不同的hash函数 88 | std::size_t hash(const std::string& x, int which) const override 89 | { 90 | const int multiplier = MULTIPLIERS_[which]; 91 | size_t hash_val = 0; 92 | 93 | for(auto ch : x) 94 | hash_val = multiplier * hash_val + ch; 95 | return hash_val; 96 | } 97 | private: 98 | std::vector MULTIPLIERS_; 99 | UniformRandom r_; 100 | }; 101 | 102 | // CuckooHashing Hash table class 103 | // 104 | // CONSTRUCTION: an approximate initial size or default of 101 105 | // 106 | // ******************PUBLIC OPERATIONS********************* 107 | // bool insert( x ) --> Insert x 108 | // bool remove( x ) --> Remove x 109 | // bool contains( x ) --> Return true if x is present 110 | // void makeEmpty( ) --> Remove all items 111 | // int hashCode( string str ) --> Global method to hash strings 112 | 113 | template 114 | class HashTable 115 | { 116 | public: 117 | explicit HashTable(int size = 101) 118 | : array_(nextPrime(size)) 119 | { 120 | n_hash_functions_ = hash_functions_.getNumberOfFunctions(); 121 | rehashes_ = 0; 122 | makeEmpty(); 123 | } 124 | 125 | bool contains(const Object& x) const 126 | { 127 | return findPos(x) != -1; 128 | } 129 | 130 | void makeEmpty() 131 | { 132 | current_size_ = 0; 133 | for(auto& entry : array_) // 惰性删除 134 | entry.is_active_ = false; 135 | } 136 | 137 | bool insert(const Object& x) 138 | { 139 | if(contains(x)) 140 | return false; 141 | // 超出了最大容量 142 | if(current_size_ >= array_.size() * MAX_LOAD) 143 | expand(); 144 | return insertHelper1(x); 145 | } 146 | 147 | bool insert(Object&& x) 148 | { 149 | if(contains(x)) 150 | return false; 151 | // 超出了最大容量 152 | if(current_size_ >= array_.size() * MAX_LOAD) 153 | expand(); 154 | return insertHelper1(std::move(x)); 155 | } 156 | 157 | int size() const 158 | { return current_size_; } 159 | 160 | int capacity() const 161 | { return array_.size(); } 162 | 163 | bool remove(const Object& x) 164 | { 165 | int pos = findPos(x); 166 | if(!isActive(pos)) 167 | return false; 168 | array_[pos].is_active_ = false; 169 | --current_size_; 170 | return true; 171 | } 172 | 173 | private: 174 | struct HashEntry 175 | { 176 | Object element_; 177 | bool is_active_; 178 | 179 | explicit HashEntry(const Object& e = Object(), bool a = false) 180 | : element_{e}, is_active_{a} 181 | {} 182 | 183 | explicit HashEntry(Object&& e, bool a = false) 184 | : element_{std::move(e)}, is_active_{a} 185 | {} 186 | }; 187 | 188 | std::vector array_; 189 | int current_size_; 190 | int n_hash_functions_; 191 | int rehashes_; 192 | UniformRandom r_; 193 | HashFamily hash_functions_; 194 | 195 | static const int ALLOWED_REHASHES = 5; 196 | 197 | bool insertHelper1(const Object& xx) 198 | { 199 | const int COUNT_LIMIT = 100; 200 | Object x = xx; 201 | while(true) 202 | { 203 | int last_pos = -1; 204 | int pos; 205 | 206 | for(int count = 0; count < COUNT_LIMIT; ++count) 207 | { 208 | for(int i = 0; i < n_hash_functions_; ++i) 209 | { 210 | pos = myHash(x, i); 211 | 212 | if(!isActive(pos)) 213 | { 214 | array_[pos] = std::move(HashEntry{std::move(x), true}); 215 | ++current_size_; 216 | return true; 217 | } 218 | } 219 | 220 | // None of the spots are available. Kick out random one 221 | int i = 0; 222 | do 223 | { 224 | pos = myHash(x, r_.nextInt(n_hash_functions_)); 225 | }while(pos == last_pos && i++ < 5); 226 | 227 | last_pos = pos; 228 | std::swap(x, array_[pos].element_); 229 | } 230 | 231 | if(++rehashes_ > ALLOWED_REHASHES) 232 | { 233 | expand(); // Make the table bigger 234 | rehashes_ = 0; 235 | } 236 | else 237 | rehash(); 238 | } 239 | } 240 | 241 | bool insertHelper1(Object&& x) 242 | { 243 | const int COUNT_LIMIT = 100; 244 | 245 | while(true) 246 | { 247 | int last_pos = -1; 248 | int pos; 249 | 250 | for(int count = 0; count < COUNT_LIMIT; ++count) 251 | { 252 | for(int i = 0; i < n_hash_functions_; ++i) 253 | { 254 | pos = myHash(x, i); 255 | 256 | if(!isActive(pos)) 257 | { 258 | array_[pos] = std::move(HashEntry{std::move(x), true}); 259 | ++current_size_; 260 | return true; 261 | } 262 | } 263 | 264 | // None of the spots are available. Kick out random one 265 | int i = 0; 266 | do 267 | { 268 | pos = myHash(x, r_.nextInt(n_hash_functions_)); 269 | }while(pos == last_pos && i++ < 5); 270 | 271 | last_pos = pos; 272 | std::swap(x, array_[ pos ].element_); 273 | } 274 | 275 | if(++rehashes_ > ALLOWED_REHASHES) 276 | { 277 | expand(); // Make the table bigger 278 | rehashes_ = 0; 279 | } 280 | else 281 | rehash(); 282 | } 283 | } 284 | 285 | bool isActive(int pos) const 286 | { return pos != -1 && array_[pos].is_active_; } 287 | 288 | // 寻找pos 289 | int findPos(const Object& x) const 290 | { 291 | for(int i = 0; i < n_hash_functions_; ++i) 292 | { 293 | int pos = myHash(x, i); // 使用第i个hash function 294 | if(isActive(pos) && array_[pos].element_ == x) 295 | return pos; 296 | } 297 | return -1; 298 | } 299 | 300 | // which 用于指定使用HashFamily里的哪一个hash function 301 | int myHash(const Object& x, int which) const 302 | { 303 | return hash_functions_.hash(x, which) % array_.size(); 304 | } 305 | 306 | void expand() 307 | { rehash(static_cast(array_.size() / MAX_LOAD)); } 308 | 309 | void rehash() 310 | { 311 | hash_functions_.generateNewFunctions(); 312 | rehash(array_.size()); 313 | } 314 | 315 | // 再hash扩张 316 | void rehash(int size) 317 | { 318 | std::vector old_table = array_; 319 | 320 | // 创建新的hash表,大致为原表大小两倍 321 | array_.resize(nextPrime(size)); 322 | for(auto& entry : array_) 323 | entry.is_active_ = false; 324 | 325 | current_size_ = 0; 326 | for(auto& entry : old_table) 327 | { 328 | if(entry.is_active_) 329 | insert(std::move(entry.element_)); 330 | } 331 | } 332 | }; 333 | } 334 | #endif //CUCKOO_HASH_HPP 335 | -------------------------------------------------------------------------------- /part5/cuckoo_hash_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "cuckoo_hash.hpp" 4 | using namespace std; 5 | using namespace DS; 6 | 7 | // Simple main 8 | int main() 9 | { 10 | const int NUMS = 200000; 11 | const int GAP = 37; 12 | const int ATTEMPTS = 1; 13 | int i; 14 | 15 | cout << "Checking... (no more output means success)" << endl; 16 | 17 | for(int att = 0; att < ATTEMPTS; ++att) 18 | { 19 | cout << "ATTEMPT: " << att << endl; 20 | 21 | HashTable> h1; 22 | HashTable> h2; 23 | 24 | for(i = GAP; i != 0; i = (i + GAP) % NUMS) 25 | { 26 | if(!h1.insert(to_string(i))) 27 | { 28 | cout << "OOPS insert fails?! " << i << endl; 29 | } 30 | } 31 | 32 | for(i = GAP; i != 0; i = (i + GAP) % NUMS) 33 | if(h1.insert(to_string(i))) 34 | cout << "INSERT OOPS!!! " << i << endl; 35 | 36 | h2 = h1; 37 | 38 | for(i = 1; i < NUMS; i += 2) 39 | h2.remove(to_string(i)); 40 | 41 | for(i = 2; i < NUMS; i += 2) 42 | if(!h2.contains(to_string(i))) 43 | cout << "Contains fails " << i << endl; 44 | 45 | for(i = 1; i < NUMS; i += 2) 46 | { 47 | if(h2.contains(to_string(i))) 48 | cout << "CONTAINS OOPS!!! " << i << endl; 49 | } 50 | 51 | cout << "END OF ATTEMPT" << endl; 52 | 53 | if(h2.capacity() > NUMS * 4) 54 | cout << "LARGE CAPACITY " << h2.capacity() << endl; 55 | } 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /part5/quadratic_probing.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 二次再探型 hash table 3 | * key出现冲突时采用二次再探法寻找下一个key 4 | * 出现冲突按照链表形式在key后增加元素 5 | */ 6 | 7 | #ifndef QUADRATIC_PROBING_HPP 8 | #define QUADRATIC_PROBING_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace DS 17 | { 18 | // 判断素数 19 | bool isPrime(int n) { 20 | if (n < 2 || (n & 1) == 0) 21 | return false; 22 | if (n == 2 || n == 3) 23 | return true; 24 | for (int i = 3; i * i <= n; i += 2) { 25 | if (n % i == 0) 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | int nextPrime(int n) 32 | { 33 | if(n < 1) 34 | return 2; 35 | if((n & 1) == 0) 36 | ++n; 37 | for(; !isPrime(n); n += 2) 38 | ; 39 | return n; 40 | } 41 | 42 | // QuadraticProbing Hash table class 43 | // CONSTRUCTION: an approximate initial size or default of 101 44 | // 45 | // ******************PUBLIC OPERATIONS********************* 46 | // bool insert( x ) --> Insert x 47 | // bool remove( x ) --> Remove x 48 | // bool contains( x ) --> Return true if x is present 49 | // void makeEmpty( ) --> Remove all items 50 | // int hashCode( string str ) --> Global method to hash strings 51 | template 52 | class HashTable 53 | { 54 | public: 55 | explicit HashTable(int size = 101) 56 | : array_(nextPrime(size)) 57 | { makeEmpty(); } 58 | 59 | bool contains(const Object& x) const 60 | { 61 | return isActive(findPos(x)); 62 | } 63 | 64 | void makeEmpty() 65 | { 66 | current_size_ = 0; 67 | for(auto& entry : array_) // 惰性删除 68 | entry.info_ = EMPTY; 69 | } 70 | 71 | bool insert(const Object& x) 72 | { 73 | int pos = findPos(x); 74 | if(isActive(pos)) 75 | return false; 76 | if(array_[pos].info_ != DELETED) 77 | ++current_size_; 78 | array_[pos].element_ = x; 79 | array_[pos].info_ = ACTIVE; 80 | 81 | if(current_size_ > array_.size() / 2) 82 | rehash(); 83 | return true; 84 | } 85 | 86 | bool insert(Object&& x) 87 | { 88 | int pos = findPos(x); 89 | if(isActive(pos)) 90 | return false; 91 | if(array_[pos].info_ != DELETED) 92 | ++current_size_; 93 | array_[pos].element_ = std::move(x); 94 | array_[pos].info_ = ACTIVE; 95 | 96 | if(current_size_ > array_.size() / 2) 97 | rehash(); 98 | return true; 99 | } 100 | 101 | bool remove(const Object& x) 102 | { 103 | int pos = findPos(x); 104 | if(!isActive(pos)) 105 | return false; 106 | array_[pos].info_ = DELETED; 107 | --current_size_; 108 | return true; 109 | } 110 | 111 | enum EntryType{ACTIVE, EMPTY, DELETED}; 112 | 113 | private: 114 | struct HashEntry 115 | { 116 | Object element_; 117 | EntryType info_; // 惰性删除使用,标记元素是否被删除 118 | 119 | explicit HashEntry(const Object& e = Object{}, EntryType i = EMPTY) 120 | : element_{e}, info_{i} 121 | {} 122 | 123 | explicit HashEntry(Object&& e, EntryType i = EMPTY) 124 | : element_{std::move(e)}, info_{i} 125 | {} 126 | }; 127 | 128 | std::vector array_; 129 | std::size_t current_size_; 130 | 131 | bool isActive(int pos) const 132 | { return array_[pos].info_ == ACTIVE; } 133 | 134 | // 关键:二次再探法中的pos探查 135 | std::size_t findPos(const Object& x) const 136 | { 137 | std::size_t offset = 1; 138 | std::size_t pos = myHash(x); 139 | // 出现EMPTY元素后作为搜索终点 140 | while(array_[pos].info_ != EMPTY && array_[pos].element_ != x) 141 | { 142 | // 二次数列 143 | // offset 1 3 5 7 9... 144 | // pos+ 1 4 9 16 25... 145 | pos += offset; 146 | offset += 2; 147 | if(pos >= array_.size()) 148 | pos -= array_.size(); 149 | } 150 | return pos; 151 | } 152 | 153 | std::size_t myHash(const Object& x) const 154 | { 155 | // 定义hash函数 156 | static std::hash hash_function; 157 | return hash_function(x) % array_.size(); 158 | } 159 | 160 | // 再hash扩张 161 | void rehash() 162 | { 163 | std::vector old_table = array_; 164 | 165 | // 创建新的hash表,大致为原表大小两倍 166 | array_.resize(nextPrime(2 * old_table.size())); 167 | for(auto& entry : array_) 168 | entry.info_ = EMPTY; 169 | 170 | // 复制原表处于激活状态的元素 171 | current_size_ = 0; 172 | for(auto& entry : old_table) 173 | { 174 | if(entry.info_ == ACTIVE) 175 | insert(std::move(entry.element_)); 176 | } 177 | } 178 | }; 179 | } 180 | #endif //QUADRATIC_PROBING_HPP 181 | -------------------------------------------------------------------------------- /part5/quadratic_probing_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "quadratic_probing.hpp" 3 | using namespace std; 4 | using DS::HashTable; 5 | 6 | // Simple main 7 | int main( ) 8 | { 9 | HashTable h1; 10 | HashTable h2; 11 | 12 | const int NUMS = 10000; 13 | const int GAP = 37; 14 | int i; 15 | 16 | cout << "Checking... (no more output means success)" << endl; 17 | 18 | for( i = GAP; i != 0; i = ( i + GAP ) % NUMS ) 19 | h1.insert( i ); 20 | 21 | h2 = h1; 22 | 23 | for( i = 1; i < NUMS; i += 2 ) 24 | h2.remove( i ); 25 | 26 | for( i = 2; i < NUMS; i += 2 ) 27 | if( !h2.contains( i ) ) 28 | cout << "Contains fails " << i << endl; 29 | 30 | for( i = 1; i < NUMS; i += 2 ) 31 | { 32 | if( h2.contains( i ) ) 33 | cout << "OOPS!!! " << i << endl; 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /part5/separate_chaining.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 分离链接型hash table 3 | * 采用链表再key处扩增元素 4 | * 出现冲突按照链表形式在key后增加元素 5 | */ 6 | 7 | #ifndef SEPARATE_CHAINING_HPP 8 | #define SEPARATE_CHAINING_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace DS 17 | { 18 | // 判断素数 19 | bool isPrime(int n) { 20 | if (n < 2 || (n & 1) == 0) 21 | return false; 22 | if (n == 2 || n == 3) 23 | return true; 24 | for (int i = 3; i * i <= n; i += 2) { 25 | if (n % i == 0) 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | int nextPrime(int n) 32 | { 33 | if(n < 1) 34 | return 2; 35 | if((n & 1) == 0) 36 | ++n; 37 | for(; !isPrime(n); n += 2) 38 | ; 39 | return n; 40 | } 41 | 42 | // A hash function for string objects 43 | size_t hash(const std::string& key) 44 | { 45 | size_t hash_val = 0; 46 | for(char ch : key) 47 | hash_val = 37 * hash_val + int(ch); 48 | return hash_val; 49 | } 50 | 51 | // A hash function for ints 52 | size_t hash(int key) 53 | { 54 | return key; 55 | } 56 | 57 | // SeparateChaining Hash table class 58 | // 59 | // CONSTRUCTION: an approximate initial size or default of 101 60 | // 61 | // ******************PUBLIC OPERATIONS********************* 62 | // bool insert( x ) --> Insert x 63 | // bool remove( x ) --> Remove x 64 | // bool contains( x ) --> Return true if x is present 65 | // void makeEmpty( ) --> Remove all items 66 | template 67 | class HashTable 68 | { 69 | public: 70 | explicit HashTable(int size = 101) 71 | : current_size_{0} 72 | { hash_table_.resize(size); } 73 | 74 | bool contains(const Object& x) const 75 | { 76 | // 调用hash函数返回第一级关键字对应的list 77 | const std::list& which_list = hash_table_[myHash(x)]; 78 | // 在链表中寻找 79 | return which_list.end() != myFind(which_list.begin(), which_list.end(), x); 80 | } 81 | 82 | void makeEmpty() 83 | { 84 | for(std::list& the_list : hash_table_) 85 | { 86 | the_list.clear(); 87 | } 88 | } 89 | 90 | bool insert(const Object& x) 91 | { 92 | std::list& which_list = hash_table_[myHash(x)]; 93 | if(myFind(which_list.begin(), which_list.end(), x) != which_list.end()) 94 | return false; 95 | which_list.push_back(x); 96 | 97 | if(++current_size_ > hash_table_.size()) 98 | rehash(); 99 | return true; 100 | } 101 | 102 | bool insert(Object&& x) 103 | { 104 | std::list& which_list = hash_table_[myHash(x)]; 105 | if(myFind(which_list.begin(), which_list.end(), x) != which_list.end()) 106 | return false; 107 | which_list.push_back(std::move(x)); 108 | 109 | if(++current_size_ > hash_table_.size()) 110 | rehash(); 111 | return true; 112 | } 113 | 114 | bool remove(const Object& x) 115 | { 116 | std::list& which_list = hash_table_[myHash(x)]; 117 | typename std::list::iterator iter = myFind(which_list.begin(), which_list.end(), x); 118 | if(iter == which_list.end()) 119 | return false; 120 | which_list.erase(iter); 121 | --current_size_; 122 | return true; 123 | } 124 | 125 | private: 126 | std::vector> hash_table_; 127 | int current_size_ ; 128 | 129 | size_t myHash(const Object& x) const 130 | { 131 | // 定义hash函数 132 | static std::hash hash_function; 133 | return hash_function(x) % hash_table_.size(); 134 | } 135 | 136 | typename std::list::iterator myFind( 137 | typename std::list::iterator begin, 138 | typename std::list::iterator end, 139 | const Object& x) const 140 | { 141 | typename std::list::iterator iter = begin; 142 | while(iter != end) 143 | { 144 | if(*iter == x) 145 | return iter; 146 | ++iter; 147 | } 148 | return end; 149 | } 150 | 151 | typename std::list::const_iterator myFind( 152 | typename std::list::const_iterator begin, 153 | typename std::list::const_iterator end, 154 | const Object& x) const 155 | { 156 | typename std::list::const_iterator iter = begin; 157 | while(iter != end) 158 | { 159 | if(*iter == x) 160 | return iter; 161 | ++iter; 162 | } 163 | return end; 164 | } 165 | 166 | // 再hash扩张 167 | void rehash() 168 | { 169 | std::vector> old_table = hash_table_; 170 | 171 | // 创建新的hash表,大致为原表大小两倍 172 | hash_table_.resize(nextPrime(2 * hash_table_.size())); 173 | for(auto& the_list : hash_table_) 174 | the_list.clear(); 175 | 176 | // 复制原表 177 | current_size_ = 0; 178 | for(std::list& the_list : old_table) 179 | { 180 | for(Object& x : the_list) 181 | insert(std::move(x)); 182 | } 183 | } 184 | }; 185 | } 186 | #endif //SEPARATE_CHAINING_HPP 187 | -------------------------------------------------------------------------------- /part5/separate_chaining_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "separate_chaining.hpp" 3 | using namespace std; 4 | using DS::HashTable; 5 | 6 | // Simple main 7 | int main( ) 8 | { 9 | HashTable h1; 10 | HashTable h2; 11 | 12 | const int NUMS = 400000; 13 | const int GAP = 37; 14 | int i; 15 | 16 | cout << "Checking... (no more output means success)" << endl; 17 | 18 | for( i = GAP; i != 0; i = ( i + GAP ) % NUMS ) 19 | h1.insert( i ); 20 | 21 | h2 = h1; 22 | 23 | for( i = 1; i < NUMS; i += 2 ) 24 | h2.remove( i ); 25 | 26 | for( i = 2; i < NUMS; i += 2 ) 27 | if( !h2.contains( i ) ) 28 | cout << "Contains fails " << i << endl; 29 | 30 | for( i = 1; i < NUMS; i += 2 ) 31 | { 32 | if( h2.contains( i ) ) 33 | cout << "OOPS!!! " << i << endl; 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /part5/use_of_unordered_set.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | // unordered_set 使用,提供定制的equal(==)和hash函数 9 | // 实现一个大小写不敏感的字符串的无序集合 10 | 11 | string toLower(const string& s) 12 | { 13 | string copy = s; // 避免对s的修改 14 | transform(copy.begin(), copy.end(), copy.begin(), 15 | [](unsigned char c) -> unsigned char {return tolower(c);}); 16 | return copy; 17 | } 18 | 19 | bool equalsIgnoreCase(const string& lhs, const string& rhs) 20 | { 21 | return toLower(lhs) == toLower(rhs); 22 | } 23 | class CaseInsensitive 24 | { 25 | public: 26 | size_t operator() (const string& s) const // 重载的hash函数 27 | { 28 | static hash hf; 29 | return hf(toLower(s)); 30 | } 31 | 32 | bool operator() (const string& lhs, const string& rhs) const // 重载的比较函数 33 | { 34 | return equalsIgnoreCase(lhs, rhs); 35 | } 36 | }; 37 | 38 | int main() 39 | { 40 | unordered_set s; 41 | 42 | s.insert("HELLO"); 43 | s.insert("helLo"); 44 | s.insert("WORLD"); 45 | s.insert("world"); 46 | s.insert("hello"); 47 | 48 | auto itr = s.begin(); 49 | 50 | while(itr != s.end()) 51 | cout << *itr++ << endl; 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /part6/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART6) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | elseif(${CMAKE_BUILD_TYPE} MATCHES Release) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Using [Release] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # heap 堆 / priority queue 优先队列 15 | 16 | # binary_heap 最基本的二叉堆 17 | set(DEMO binary_heap) 18 | set(LIB ../lib) 19 | set(SOURCE 20 | ${DEMO}_test.cpp 21 | ${DEMO}.hpp 22 | ${LIB}) 23 | add_executable(${DEMO} ${SOURCE}) 24 | 25 | # leftist_heap 左式堆 26 | set(DEMO left_heap) 27 | set(LIB ../lib) 28 | set(SOURCE 29 | ${DEMO}_test.cpp 30 | ${DEMO}.hpp 31 | ${LIB}) 32 | add_executable(${DEMO} ${SOURCE}) 33 | 34 | # binomial_queue 二项队列 35 | set(DEMO binomial_queue) 36 | set(LIB ../lib) 37 | set(SOURCE 38 | ${DEMO}_test.cpp 39 | ${DEMO}.hpp 40 | ${LIB}) 41 | add_executable(${DEMO} ${SOURCE}) 42 | 43 | # priority_queue 使用 44 | set(DEMO priority_queue) 45 | set(SOURCE ${DEMO}_test.cpp) 46 | add_executable(${DEMO} ${SOURCE}) 47 | -------------------------------------------------------------------------------- /part6/binary_heap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BINARY_HEAP_HPP 2 | #define BINARY_HEAP_HPP 3 | 4 | #include "../lib/dsexceptions.h" 5 | #include 6 | 7 | // 基本二叉堆 8 | // BinaryHeap class 9 | // CONSTRUCTION: with an optional capacity (that defaults to 100) 10 | // 11 | // ******************PUBLIC OPERATIONS********************* 12 | // void insert( x ) --> Insert x, allowing duplicates 13 | // pop( minItem ) --> Remove (and optionally return) top item 14 | // Comparable top( ) --> Return the top item 15 | // bool empty( ) --> Return true if empty; else false 16 | // void clear( ) --> Remove all items 17 | // ******************ERRORS******************************** 18 | // Throws UnderflowException as warranted 19 | 20 | namespace DS 21 | { 22 | // 默认的比较函数 23 | template 24 | class IsLess 25 | { 26 | public: 27 | bool operator() (const Object& lhs, const Object& rhs) const 28 | { 29 | return lhs < rhs; 30 | } 31 | }; 32 | 33 | template > 34 | class BinaryHeap 35 | { 36 | public: 37 | // array额外流程一个空间(array[0])作为插入删除中介 38 | explicit BinaryHeap(const Compare& cmp = Compare(), std::size_t capacity = 100) 39 | : array_(capacity + 1), current_size_{0}, compare_{cmp} 40 | {} 41 | 42 | explicit BinaryHeap(const std::vector& items, const Compare& cmp = Compare()) 43 | : array_(items.size() + 10), current_size_{items.size()}, compare_{cmp} 44 | { 45 | for(int i = 0; i < items.size(); ++i) 46 | array_[i + 1] = items[i]; 47 | buildHeap(); 48 | } 49 | 50 | bool empty() const 51 | { return current_size_ == 0; } 52 | 53 | std::size_t size() const 54 | { return current_size_; } 55 | 56 | // 找堆顶元素,如果空堆则抛出异常 57 | const Object& top() const 58 | { 59 | if(empty()) 60 | throw UnderflowException{}; 61 | return array_[1]; 62 | } 63 | 64 | // 删除堆顶元素 65 | void pop() 66 | { 67 | if(empty()) 68 | throw UnderflowException{}; 69 | 70 | array_[1] = std::move(array_[current_size_--]); 71 | // 下滤过程 72 | percolateDown(1); 73 | } 74 | 75 | // 删除堆顶元素,并将其放在min_item中 76 | void pop(Object& min_item) 77 | { 78 | if(empty()) 79 | throw UnderflowException{}; 80 | 81 | min_item = std::move(array_[1]); 82 | array_[1] = std::move(array_[current_size_--]); 83 | // 下滤过程 84 | percolateDown(1); 85 | } 86 | 87 | void insert(const Object& x) 88 | { 89 | if(current_size_ == array_.size() - 1) 90 | array_.resize(array_.size() * 2); 91 | 92 | Object copy(x); 93 | array_[0] = std::move(copy); 94 | 95 | // 上滤过程 96 | // current_size += 1 97 | // 将新的元素放在最后一位 98 | percolateUp(++current_size_); 99 | } 100 | 101 | void insert(Object&& x) 102 | { 103 | if(current_size_ == array_.size() - 1) 104 | array_.resize(array_.size() * 2); 105 | 106 | array_[0] = std::move(x); 107 | 108 | // 上滤过程 109 | // current_size += 1 110 | // 将新的元素放在最后一位 111 | percolateUp(++current_size_); 112 | } 113 | 114 | // 惰性擦除 115 | void clear() 116 | { current_size_ = 0; } 117 | 118 | private: 119 | std::vector array_; 120 | std::size_t current_size_; 121 | Compare compare_; 122 | 123 | void percolateUp(std::size_t pos) 124 | { 125 | for(; compare_(array_[0], array_[pos / 2]); pos /= 2) 126 | array_[pos] = std::move(array_[pos / 2]); 127 | array_[pos] = std::move(array_[0]); 128 | } 129 | 130 | void percolateDown(std::size_t pos) 131 | { 132 | std::size_t next_pos = 0; 133 | Object tmp = std::move(array_[pos]); 134 | for(; pos * 2 <= current_size_; pos = next_pos) 135 | { 136 | next_pos = pos * 2; 137 | if(next_pos < current_size_ && compare_(array_[next_pos + 1], array_[next_pos])) 138 | ++next_pos; 139 | if(compare_(tmp, array_[next_pos])) 140 | break; 141 | else 142 | array_[pos] = std::move(array_[next_pos]); 143 | } 144 | array_[pos] = std::move(tmp); 145 | } 146 | 147 | void buildHeap() 148 | { 149 | for(int i = current_size_ / 2; i > 0; --i) 150 | percolateDown(i); 151 | } 152 | }; 153 | } 154 | #endif 155 | -------------------------------------------------------------------------------- /part6/binary_heap_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "binary_heap.hpp" 5 | using namespace std; 6 | using DS::BinaryHeap; 7 | 8 | // Test program 9 | int main() 10 | { 11 | int minItem = 10000; // same number of digits 12 | int maxItem = 99999; 13 | // auto fun = [](const string& a, const string& b) -> bool{ 14 | // return a > b; 15 | // }; // 用于大根堆 16 | // BinaryHeap h(fun); 17 | BinaryHeap h; 18 | string str = "hello"; 19 | int i = 37; 20 | string x; 21 | 22 | cout << "Begin test... " << endl; 23 | 24 | for(i = 37; i != 0; i = (i + 37) % maxItem) 25 | { 26 | // should use to_string in C++11 27 | ostringstream sout; 28 | sout << "hello" << i; 29 | if(i >= minItem) 30 | { 31 | string s = sout.str(); 32 | h.insert(s); 33 | } 34 | } 35 | 36 | for(i = minItem; i < maxItem; ++i) 37 | { 38 | ostringstream sout; 39 | sout << "hello" << i; 40 | 41 | h.pop(x); 42 | 43 | if(x != sout.str()) 44 | cout << "Oops! " << i << endl; 45 | } 46 | 47 | cout << "End test... no other output is good" << endl; 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /part6/binomial_queue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BINOMIAL_QUEUE_HPP 2 | #define BINOMIAL_QUEUE_HPP 3 | 4 | #include 5 | #include 6 | #include "../lib/dsexceptions.h" 7 | 8 | // Binomial queue class 9 | // 二项队列 10 | // CONSTRUCTION: with no parameters 11 | // 12 | // ******************PUBLIC OPERATIONS********************* 13 | // void insert( x ) --> Insert x 14 | // pop( ) --> Return and remove smallest item 15 | // Comparable top( ) --> Return smallest item 16 | // bool empty( ) --> Return true if empty; else false 17 | // void clear( ) --> Remove all items 18 | // void merge( rhs ) --> Absorb rhs into this heap 19 | // ******************ERRORS******************************** 20 | // Throws UnderflowException as warranted 21 | 22 | namespace DS 23 | { 24 | // 默认的比较函数 25 | template 26 | class IsLessBQ 27 | { 28 | public: 29 | bool operator() (const Object& lhs, const Object& rhs) const 30 | { 31 | return lhs < rhs; 32 | } 33 | }; 34 | 35 | template > 36 | class BinomialQueue 37 | { 38 | public: 39 | explicit BinomialQueue(const Compare& comp = Compare()) 40 | : trees_(DEFAULT_TREES), size_{0}, compare_{comp} 41 | { 42 | for(auto& root : trees_) 43 | root = nullptr; 44 | } 45 | 46 | explicit BinomialQueue(const Object& item, const Compare& comp = Compare()) 47 | : trees_(1), size_{1}, compare_{comp} 48 | { 49 | trees_[0] = new BinomialNode(item, nullptr, nullptr); 50 | } 51 | 52 | explicit BinomialQueue(Object&& item, const Compare& comp = Compare()) 53 | : trees_(1), size_{1}, compare_{comp} 54 | { 55 | trees_[0] = new BinomialNode(std::move(item), nullptr, nullptr); 56 | } 57 | 58 | BinomialQueue(const BinomialQueue& rhs) 59 | : trees_(rhs.trees_.size(), nullptr), size_{rhs.size_}, compare_{rhs.compare_} 60 | { 61 | for(int i = 0; i < rhs.trees_.size(); ++i) 62 | clone(trees_[i], rhs.trees_[i]); 63 | } 64 | 65 | BinomialQueue(BinomialQueue&& rhs) noexcept 66 | : trees_{std::move(rhs.trees_)}, size_{rhs.size_}, compare_{std::move(rhs.compare_)} 67 | {} 68 | 69 | ~BinomialQueue() noexcept 70 | { clear(); } 71 | 72 | BinomialQueue& operator=(const BinomialQueue& rhs) 73 | { 74 | BinomialQueue copy(rhs); 75 | std::swap(*this, copy); 76 | return *this; 77 | } 78 | 79 | BinomialQueue& operator=(BinomialQueue&& rhs) noexcept 80 | { 81 | std::swap(size_, rhs.size_); 82 | std::swap(trees_, rhs.trees_); 83 | std::swap(compare_, rhs.compare_); 84 | return *this; 85 | } 86 | 87 | bool empty() const 88 | { return size_ == 0; } 89 | 90 | int size() const 91 | { return size_; } 92 | 93 | void clear() 94 | { 95 | size_ = 0; 96 | for(auto& root : trees_) 97 | clear(root); 98 | } 99 | 100 | const Object& top() const 101 | { 102 | if(empty()) 103 | throw UnderflowException{}; 104 | return trees_[findTopIndex()]->element_; 105 | } 106 | 107 | // 允许重复 108 | // 插入即为特殊的合并 109 | void insert(const Object& x) 110 | { 111 | BinomialQueue new_tree(x, compare_); 112 | merge(new_tree); 113 | } 114 | 115 | void insert(Object&& x) 116 | { 117 | BinomialQueue new_tree(std::move(x), compare_); 118 | merge(new_tree); 119 | } 120 | 121 | void pop() 122 | { 123 | Object item; 124 | pop(item); 125 | } 126 | 127 | void pop(Object& item) 128 | { 129 | if(empty()) 130 | throw UnderflowException{}; 131 | int top_id = findTopIndex(); // 找到待删除的节点id 132 | item = trees_[top_id]->element_; 133 | BinomialNode* old = trees_[top_id]; 134 | BinomialNode* rest_tree = old->first_child_; 135 | 136 | delete old; // 删除根 137 | // 构造树H'' 138 | BinomialQueue rest_queue(compare_); 139 | rest_queue.trees_.resize(top_id); 140 | rest_queue.size_ = (1 << top_id) - 1; 141 | for(int j = top_id - 1; j >= 0; --j) 142 | { 143 | rest_queue.trees_[j] = rest_tree; 144 | rest_tree = rest_tree->next_sibling_; 145 | rest_queue.trees_[j]->next_sibling_ = nullptr; 146 | } 147 | // 将当前树this构造成H' 148 | trees_[top_id] = nullptr; 149 | size_ -= rest_queue.size_ + 1; 150 | 151 | // 合并h' h'' 152 | merge(rest_queue); 153 | } 154 | 155 | // 合并 156 | void merge(BinomialQueue& rhs) 157 | { 158 | if(this == &rhs) 159 | return; 160 | size_ += rhs.size_; 161 | 162 | if(size_ > capacity()) // 表扩张 163 | { 164 | int old_n_trees = trees_.size(); 165 | // 新的表长=合并项中表长大者+1 166 | int new_n_trees = std::max(trees_.size(), rhs.trees_.size()) + 1; 167 | trees_.resize(new_n_trees); 168 | for(int i = old_n_trees; i < new_n_trees; ++i) 169 | { 170 | trees_[i] = nullptr; // 新的表节点初始化nullptr 171 | } 172 | } 173 | 174 | BinomialNode* carry = nullptr; // 从循环上一步得到的树 175 | BinomialNode* t1 = nullptr; 176 | BinomialNode* t2 = nullptr; 177 | for(int i = 0, j = 1; j <= size_; ++i, j *= 2) 178 | { 179 | // 用i遍历每棵树 180 | t1 = trees_[i]; 181 | t2 = i < rhs.trees_.size() ? rhs.trees_[i] : nullptr; 182 | 183 | int which_case = t1 == nullptr ? 0 : 1; 184 | which_case += t2 == nullptr ? 0 : 2; 185 | which_case += carry == nullptr ? 0 : 4; 186 | 187 | if(which_case < 2) 188 | continue; 189 | 190 | switch(which_case) 191 | { 192 | // case 0, 1 do nothing 193 | // case 0: // no trees 194 | // case 1: // only this 195 | case 2: /* Only rhs */ 196 | trees_[i] = t2; 197 | rhs.trees_[i] = nullptr; 198 | break; 199 | case 4: /* Only carry */ 200 | trees_[i] = carry; 201 | carry = nullptr; 202 | break; 203 | case 3: /* this and rhs */ 204 | carry = combineTrees(t1, t2); 205 | trees_[i] = rhs.trees_[i] = nullptr; 206 | break; 207 | case 5: /* this and carry */ 208 | carry = combineTrees(t1, carry); 209 | trees_[i] = nullptr; 210 | break; 211 | case 6: /* rhs and carry */ 212 | carry = combineTrees(t2, carry); 213 | rhs.trees_[i] = nullptr; 214 | break; 215 | case 7: /* All three */ 216 | trees_[i] = carry; 217 | carry = combineTrees(t1, t2); 218 | rhs.trees_[i] = nullptr; 219 | break; 220 | default: 221 | break; 222 | } 223 | } 224 | // 消除rhs 225 | for(auto& root : rhs.trees_) 226 | root = nullptr; 227 | rhs.size_ = 0; 228 | } 229 | 230 | 231 | private: 232 | class BinomialNode 233 | { 234 | public: 235 | Object element_; 236 | BinomialNode* first_child_; 237 | BinomialNode* next_sibling_; // 二项队列中的树不是二叉树,所有用孩子兄弟法表示 238 | 239 | explicit BinomialNode(const Object& e, BinomialNode* lt = nullptr, BinomialNode* rt = nullptr) 240 | : element_{e}, first_child_{lt}, next_sibling_{rt} 241 | {} 242 | 243 | explicit BinomialNode(Object&& e, BinomialNode* lt = nullptr, BinomialNode* rt = nullptr) 244 | : element_{std::move(e)}, first_child_{lt}, next_sibling_{rt} 245 | {} 246 | }; 247 | 248 | const static int DEFAULT_TREES = 1; 249 | 250 | std::vector trees_; // 二项树列表 251 | int size_; // 记录队列中项数 252 | Compare compare_; // 比较函数 253 | 254 | int findTopIndex() const 255 | { 256 | int i; 257 | int top_id; 258 | for(i = 0; trees_[i] == nullptr; ++i) // 找到树表中第一个不为null的根 259 | ; 260 | for(top_id = i; i < trees_.size(); ++i) 261 | { 262 | if(trees_[i] != nullptr && compare_(trees_[i]->element_, trees_[top_id]->element_)) 263 | top_id = i; 264 | } 265 | return top_id; 266 | } 267 | 268 | // 返回二项队列的容量 2^k - 1, k = 队列长度 269 | int capacity() const 270 | { return (1 << trees_.size()) - 1;} 271 | 272 | void clear(BinomialNode*& node) 273 | { 274 | if(nullptr == node) 275 | return; 276 | BinomialNode* lt = node->first_child_; 277 | BinomialNode* rt = node->next_sibling_; 278 | delete node; 279 | node = nullptr; 280 | clear(rt); 281 | clear(lt); 282 | } 283 | 284 | void clone(BinomialNode*& node, BinomialNode* rhs) 285 | { 286 | if(nullptr == rhs) 287 | return; 288 | node = new BinomialNode(rhs->element_, nullptr, nullptr); 289 | clone(node->next_sibling_, rhs->next_sibling_); 290 | clone(node->first_child_, rhs->first_child_); 291 | } 292 | 293 | // Return the result of merging equal-sized t1 and t2. 294 | // 合并两棵同样大小的树 295 | BinomialNode* combineTrees(BinomialNode* t1, BinomialNode* t2) 296 | { 297 | if(compare_(t2->element_, t1->element_)) 298 | return combineTrees(t2, t1); 299 | t2->next_sibling_ = t1->first_child_; 300 | t1->first_child_ = t2; 301 | return t1; 302 | } 303 | }; 304 | } 305 | #endif //BINOMIAL_QUEUE_HPP 306 | -------------------------------------------------------------------------------- /part6/binomial_queue_test.cpp: -------------------------------------------------------------------------------- 1 | #include "binomial_queue.hpp" 2 | #include 3 | using namespace std; 4 | using DS::BinomialQueue; 5 | 6 | int main() 7 | { 8 | int numItems = 100000; 9 | BinomialQueue h; 10 | BinomialQueue h1; 11 | BinomialQueue h2; 12 | int i = 37; 13 | 14 | cout << "Begin test..." << endl; 15 | for(i = 37; i != 0; i = (i + 37) % numItems) 16 | { 17 | if (i % 2 == 0) 18 | { 19 | h1.insert(i); 20 | } else 21 | { 22 | h.insert(i); 23 | } 24 | } 25 | 26 | h.merge(h1); 27 | 28 | h2 = h; 29 | 30 | for(i = 1; i < numItems; ++i) 31 | { 32 | int x; 33 | h2.pop(x); 34 | if(x != i) 35 | cout << "Oops! " << i << endl; 36 | } 37 | 38 | if(!h1.empty()) 39 | cout << "Oops! h1 should have been empty!" << endl; 40 | 41 | cout << "End of test... no output is good" << endl; 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /part6/left_heap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LEFT_HEAP_HPP 2 | #define LEFT_HEAP_HPP 3 | 4 | #include 5 | #include "../lib/dsexceptions.h" 6 | 7 | // Leftist heap class 8 | // 支持快速合并 9 | // CONSTRUCTION: with no parameters 10 | // 11 | // ******************PUBLIC OPERATIONS********************* 12 | // void insert( x ) --> Insert x 13 | // pop( minItem ) --> Remove (and optionally return) top item 14 | // Comparable top( ) --> Return top item 15 | // bool empty( ) --> Return true if empty; else false 16 | // void clear( ) --> Remove all items 17 | // void merge( rhs ) --> Absorb rhs into this heap 18 | // ******************ERRORS******************************** 19 | // Throws UnderflowException as warranted 20 | 21 | namespace DS 22 | { 23 | // 默认的比较函数 24 | template 25 | class IsLessLeft 26 | { 27 | public: 28 | bool operator() (const Object& lhs, const Object& rhs) const 29 | { 30 | return lhs < rhs; 31 | } 32 | }; 33 | 34 | template > 35 | class LeftistHeap 36 | { 37 | public: 38 | explicit LeftistHeap(const Compare& cmp = Compare()) 39 | : root_{nullptr}, compare_{cmp} 40 | {} 41 | 42 | LeftistHeap(const LeftistHeap& rhs) 43 | : root_{nullptr}, compare_{rhs.compare_} 44 | { clone(root_, rhs.root_); } 45 | 46 | LeftistHeap(LeftistHeap&& rhs) noexcept 47 | : root_{rhs.root_}, compare_{rhs.compare_} 48 | { 49 | rhs.root_ = nullptr; // 置空, rhs析构时不会删除已经隶属于this的子节点 50 | } 51 | 52 | ~LeftistHeap() 53 | { clear(); } 54 | 55 | LeftistHeap& operator=(const LeftistHeap& rhs) 56 | { 57 | LeftistHeap copy(rhs); 58 | std::swap(*this, copy); 59 | return *this; 60 | } 61 | 62 | LeftistHeap& operator=(LeftistHeap&& rhs) noexcept 63 | { 64 | std::swap(root_, rhs.root_); 65 | std::swap(compare_, rhs.compare_); 66 | return *this; 67 | } 68 | 69 | bool empty() const 70 | { return root_ == nullptr; } 71 | 72 | // 获取堆顶 73 | const Object& top() const 74 | { 75 | if(empty()) 76 | throw UnderflowException{}; 77 | return root_->element_; 78 | } 79 | 80 | void pop() 81 | { 82 | if(empty()) 83 | throw UnderflowException{}; 84 | LeftistNode* old = root_; 85 | root_ = merge(root_->left_, root_->right_); 86 | delete old; 87 | } 88 | 89 | void pop(Object& item) 90 | { 91 | item = top(); 92 | pop(); 93 | } 94 | 95 | void clear() 96 | { 97 | clear(root_); 98 | root_ = nullptr; // 要置空 99 | } 100 | 101 | // 插入过程相当于把待插入的堆合并到插入节点上 102 | // Inserts x; duplicates allowed 103 | void insert(const Object& x) 104 | { root_ = merge(new LeftistNode(x), root_); } 105 | 106 | // Inserts x; duplicates allowed. 107 | void insert(Object&& x) 108 | { root_ = merge(new LeftistNode(std::move(x)), root_); } 109 | 110 | // 将新的堆合并到当前堆 111 | void merge(LeftistHeap& rhs) 112 | { 113 | if(this == &rhs) // 检查是不是本身 114 | return; 115 | root_ = merge(root_, rhs.root_); 116 | rhs.root_ = nullptr; // 置空, rhs析构时不会删除已经隶属于this的子节点 117 | } 118 | 119 | private: 120 | class LeftistNode 121 | { 122 | public: 123 | Object element_; 124 | LeftistNode* left_; 125 | LeftistNode* right_; 126 | int npl_; // 记录零路径长 127 | 128 | explicit LeftistNode(const Object& e, LeftistNode* lt = nullptr, 129 | LeftistNode* rt = nullptr, int np = 0) 130 | : element_{e}, left_{lt}, right_{rt}, npl_{np} 131 | {} 132 | 133 | explicit LeftistNode(Object&& e, LeftistNode* lt = nullptr, 134 | LeftistNode* rt = nullptr, int np = 0) 135 | : element_{std::move(e)}, left_{lt}, right_{rt}, npl_{np} 136 | {} 137 | }; 138 | 139 | LeftistNode* root_; // 根节点 140 | Compare compare_; 141 | 142 | // 函数本身没有修改root_, 所以仍旧使用const修饰this 143 | // 采用尾递归消除以尽可能避免堆栈溢出可能 144 | void clone(LeftistNode*& node, LeftistNode* copy) 145 | { 146 | if(nullptr == copy) 147 | return; 148 | node = new LeftistNode(copy->element_, nullptr, nullptr, copy->npl_); 149 | // 优先拷贝高度小的右端 150 | clone(node->right_, copy->right_); 151 | // 拷贝高度大的左端,尾递归 152 | clone(node->left_, copy->left_); 153 | } 154 | 155 | // 采用尾递归消除以尽可能避免堆栈溢出可能 156 | void clear(LeftistNode* node) 157 | { 158 | if(nullptr == node) 159 | return; 160 | LeftistNode* rt = node->right_; 161 | LeftistNode* lt = node->left_; 162 | // 删除 163 | delete node; 164 | // 优先释放高度小的右端 165 | clear(rt); 166 | // 消除高度大的左端,尾递归 167 | clear(lt); 168 | } 169 | 170 | // 合并过程 171 | LeftistNode* merge(LeftistNode* h1, LeftistNode* h2) 172 | { 173 | if(h1 == nullptr) 174 | return h2; 175 | if(h2 == nullptr) 176 | return h1; 177 | if(compare_(h1->element_, h2->element_)) 178 | return doMerge(h1, h2); 179 | else 180 | return doMerge(h2, h1); 181 | } 182 | 183 | // 合并h2到h1 184 | LeftistNode* doMerge(LeftistNode* h1, LeftistNode* h2) 185 | { 186 | if(h1->left_ == nullptr) 187 | h1->left_ = h2; 188 | else 189 | { 190 | // 递归的先将h2与h1的右子树合并 191 | h1->right_ = merge(h1->right_, h2); 192 | if(h1->left_->npl_ < h1->right_->npl_) 193 | std::swap(h1->left_, h1->right_); 194 | // 零路径长是当前节点到一个不具有两个儿子的最短路径长 195 | h1->npl_ = h1->right_->npl_ + 1; // 更新零路径长 196 | } 197 | return h1; 198 | } 199 | }; 200 | } 201 | #endif //LEFT_HEAP_HPP 202 | -------------------------------------------------------------------------------- /part6/left_heap_test.cpp: -------------------------------------------------------------------------------- 1 | #include "left_heap.hpp" 2 | #include 3 | using namespace std; 4 | using DS::LeftistHeap; 5 | 6 | int main() 7 | { 8 | int numItems = 10000; 9 | LeftistHeap h; 10 | LeftistHeap h1; 11 | LeftistHeap h2; 12 | int i = 37; 13 | 14 | cout << "Begin test..." << endl; 15 | for(i = 37; i != 0; i = (i + 37) % numItems) 16 | if(i % 2 == 0) 17 | h1.insert(i); 18 | else 19 | h.insert(i); 20 | h.merge(h1); 21 | h2 = h; 22 | 23 | for(i = 1; i < numItems; ++i) 24 | { 25 | int x; 26 | h2.pop(x); 27 | if(x != i) 28 | cout << "Oops! " << i << endl; 29 | } 30 | 31 | if(!h1.empty()) 32 | cout << "Oops! h1 should have been empty!" << endl; 33 | 34 | cout << "End test... no other output is good" << endl; 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /part6/priority_queue_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // 8 | template 9 | void dumpContents(const string & msg, PriorityQueue & pq) 10 | { 11 | cout << msg << ":" << endl; 12 | while(!pq.empty()) 13 | { 14 | cout << pq.top() << endl; 15 | pq.pop(); 16 | } 17 | } 18 | 19 | int main( ) 20 | { 21 | priority_queue maxPQ; // 小根堆 22 | priority_queue, greater> minPQ; // 大根堆 23 | 24 | vector nums = {1,3,5,2,12,9,16,11,8,10}; 25 | 26 | for(auto x : nums) 27 | { 28 | minPQ.push(x); 29 | maxPQ.push(x); 30 | } 31 | 32 | dumpContents("minPQ", minPQ); 33 | dumpContents("maxPQ", maxPQ); 34 | 35 | return 0; 36 | } -------------------------------------------------------------------------------- /part7/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART7) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | elseif(${CMAKE_BUILD_TYPE} MATCHES Release) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Using [Release] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # sort 排序 15 | set(DEMO sort) 16 | set(LIB ../lib) 17 | set(SOURCE 18 | ${DEMO}_test.cpp 19 | ${DEMO}.hpp 20 | ${LIB}) 21 | add_executable(${DEMO} ${SOURCE}) 22 | 23 | # radix_sort 基数排序 24 | set(DEMO radix_sort) 25 | set(LIB ../lib) 26 | set(SOURCE 27 | ${DEMO}.cpp 28 | ${LIB}) 29 | add_executable(${DEMO} ${SOURCE}) -------------------------------------------------------------------------------- /part7/radix_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../lib/uniform_random.h" 6 | 7 | using namespace std; 8 | using namespace DS; 9 | 10 | // 基数排序实现 11 | // 假设字符串中只出现ASCII码 12 | // 如果字符串长度不同,补'\0'填充 13 | void radixSortA(vector& arr, int max_string_len) 14 | { 15 | const int BUCKETS = 256; 16 | vector> buckets(BUCKETS); // 桶 17 | for(int i = 1; i <= max_string_len; ++i) 18 | { 19 | // 从低位到高位,依次进行桶排序迭代 20 | // 对于string而言就是从字符串尾到头 21 | // 长度不够补0('\0') 22 | for(string& s : arr) 23 | { 24 | // 计算插入的桶序号 25 | int idx = static_cast((s.size() >= i) ? s[s.size() - i] : '\0'); 26 | buckets[idx].push_back(std::move(s)); 27 | } 28 | 29 | int pos = 0; 30 | for(auto& bucket : buckets) 31 | { 32 | for(string& s : bucket) 33 | arr[pos++] = std::move(s); 34 | bucket.clear(); 35 | } 36 | } 37 | } 38 | 39 | // 对数组进行计数基数排序 40 | // 假设字符串中只出现ASCII码 41 | // 假设所有字符串一样长 42 | // 详解见书P266-267 43 | void countingRadixSort(vector& arr, int max_string_len) 44 | { 45 | const int BUCKETS = 256; 46 | int n_total = arr.size(); 47 | vector buffer(n_total); 48 | 49 | vector* in = &arr; 50 | vector* out = &buffer; 51 | 52 | for(int i = 1; i <= max_string_len; ++i) 53 | { 54 | vector count(BUCKETS + 1); 55 | int idx = 0; 56 | for(string& s : (*in)) 57 | { 58 | idx = static_cast((s.size() >= i) ? s[s.size() - i] : '\0'); 59 | ++count[idx + 1]; 60 | } 61 | for(int b = 1; b < BUCKETS; ++b) 62 | count[b] += count[b - 1]; 63 | for(string& s : (*in)) 64 | { 65 | idx = static_cast((s.size() >= i) ? s[s.size() - i] : '\0'); 66 | (*out)[count[idx]++] = std::move(s); 67 | } 68 | std::swap(in, out); 69 | } 70 | // if odd number of passes, in is buffer, out is arr; so copy back 71 | if(max_string_len % 2 == 1) 72 | { 73 | for(int i = 0; i < arr.size(); ++i) 74 | (*out)[i] = std::move((*in)[i]); 75 | } 76 | } 77 | 78 | // 标准基数排序 79 | // 假设字符串中只有ASCII 80 | // 边长字符串 81 | void radixSort(vector& arr, int max_len) 82 | { 83 | const int BUCKETS = 256; 84 | vector> word_by_length(max_len + 1); 85 | vector> buckets(BUCKETS); 86 | // 按照字符串长度分类 87 | for(string& s : arr) 88 | { 89 | word_by_length[s.length()].push_back(std::move(s)); 90 | } 91 | // 将按照长度分类后的字符串放回arr(短在前,长在后) 92 | int idx = 0; 93 | for(auto& word_list : word_by_length) 94 | { 95 | for(string& s : word_list) 96 | arr[idx++] = std::move(s); 97 | } 98 | 99 | int starting_idx = arr.size(); 100 | // 从字符串尾到头 101 | for(int pos = max_len - 1; pos >= 0; --pos) 102 | { 103 | starting_idx -= word_by_length[pos + 1].size(); 104 | // 对starting_idx后的所有元素排序 105 | // 更长的字符串被包含在了含有短字符串的新的集合内 106 | for(int i = starting_idx; i < arr.size(); ++i) 107 | buckets[arr[i][pos]].push_back(std::move(arr[i])); 108 | idx = starting_idx; 109 | // 出桶 110 | for(auto& bucket : buckets) 111 | { 112 | for(string& s : bucket) 113 | arr[idx++] = std::move(s); 114 | bucket.clear(); 115 | } 116 | } 117 | } 118 | 119 | int main() 120 | { 121 | vector lst; 122 | UniformRandom r; 123 | const int N = 100000; 124 | const int LEN = 5; 125 | const int ADD = 7; 126 | 127 | for (int i = 0; i < N; ++i) 128 | { 129 | string str = ""; 130 | int len = LEN + ADD; //r.nextInt( ADD ); // between 5 and 11 characters 131 | 132 | for (int j = 0; j < len; ++j) 133 | str += static_cast( 'a' + r.nextInt(26)); 134 | 135 | lst.push_back(str); 136 | } 137 | 138 | vector arr1 = lst; 139 | vector arr2 = lst; 140 | vector arr3 = lst; 141 | vector arr4 = lst; 142 | 143 | sort(begin(arr1), end(arr1)); 144 | radixSortA(arr2, LEN + ADD); 145 | countingRadixSort(arr3, LEN + ADD); 146 | radixSort(arr4, LEN + ADD); 147 | 148 | cout << "radixSortA" << endl; 149 | for (int i = 0; i < arr1.size(); ++i) 150 | if (arr1[i] != arr2[i]) 151 | cout << "OOPS!! " << i << endl; 152 | cout << "=====" << endl; 153 | 154 | cout << "countingRadixSort" << endl; 155 | for (int i = 0; i < arr1.size(); ++i) 156 | if (arr1[i] != arr3[i]) 157 | cout << "OOPS!! " << i << endl; 158 | cout << "=====" << endl; 159 | 160 | cout << "radixSort" << endl; 161 | for (int i = 0; i < arr1.size(); ++i) 162 | if (arr1[i] != arr4[i]) 163 | cout << "OOPS!! " << i << endl; 164 | cout << "=====" << endl; 165 | 166 | return 0; 167 | } -------------------------------------------------------------------------------- /part7/sort.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SORT_HPP 2 | #define SORT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace DS 9 | { 10 | typedef std::size_t ds_size; 11 | 12 | // 插入排序,默认升序 13 | template> 14 | void insertionSort(std::vector& arr, const Compare& cmp = Compare()) 15 | { 16 | ds_size n_total = arr.size(); 17 | for(ds_size i = 1; i < n_total; ++i) 18 | { 19 | Object tmp = std::move(arr[i]); 20 | int j = i; 21 | for(; j != 0 && cmp(tmp, arr[j - 1]); --j) 22 | arr[j] = std::move(arr[j - 1]); 23 | arr[j] = std::move(tmp); 24 | } 25 | } 26 | 27 | // 指定排序范围的插入排序 28 | // 可以作为快速排序的子函数 29 | template> 30 | void insertionSort(std::vector& arr, ds_size left, ds_size right, 31 | const Compare& cmp = Compare()) 32 | { 33 | for(ds_size i = left; i <= right; ++i) 34 | { 35 | Object tmp = std::move(arr[i]); 36 | int j = i; 37 | for(; j != 0 && cmp(tmp, arr[j - 1]); --j) 38 | arr[j] = std::move(arr[j - 1]); 39 | arr[j] = std::move(tmp); 40 | } 41 | } 42 | 43 | template 44 | void insertionSort(const RandomIterator& begin, const RandomIterator& end, 45 | const Compare& cmp) 46 | { 47 | if(begin == end) 48 | return; 49 | RandomIterator iter; 50 | for(RandomIterator p = begin + 1; p != end; ++p) 51 | { 52 | auto tmp = std::move(*p); 53 | for(iter = p; iter != begin && cmp(tmp, *(iter - 1)); --iter) 54 | *iter = std::move(*(iter - 1)); 55 | *iter = std::move(tmp); 56 | } 57 | } 58 | 59 | template 60 | void insertionSort(const RandomIterator& begin, const RandomIterator& end) 61 | { 62 | insertionSort(begin, end, std::less{}); 63 | } 64 | 65 | // shell sort 希尔排序 66 | template> 67 | void shellSort(std::vector& arr, const Compare& cmp = Compare()) 68 | { 69 | for(ds_size gap = arr.size() / 2; gap != 0; gap /= 2) 70 | { 71 | // 间隔gap的插入排序 72 | for(ds_size i = gap; i < arr.size(); ++i) 73 | { 74 | Object tmp = std::move(arr[i]); 75 | ds_size j = i; 76 | for(; j >= gap && cmp(tmp, arr[j - gap]); j -= gap) 77 | arr[j] = std::move(arr[j - gap]); 78 | arr[j] = std::move(tmp); 79 | } 80 | } 81 | } 82 | 83 | inline ds_size leftChild(ds_size i) 84 | { return 2 * i + 1; } 85 | 86 | inline int leftChild(int i) 87 | { return 2 * i + 1; } 88 | 89 | template> 90 | void percDown(std::vector& arr, ds_size begin, ds_size end, const Compare& cmp = Compare()) 91 | { 92 | ds_size child = leftChild(begin); 93 | Object tmp; 94 | for(tmp = std::move(arr[begin]); child < end; ) 95 | { 96 | if(child < end - 1 && cmp(arr[child], arr[child + 1])) 97 | ++child; 98 | if(cmp(tmp, arr[child])) 99 | arr[begin] = std::move(arr[child]); 100 | else 101 | break; 102 | begin = child; 103 | child = leftChild(begin); 104 | } 105 | arr[begin] = std::move(tmp); 106 | } 107 | 108 | // heap sort 109 | template> 110 | void heapSort(std::vector& arr, const Compare& cmp = Compare()) 111 | { 112 | // build heap 下滤过程,建立与排序顺序相反的堆 113 | for (ds_size i = arr.size() / 2 - 1; i > 0; --i) 114 | percDown(arr, i, arr.size(), cmp); 115 | percDown(arr, 0, arr.size(), cmp); 116 | // deleteTop 117 | for (ds_size j = arr.size() - 1; j > 0; --j) 118 | { 119 | std::swap(arr[0], arr[j]); // 去top 120 | percDown(arr, 0, j, cmp); // 下滤 121 | } 122 | } 123 | 124 | template> 125 | void merge(std::vector& arr, std::vector& tmp_arr, 126 | ds_size left, ds_size right, ds_size right_end, const Compare& cmp = Compare()) 127 | { 128 | ds_size left_end = right - 1; 129 | ds_size tmp_pos = left; 130 | ds_size n_elements = right_end - left + 1; 131 | 132 | // main loop 133 | // 将arr里的数字插入到tmp_arr 134 | while(left <= left_end && right <= right_end) 135 | { 136 | if(cmp(arr[left], arr[right])) 137 | tmp_arr[tmp_pos++] = std::move(arr[left++]); 138 | else 139 | tmp_arr[tmp_pos++] = std::move(arr[right++]); 140 | } 141 | while(left <= left_end) 142 | tmp_arr[tmp_pos++] = std::move(arr[left++]); 143 | 144 | while(right <= right_end) 145 | tmp_arr[tmp_pos++] = std::move(arr[right++]); 146 | 147 | // copy tmp_arr 148 | for(ds_size i = 0; i < n_elements; ++i, --right_end) 149 | arr[right_end] = std::move(tmp_arr[right_end]); 150 | } 151 | 152 | // 归并排序 153 | template> 154 | void mergeSort(std::vector& arr, std::vector& tmp_arr, 155 | ds_size left, ds_size right, const Compare& cmp = Compare()) 156 | { 157 | if(left < right) 158 | { 159 | ds_size mid = (left + right) / 2; 160 | mergeSort(arr, tmp_arr, left, mid, cmp); 161 | mergeSort(arr, tmp_arr, mid + 1, right, cmp); 162 | merge(arr, tmp_arr, left, mid + 1, right, cmp); 163 | } 164 | } 165 | 166 | template> 167 | void mergeSort(std::vector& arr, const Compare& cmp = Compare()) 168 | { 169 | std::vector tmp_arr(arr.size(), Object()); 170 | mergeSort(arr, tmp_arr, 0, arr.size() - 1, cmp); 171 | } 172 | 173 | // 采用三分中值分割法找枢轴 174 | template> 175 | const Object& median3(std::vector& arr, ds_size left, ds_size right, 176 | const Compare& cmp = Compare()) 177 | { 178 | ds_size mid = (left + right) / 2; // 中间点 179 | if(cmp(arr[mid], arr[left])) // mid 与 left 逆序 180 | std::swap(arr[left], arr[mid]); 181 | if(cmp(arr[right], arr[left])) // right 与 left 逆序 182 | std::swap(arr[left], arr[right]); 183 | if(cmp(arr[right], arr[mid])) // right 与 mid逆序 184 | std::swap(arr[right], arr[mid]); 185 | // 交换之后 arr[left] arr[mid] arr[right] 有序 186 | std::swap(arr[mid], arr[right - 1]); // 将mid处放到right-1去 187 | return arr[right - 1]; 188 | } 189 | 190 | template> 191 | void quickSort(std::vector& arr, ds_size left, ds_size right, 192 | const Compare& cmp = Compare()) 193 | { 194 | // 递归过程中,当子数组大小较小时,会使用插入排序直接保持有序 195 | if(left + 10 <= right) 196 | { 197 | // 找pivot 198 | const Object &pivot = median3(arr, left, right, cmp); 199 | // 三分中值法后 arr[left] arr[mid] arr[right] 有序 200 | // pivot 被放在 arr[right - 1] 处 201 | ds_size i = left, j = right - 1; 202 | while (true) 203 | { 204 | while (cmp(arr[++i], pivot)); // 从头向后,直到出现逆序 205 | while (cmp(pivot, arr[--j])); // 从后向前,直到出现逆序 206 | // 处理逆序 207 | if (i < j) 208 | std::swap(arr[i], arr[j]); // 交换逆序数,arr[j] 放到pivot之前,arr[i] 放到pivot之后 209 | else 210 | break; 211 | } 212 | // 上述结束后,i,j 指向一个逆序于pivot元素 213 | std::swap(arr[i], arr[right - 1]); // 保存pivot 214 | // 枢轴不用再操作 215 | quickSort(arr, left, i - 1, cmp); // sort small elements 216 | quickSort(arr, i + 1, right, cmp); // sort large elements 217 | } else{ // 对于长度小于10的排序表,用直接插入排序更快 218 | insertionSort(arr, left, right, cmp); 219 | } 220 | } 221 | 222 | // 快速排序 223 | // 采用三分中值分割法找枢轴 224 | template> 225 | void quickSort(std::vector& arr, const Compare& cmp = Compare()) 226 | { 227 | quickSort(arr, 0, arr.size() - 1, cmp); 228 | } 229 | 230 | // 最经典的快速排序 231 | template > 232 | void SORT(std::vector& arr, const Compare& cmp = Compare()) 233 | { 234 | if(arr.size() < 2) 235 | return; 236 | std::vector smaller; 237 | std::vector same; 238 | std::vector larger; 239 | 240 | auto chosen_item = arr[arr.size() / 2]; // 取中间 241 | for(auto& i : arr) 242 | { 243 | if(cmp(i, chosen_item)) 244 | smaller.push_back(std::move(i)); 245 | else if(cmp(chosen_item, i)) 246 | larger.push_back(std::move(i)); 247 | else 248 | same.push_back(std::move(i)); 249 | } 250 | 251 | SORT(smaller); 252 | SORT(larger); 253 | 254 | // 将smaller same larger数组的内容转移到arr中 255 | std::move(std::begin(smaller), std::end(smaller), std::begin(arr)); 256 | std::move(std::begin(same), std::end(same), std::begin(arr) + smaller.size()); 257 | std::move(std::begin(larger), std::end(larger), std::end(arr) - larger.size()); 258 | } 259 | 260 | // 快速选择 261 | // Internal selection method that makes recursive calls. 262 | // Uses median-of-three partitioning and a cutoff of 10. 263 | // Places the kth smallest item in a[k-1]. 264 | // a is an array of Comparable items. 265 | // left is the left-most index of the subarray. 266 | // right is the right-most index of the subarray. 267 | // k is the desired rank (1 is minimum) in the entire array. 268 | template> 269 | void quickSelect(std::vector& arr, ds_size left, ds_size right, 270 | ds_size k, const Compare& cmp = Compare()) 271 | { 272 | if(left + 10 <= right) 273 | { 274 | const Object& pivot = median3(arr, left, right, cmp); 275 | 276 | ds_size i = left, j = right - 1; 277 | while (true) 278 | { 279 | while (cmp(arr[++i], pivot)); 280 | while (cmp(pivot, arr[--j])); 281 | if (i < j) 282 | std::swap(arr[i], arr[j]); 283 | else 284 | break; 285 | } 286 | 287 | std::swap(arr[i], arr[right - 1]); 288 | 289 | // 相比快速排序,快速选择只重新排其中一部分 290 | if(k <= i) 291 | quickSelect(arr, left, i - 1, k); 292 | else if(k > i + 1) 293 | quickSelect(arr, i + 1, right, k); 294 | } else{ 295 | insertionSort(arr, left, right, cmp); 296 | } 297 | } 298 | 299 | // Quick selection algorithm. 300 | // Places the kth smallest item in a[k-1]. 301 | // a is an array of Comparable items. 302 | // k is the desired rank (1 is minimum) in the entire array. 303 | template> 304 | void quickSelect(std::vector& arr, ds_size k, const Compare& cmp = Compare()) 305 | { 306 | quickSelect(arr, 0, arr.size() - 1, k, cmp); 307 | } 308 | } 309 | #endif //SORT_HPP 310 | -------------------------------------------------------------------------------- /part7/sort_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sort.hpp" 3 | #include 4 | #include 5 | #include "../lib/uniform_random.h" 6 | 7 | using namespace std; 8 | using namespace DS; 9 | 10 | void checkSort(const vector &a, const string& msg) 11 | { 12 | for (std::size_t i = 0; i < a.size(); ++i) 13 | if (a[i].length() != i) 14 | cout << msg << " error at " << i << endl; 15 | cout << "Finished checksort " << msg << endl; 16 | } 17 | 18 | 19 | template 20 | void permute(vector &a) 21 | { 22 | static UniformRandom r; 23 | 24 | for (std::size_t j = 1; j < a.size(); ++j) 25 | swap(a[j], a[r.nextInt(0, j)]); 26 | } 27 | 28 | 29 | int main() 30 | { 31 | const int NUM_ITEMS = 1000; 32 | 33 | vector a(NUM_ITEMS); // This input adds factor of N to running time 34 | for (std::size_t i = 1; i < a.size(); ++i) // but we want to test std::move logic 35 | a[i] = a[i - 1] + 'a'; 36 | 37 | for (int theSeed = 0; theSeed < 10; ++theSeed) 38 | { 39 | cout << "epoch " << theSeed << endl; 40 | permute(a); 41 | insertionSort(a); 42 | checkSort(a, "insertionSort(a)"); 43 | 44 | permute(a); 45 | insertionSort(begin(a), end(a)); 46 | checkSort(a, "insertionSort(begin(a), end(a))"); 47 | 48 | permute(a); 49 | heapSort(a); 50 | checkSort(a, "heapSort(a)"); 51 | 52 | permute(a); 53 | shellSort(a); 54 | checkSort(a, "shellSort(a)"); 55 | 56 | permute(a); 57 | mergeSort(a); 58 | checkSort(a, "mergeSort(a)"); 59 | 60 | permute(a); 61 | quickSort(a); 62 | checkSort(a, "quickSort(a)"); 63 | 64 | permute(a); 65 | SORT(a); 66 | checkSort(a, "SORT(a)"); 67 | 68 | permute(a); 69 | quickSelect(a, NUM_ITEMS / 2); 70 | cout << a[NUM_ITEMS / 2 - 1].length() << " " << NUM_ITEMS / 2 << endl; 71 | cout << "========" << endl; 72 | } 73 | 74 | cout << "Checking SORT, Fig 7.13" << endl; 75 | int N = NUM_ITEMS * NUM_ITEMS; 76 | vector b(N); 77 | for (int i = 0; i < N; ++i) 78 | b[i] = i; 79 | permute(b); 80 | SORT(b); 81 | for (int i = 0; i < N; ++i) 82 | if (b[i] != i) 83 | cout << "OOPS!!" << endl; 84 | 85 | return 0; 86 | } -------------------------------------------------------------------------------- /part8/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART8) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | elseif(${CMAKE_BUILD_TYPE} MATCHES Release) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Using [Release] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # disjoint_set 不相交集合 15 | set(DEMO disjoint_set) 16 | set(LIB ../lib) 17 | set(SOURCE 18 | ${DEMO}_test.cpp 19 | ${DEMO}.hpp 20 | ${LIB}) 21 | add_executable(${DEMO} ${SOURCE}) -------------------------------------------------------------------------------- /part8/disjoint_set.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DISJOINT_SET_HPP 2 | #define DISJOINT_SET_HPP 3 | 4 | // DisjSets class 5 | // 6 | // CONSTRUCTION: with int representing initial number of sets 7 | // 8 | // ******************PUBLIC OPERATIONS********************* 9 | // void union( root1, root2 ) --> Merge two sets 10 | // int find( x ) --> Return set containing x 11 | // ******************ERRORS******************************** 12 | // No error checking is performed 13 | 14 | #include 15 | #include 16 | #include 17 | #include "../lib/dsexceptions.h" 18 | 19 | namespace DS 20 | { 21 | template 22 | class DisjSets 23 | { 24 | public: 25 | // init disjoint sets 26 | // 一开始所有的元素都互相独立 27 | explicit DisjSets(const std::vector& elements) 28 | { 29 | for(auto& x : elements) 30 | { 31 | s_[x].flag_ = true; 32 | s_[x].value_.height_ = 0; 33 | } 34 | } 35 | 36 | // // Perform a find. 37 | // // Return the set containing x. 38 | // const Object& find(const Object& x) const 39 | // { 40 | // auto iter = s_.find(x); 41 | // if(iter == s_.end()) 42 | // throw IllegalArgumentException{}; 43 | // if(iter == nullptr) 44 | // return s_[x]; 45 | // else 46 | // return find(s_[x]); 47 | // } 48 | 49 | // Perform a find with path compression. 50 | // Return the set containing x. 51 | // 使用路径压缩实时优化的find 52 | const Object& find(const Object& x) 53 | { 54 | // 判断存在性 55 | auto iter = s_.find(x); // &{x, s_[x]} 56 | if(iter == s_.end()) 57 | throw IllegalArgumentException{}; 58 | // 主要流程 59 | if(iter->second.flag_) // x为集合的根,返回x本身 60 | return x; 61 | else // 找到x所在集合的根,s[x]指向根 62 | { 63 | return iter->second.value_.root_ = find(iter->second.value_.root_); 64 | } 65 | } 66 | 67 | // Union two disjoint sets. 68 | // For simplicity, we assume root1 and root2 69 | // are distinct and represent set names. 70 | // root1 is the root of set 1. 71 | // root2 is the root of set 2. 72 | void unionSets(const Object& root1, const Object& root2) 73 | { 74 | auto iter1 = s_.find(root1); 75 | auto iter2 = s_.find(root2); 76 | if(iter1 == s_.end() || iter2 == s_.end()) 77 | return; 78 | // 不是根 79 | if(false == iter1->second.flag_ || false == iter2->second.flag_) 80 | throw IllegalArgumentException{}; 81 | // 主要流程 82 | // root2 is deeper, make root2 new root 83 | if(iter1->second.value_.height_ < iter2->second.value_.height_) 84 | { 85 | iter1->second.flag_ = false; 86 | iter1->second.value_.root_ = root2; 87 | } // root1 is deeper or equal height, make root1 new root 88 | else 89 | { 90 | // 如果高度相等高度,root1增高 91 | if(iter1->second.value_.height_ == iter2->second.value_.height_) 92 | ++(iter1->second.value_.height_); 93 | iter2->second.flag_ = false; 94 | iter2->second.value_.root_ = root1; 95 | } 96 | } 97 | private: 98 | union Value 99 | { 100 | int height_; 101 | Object root_; 102 | }; 103 | struct Element 104 | { 105 | bool flag_; // 标记是否是根 106 | Value value_; 107 | }; 108 | std::unordered_map s_; 109 | }; 110 | } 111 | 112 | #endif //DISJOINT_SET_HPP 113 | -------------------------------------------------------------------------------- /part8/disjoint_set_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "disjoint_set.hpp" 4 | using namespace std; 5 | using namespace DS; 6 | 7 | // Test main; all finds on same output line should be identical 8 | int main() 9 | { 10 | int numElements = 128; 11 | int numInSameSet = 16; 12 | vector vec(numElements, 0); 13 | for(int i = 0; i < numElements; ++i) 14 | { 15 | vec[i] = i; 16 | } 17 | 18 | DisjSets ds{vec}; 19 | int set1, set2; 20 | 21 | for (int k = 1; k < numInSameSet; k *= 2) 22 | { 23 | for (int j = 0; j + k < numElements; j += 2 * k) 24 | { 25 | set1 = ds.find(j); 26 | set2 = ds.find(j + k); 27 | cout << set1 << " " << set2 << endl; 28 | ds.unionSets(set1, set2); 29 | } 30 | } 31 | 32 | for (int i = 0; i < numElements; ++i) 33 | { 34 | cout << ds.find(i) << "-" << i << "*"; 35 | if (i % numInSameSet == numInSameSet - 1) 36 | cout << endl; 37 | } 38 | cout << endl; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /part9/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(DS_PART9) 3 | 4 | if(${CMAKE_BUILD_TYPE} MATCHES Debug) 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") 6 | message("Using [Debug] mode") 7 | elseif(${CMAKE_BUILD_TYPE} MATCHES Release) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 9 | message("Using [Release] mode") 10 | endif() 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | # 图类算法 15 | # word_ladder 16 | set(DEMO word_ladder) 17 | set(LIB ../lib) 18 | set(SOURCE 19 | ${DEMO}.cpp 20 | ${LIB}) 21 | add_executable(${DEMO} ${SOURCE}) -------------------------------------------------------------------------------- /part9/word_ladder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by DDRHb on 2019/10/7. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | void readWords(ifstream& in, vector& container) 17 | { 18 | string line; 19 | while(in >> line) 20 | container.push_back(line); 21 | } 22 | 23 | void computeAdjacentWords(const vector& words, map>& adj_words) 24 | { 25 | map> words_by_length; 26 | 27 | // 根据单词长度划分分组 28 | for(auto & word : words) 29 | words_by_length[word.size()].push_back(word); 30 | 31 | // 对于每个分组 32 | for(auto & entry : words_by_length) 33 | { 34 | const vector & group_words{entry.second}; 35 | int word_length = entry.first; 36 | 37 | // 对单词的每一个位置 38 | for(int i = 0; i < word_length; ++i) 39 | { 40 | // Remove one character in specified position, computing representative. 41 | // Words with same representatives are adjacent 42 | map> rep_to_word; 43 | for(auto & word : group_words) 44 | { 45 | string rep = word; 46 | rep.erase(i, 1); 47 | rep_to_word[rep].push_back(word); 48 | } 49 | 50 | // and then look for map values with more than one string 51 | for(auto & word : rep_to_word) 52 | { 53 | const vector & clique = word.second; 54 | if(clique.size() > 1) 55 | { 56 | // 单词两两之间配对,加入adj_words 57 | for(size_t p = 0; p < clique.size(); ++p) 58 | { 59 | for(size_t q = p + 1; q < clique.size(); ++q) 60 | { 61 | adj_words[clique[p]].push_back(clique[q]); 62 | adj_words[clique[q]].push_back(clique[p]); 63 | } 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | void printHighChangeables(const map>& adj_word, int min_words = 15) 72 | { 73 | if(min_words <= 0) 74 | return; 75 | for(auto & entry : adj_word) 76 | { 77 | const vector& words = entry.second; 78 | if(words.size() >= min_words) 79 | { 80 | cout << entry.first << " (" << words.size() << "):"; 81 | for(auto & str : words) 82 | cout << " " << str; 83 | cout << endl; 84 | } 85 | } 86 | } 87 | 88 | vector getChainFromPreviousMap(const map& previous, 89 | const string& first, const string& second) 90 | { 91 | vector result; 92 | auto& prev = const_cast&>(previous); 93 | for(string current = second; !current.empty(); current = prev[current]) 94 | result.push_back(current); 95 | reverse(result.begin(), result.end()); 96 | return result; 97 | } 98 | 99 | // Runs the shortest path calculation from the adjacency map, returning a vector 100 | // that contains the sequence of word changes to get from first to second. 101 | // 利用广度优先BFS找单词first到second的最快替换路线 102 | vector findChain(const map>& adjacent_words, 103 | const string& first, const string& second) 104 | { 105 | map previous_word; // 记录已经访问的节点 106 | queue q; 107 | previous_word[first] = first; 108 | q.push(first); 109 | // BFS 广度优先搜索 110 | while(!q.empty() && q.front() != second) 111 | { 112 | string current = q.front(); 113 | q.pop(); 114 | auto iter = adjacent_words.find(current); 115 | if(iter != adjacent_words.end()) 116 | { 117 | const vector& adj = iter->second; 118 | for(auto& str : adj) 119 | { 120 | if(previous_word.find(str) == previous_word.end()) 121 | { 122 | previous_word[str] = current; 123 | q.push(str); 124 | } 125 | } 126 | } 127 | } 128 | previous_word[first] = ""; 129 | if(previous_word.find(second) != previous_word.end()) 130 | return getChainFromPreviousMap(previous_word, first, second); 131 | else 132 | return vector{}; 133 | } 134 | 135 | int main() 136 | { 137 | clock_t start, end; 138 | ifstream file("../dict.txt"); 139 | if (!file.is_open()) 140 | { 141 | cout << "Error opening file"; 142 | exit (1); 143 | } 144 | vector words(32, string{}); 145 | // read words from dict.txt 146 | readWords(file, words); 147 | 148 | map> adjacent_words; 149 | 150 | start = clock(); 151 | computeAdjacentWords(words, adjacent_words); 152 | end = clock(); 153 | cout << "Elapsed time FAST: " << double(end - start) / CLOCKS_PER_SEC << endl; 154 | 155 | printHighChangeables(adjacent_words, 15); 156 | 157 | while(true) 158 | { 159 | cout << "Enter two words:"; 160 | string w1, w2; 161 | cin >> w1 >> w2; 162 | vector path = findChain(adjacent_words, w1, w2); 163 | cout << path.size() << endl; 164 | for(string& word : path) 165 | cout << word << " "; 166 | cout << endl; 167 | } 168 | return 0; 169 | } --------------------------------------------------------------------------------