├── README.md ├── chapter8-disjoint-set.cpp ├── chapter6-bubble-sort.cpp ├── chapter6-selection-sort.cpp ├── chapter6-insertion-sort.cpp ├── chapter6-shell-sort.cpp ├── chapter6-bucket-sort.cpp ├── chapter3-stack.cpp ├── chapter3-queue.cpp ├── chapter10-primality-testing.cpp ├── chapter6-merge-sort.cpp ├── chapter6-radix-sort.cpp ├── chapter10-ordering-matrix-multiplication.cpp ├── chapter9-topological-sort.cpp ├── chapter6-heap-sort.cpp ├── chapter9-unweighted-shortest-path.cpp ├── chapter9-all-pairs-shortest-path.cpp ├── chapter6-quick-sort.cpp ├── chapter9-weighted-shortest-path.cpp ├── chapter10-a-simple-nim.cpp ├── chapter4-binary-tree.cpp ├── chapter9-prims-algorithm.cpp ├── chapter9-cut-vertices.cpp ├── chapter9-kruskals-algorithm.cpp ├── chapter3-singly-linked-list.cpp ├── chapter10-turnpike-reconstrution.cpp ├── chapter10-closest-pair-of-points.cpp ├── chapter10-huffman-encoding.cpp ├── chapter3-doubly-linked-list.cpp ├── chapter7-hash-map.cpp ├── chapter5-priority-queue.cpp ├── chapter9-maximum-flow.cpp ├── chapter10-minimax-game-strategy.cpp ├── chapter7-hash-set.cpp ├── chapter10-strassen-algorithm.cpp ├── chapter10-skip-list.cpp ├── chapter10-alpha-beta-pruning.cpp ├── chapter4-binary-search-tree.cpp ├── chapter4-splay-tree.cpp └── chapter4-avl-tree.cpp /README.md: -------------------------------------------------------------------------------- 1 | Data-Structures-and-Algorithm-Analysis-in-C 2 | =========================================== 3 | 4 | A good textbook by Mark Allen Weiss. 5 | ------------------------------------------- 6 | I decide to make a review on this book and implement the data structures myself.
7 | Reinventing a wheel is important training, especially for those who design a car.
8 | Digesting CLRS might be too time-consuming, and inappropriate for a job-seeker like me.
9 | This book will be a proper substitute.
10 | Timestamp: 1399952708
11 | -------------------------------------------------------------------------------- /chapter8-disjoint-set.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for disjoint set. 2 | #include 3 | using namespace std; 4 | 5 | int findRoot(const vector &dj, int x) 6 | { 7 | int k, r; 8 | 9 | r = x; 10 | while (r != dj[r]) { 11 | r = dj[r]; 12 | } 13 | 14 | k = x; 15 | while (k != r) { 16 | x = dj[x]; 17 | dj[k] = r; 18 | k = x; 19 | } 20 | 21 | return r; 22 | } 23 | 24 | void unionSet(vector &dj, int x, int y) 25 | { 26 | int n = (int)dj.size(); 27 | 28 | if (x == y) { 29 | return; 30 | } 31 | 32 | dj[x] = y; 33 | findRoot(x); 34 | } 35 | 36 | int main() 37 | { 38 | return 0; 39 | } -------------------------------------------------------------------------------- /chapter6-bubble-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for bubble sort. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | void bubbleSort(vector &v) 7 | { 8 | int n, i, j; 9 | int val; 10 | 11 | n = (int)v.size(); 12 | for (i = 0; i < n; ++i) { 13 | for (j = n - 1; j > i; --j) { 14 | if (v[j - 1] > v[j]) { 15 | val = v[j - 1]; 16 | v[j - 1] = v[j]; 17 | v[j] = val; 18 | } 19 | } 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | vector v; 26 | int n, i; 27 | 28 | while (cin >> n && n > 0) { 29 | v.resize(n); 30 | for (i = 0; i < n; ++i) { 31 | cin >> v[i]; 32 | } 33 | bubbleSort(v); 34 | for (i = 0; i < n; ++i) { 35 | cout << v[i] << ' '; 36 | } 37 | cout << endl; 38 | } 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /chapter6-selection-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for selection sort. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | void selectionSort(vector &v) 7 | { 8 | int n, i, j; 9 | int val; 10 | 11 | n = (int)v.size(); 12 | for (i = 0; i < n; ++i) { 13 | for (j = i + 1; j < n; ++j) { 14 | if (v[i] > v[j]) { 15 | val = v[i]; 16 | v[i] = v[j]; 17 | v[j] = val; 18 | } 19 | } 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | vector v; 26 | int n, i; 27 | 28 | while (cin >> n && n > 0) { 29 | v.resize(n); 30 | for (i = 0; i < n; ++i) { 31 | cin >> v[i]; 32 | } 33 | selectionSort(v); 34 | for (i = 0; i < n; ++i) { 35 | cout << v[i] << ' '; 36 | } 37 | cout << endl; 38 | } 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /chapter6-insertion-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for insertion sort. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | void insertionSort(vector &v) 7 | { 8 | int i, j, n; 9 | int val; 10 | 11 | n = (int)v.size(); 12 | if (n <= 1) { 13 | return; 14 | } 15 | 16 | for (i = 1; i < n; ++i) { 17 | val = v[i]; 18 | for (j = i - 1; j >= 0 && v[j] > val; --j) { 19 | v[j + 1] = v[j]; 20 | } 21 | v[j + 1] = val; 22 | } 23 | } 24 | 25 | int main() 26 | { 27 | vector v; 28 | int n, i; 29 | 30 | while (cin >> n && n > 0) { 31 | v.resize(n); 32 | for (i = 0; i < n; ++i) { 33 | cin >> v[i]; 34 | } 35 | insertionSort(v); 36 | for (i = 0; i < n; ++i) { 37 | cout << v[i] << ' '; 38 | } 39 | cout << endl; 40 | } 41 | 42 | return 0; 43 | } -------------------------------------------------------------------------------- /chapter6-shell-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for shell sort. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | void shellSort(vector &v) 7 | { 8 | int n, i, j; 9 | int tmp; 10 | int increment; 11 | 12 | n = (int)v.size(); 13 | for (increment = n / 2; increment > 0; increment /= 2) { 14 | for (i = increment; i < n; ++i) { 15 | tmp = v[i]; 16 | for (j = i; j >= increment && v[j - increment] > tmp; j -= increment) { 17 | v[j] = v[j - increment]; 18 | } 19 | v[j] = tmp; 20 | } 21 | } 22 | } 23 | 24 | int main() 25 | { 26 | vector v; 27 | int n, i; 28 | 29 | while (cin >> n && n > 0) { 30 | v.resize(n); 31 | for (i = 0; i < n; ++i) { 32 | cin >> v[i]; 33 | } 34 | shellSort(v); 35 | for (i = 0; i < n; ++i) { 36 | cout << v[i] << ' '; 37 | } 38 | cout << endl; 39 | } 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /chapter6-bucket-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for radix sort. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void bucketSort(vector &v) 8 | { 9 | const int BUCKET_SIZE = 1000; 10 | const int BUCKET_NUM = 1000; 11 | vector buckets[BUCKET_NUM]; 12 | 13 | int n, i, j, k; 14 | 15 | n = (int)v.size(); 16 | for (i = 0; i < n; ++i) { 17 | buckets[v[i] / BUCKET_SIZE % BUCKET_NUM].push_back(v[i]); 18 | } 19 | 20 | k = 0; 21 | for (i = 0; i < BUCKET_NUM; ++i) { 22 | if (buckets[i].size() > 1) { 23 | sort(buckets[i].begin(), buckets[i].end()); 24 | } 25 | for (j = 0; j < (int)buckets[i].size(); ++j) { 26 | v[k++] = buckets[i][j]; 27 | } 28 | buckets[i].clear(); 29 | } 30 | } 31 | 32 | int main() 33 | { 34 | vector v; 35 | int n, i; 36 | 37 | while (cin >> n && n > 0) { 38 | v.resize(n); 39 | for (i = 0; i < n; ++i) { 40 | cin >> v[i]; 41 | } 42 | bucketSort(v); 43 | for (i = 0; i < n; ++i) { 44 | cout << v[i] << ' '; 45 | } 46 | cout << endl; 47 | } 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /chapter3-stack.cpp: -------------------------------------------------------------------------------- 1 | // My implementation of stack. 2 | class Stack { 3 | public: 4 | Stack() { 5 | m_capacity = 1; 6 | m_size = 0; 7 | m_data = new int[m_capacity]; 8 | } 9 | 10 | void push(int val) { 11 | if (m_size + 1 >= m_capacity) { 12 | resize(2 * m_capacity); 13 | } 14 | m_data[m_size++] = val; 15 | } 16 | 17 | void pop() { 18 | if (m_size > 0) { 19 | --m_size; 20 | } 21 | } 22 | 23 | int top() { 24 | return m_data[m_size - 1]; 25 | } 26 | 27 | int size() { 28 | return m_size; 29 | } 30 | 31 | bool empty() { 32 | return m_size == 0; 33 | } 34 | 35 | ~Stack() { 36 | delete m_data; 37 | } 38 | private: 39 | int *m_data; 40 | int m_capacity; 41 | int m_size; 42 | 43 | void resize(int new_capacity) { 44 | if (new_capacity <= m_capacity) { 45 | return; 46 | } 47 | int *new_data = new int[new_capacity]; 48 | 49 | for (int i = 0; i < m_size; ++i) { 50 | new_data[i] = m_data[i]; 51 | } 52 | delete[] m_data; 53 | m_data = new_data; 54 | m_capacity = new_capacity; 55 | } 56 | }; 57 | 58 | int main() 59 | { 60 | return 0; 61 | } -------------------------------------------------------------------------------- /chapter3-queue.cpp: -------------------------------------------------------------------------------- 1 | // My implementation of queue with two stacks. 2 | #include 3 | using namespace std; 4 | 5 | class Queue { 6 | public: 7 | Queue() {} 8 | 9 | void push(int val) { 10 | s1.push(val); 11 | } 12 | 13 | void pop() { 14 | if (s2.empty()) { 15 | while (!s1.empty()) { 16 | s2.push(s1.top()); 17 | s1.pop(); 18 | } 19 | } 20 | s2.pop(); 21 | } 22 | 23 | int size() { 24 | return s1.size() + s2.size(); 25 | } 26 | 27 | bool empty() { 28 | return size() == 0; 29 | } 30 | 31 | int front() { 32 | if (s2.empty()) { 33 | while (!s1.empty()) { 34 | s2.push(s1.top()); 35 | s1.pop(); 36 | } 37 | } 38 | 39 | return s2.top(); 40 | } 41 | 42 | int back() { 43 | if (s1.empty()) { 44 | while (!s2.empty()) { 45 | s1.push(s2.top()); 46 | s2.pop(); 47 | } 48 | } 49 | 50 | return s1.top(); 51 | } 52 | 53 | ~Queue() { 54 | while (!s1.empty()) { 55 | s1.pop(); 56 | } 57 | while (!s2.empty()) { 58 | s2.pop(); 59 | } 60 | } 61 | private: 62 | stack s1, s2; 63 | }; 64 | 65 | int main() 66 | { 67 | return 0; 68 | } -------------------------------------------------------------------------------- /chapter10-primality-testing.cpp: -------------------------------------------------------------------------------- 1 | // Primality testing using Fermat's Lesser Theorem. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | int primalityTest(int a, int i, int n) 8 | { 9 | // a is randomly chosen between (1, n) to test the primality of n. 10 | int x, y; 11 | 12 | if (i == 0) { 13 | return 1; 14 | } 15 | 16 | x = primalityTest(a, i / 2, n); 17 | if (x == 0) { 18 | // x == 0 means n is composite. 19 | // recursively return false 20 | return 0; 21 | } 22 | 23 | y = (x * x) % n; 24 | if (i % 2 != 0) { 25 | y = (y * a) % n; 26 | } 27 | 28 | return y; 29 | } 30 | 31 | bool isPrime(const int n) 32 | { 33 | if (n < 2) { 34 | return false; 35 | } else if (n < 4) { 36 | return true; 37 | } 38 | 39 | const int NUM_OF_TRIALS = 10; 40 | int i = 0; 41 | while (i < NUM_OF_TRIALS) { 42 | if (primalityTest(2 + rand() % (n - 3), n - 1, n) != 1) { 43 | return false; 44 | } 45 | ++i; 46 | } 47 | 48 | return true; 49 | } 50 | 51 | int main() 52 | { 53 | srand((unsigned int)time(nullptr)); 54 | int n; 55 | 56 | while (cin>> n && n > 0) { 57 | cout << (isPrime(n) ? "Yes": "No") << endl; 58 | } 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /chapter6-merge-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for merge sort. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | void mergeSortRecursive(vector &v, vector &temp, int left, int right) 7 | { 8 | if (right - left < 1) { 9 | return; 10 | } 11 | int mid = left + (right - left) / 2; 12 | mergeSortRecursive(v, temp, left, mid); 13 | mergeSortRecursive(v, temp, mid + 1, right); 14 | 15 | int i, j, k; 16 | i = left; 17 | j = mid + 1; 18 | k = left; 19 | while (i <= mid && j <= right) { 20 | if (v[i] < v[j]) { 21 | temp[k++] = v[i++]; 22 | } else { 23 | temp[k++] = v[j++]; 24 | } 25 | } 26 | while (i <= mid) { 27 | temp[k++] = v[i++]; 28 | } 29 | while (j <= right) { 30 | temp[k++] = v[j++]; 31 | } 32 | for (i = left; i <= right; ++i) { 33 | v[i] = temp[i]; 34 | } 35 | } 36 | 37 | void mergeSort(vector &v) 38 | { 39 | int n; 40 | vector temp; 41 | 42 | n = (int)v.size(); 43 | temp.resize(n); 44 | mergeSortRecursive(v, temp, 0, n - 1); 45 | temp.clear(); 46 | } 47 | 48 | int main() 49 | { 50 | vector v; 51 | int n, i; 52 | 53 | while (cin >> n && n > 0) { 54 | v.resize(n); 55 | for (i = 0; i < n; ++i) { 56 | cin >> v[i]; 57 | } 58 | mergeSort(v); 59 | for (i = 0; i < n; ++i) { 60 | cout << v[i] << ' '; 61 | } 62 | cout << endl; 63 | } 64 | 65 | return 0; 66 | } -------------------------------------------------------------------------------- /chapter6-radix-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for radix sort. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void radixSort(vector &v) 8 | { 9 | int n, i, j, k; 10 | int max_val; 11 | vector > rad; 12 | 13 | n = (int)v.size(); 14 | if (n <= 1) { 15 | return; 16 | } 17 | 18 | // This algorithm works for negative integers. 19 | max_val = abs(v[0]); 20 | for (i = 1; i < n; ++i) { 21 | max_val = max(abs(v[i]), max_val); 22 | } 23 | 24 | int exp = 1; 25 | while (max_val / exp >= 10) { 26 | exp *= 10; 27 | } 28 | 29 | rad.resize(19); 30 | int iexp = 1; 31 | while (true) { 32 | for (i = 0; i < n; ++i) { 33 | rad[v[i] / iexp % 10 + 9].push_back(v[i]); 34 | } 35 | 36 | k = 0; 37 | for (i = 0; i < 19; ++i) { 38 | int n2 = (int)rad[i].size(); 39 | for (j = 0; j < n2; ++j) { 40 | v[k++] = rad[i][j]; 41 | } 42 | rad[i].clear(); 43 | } 44 | 45 | if (iexp == exp) { 46 | break; 47 | } else { 48 | iexp *= 10; 49 | } 50 | } 51 | rad.clear(); 52 | } 53 | 54 | int main() 55 | { 56 | vector v; 57 | int n, i; 58 | 59 | while (cin >> n && n > 0) { 60 | v.resize(n); 61 | for (i = 0; i < n; ++i) { 62 | cin >> v[i]; 63 | } 64 | radixSort(v); 65 | for (i = 0; i < n; ++i) { 66 | cout << v[i] << ' '; 67 | } 68 | cout << endl; 69 | } 70 | 71 | return 0; 72 | } -------------------------------------------------------------------------------- /chapter10-ordering-matrix-multiplication.cpp: -------------------------------------------------------------------------------- 1 | // Ordering matrix multiplication, a typical dynamic programming problem. 2 | // Description: 3 | // You have a list of matrices M1, M2, ..., Mn to multiply. 4 | // Each with dimension (X1, Y1), (X2, Y2), ..., (Xn, Yn) 5 | // Of course, Yi == X(i + 1) 6 | // You can arrange the order of matrix multiplications, 7 | // to achieve minimal number of multiplications. 8 | // For example: A * B * C can be A * (B * C) or (A * B) * C, 9 | // they might require different number of multiplications. 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | const int INF = 1000000000; 15 | 16 | int orderingMatrixMultiplication(const vector &dimension) 17 | { 18 | int n = (int)dimension.size() - 1; 19 | vector > dp; 20 | 21 | dp.resize(n, vector(n, INF)); 22 | 23 | int i, j, k; 24 | 25 | for (i = 0; i < n; ++i) { 26 | dp[i][i] = 0; 27 | } 28 | 29 | for (i = 1; i < n; ++i) { 30 | for (j = 0; j + i < n; ++j) { 31 | for (k = j; k < j + i; ++k) { 32 | dp[j][j + i] = min(dp[j][j + i], dp[j][k] + dp[k + 1][j + i] 33 | + dimension[j] * dimension[k + 1] * dimension[j + i + 1]); 34 | } 35 | } 36 | } 37 | 38 | int result = dp[0][n - 1]; 39 | dp.clear(); 40 | 41 | return result; 42 | } 43 | 44 | int main() 45 | { 46 | int i; 47 | int n; 48 | vector v; 49 | 50 | while (cin >> n && n > 0) { 51 | v.resize(n + 1); 52 | for (i = 0; i < n + 1; ++i) { 53 | cin >> v[i]; 54 | } 55 | cout << orderingMatrixMultiplication(v) << endl; 56 | } 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /chapter9-topological-sort.cpp: -------------------------------------------------------------------------------- 1 | // A simple illustration for topological sort. Graph represented by adjacency matrix. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void topologicalSort(const vector > &graph, vector &order) 8 | { 9 | int n; 10 | int i, j; 11 | vector indegree; 12 | queue q; 13 | 14 | n = (int)graph.size(); 15 | indegree.resize(n, 0); 16 | 17 | for (i = 0; i < n; ++i) { 18 | for (j = 0; j < n; ++j) { 19 | if (graph[i][j]) { 20 | ++indegree[j]; 21 | } 22 | } 23 | } 24 | 25 | for (i = 0; i < n; ++i) { 26 | if (indegree[i] == 0) { 27 | q.push(i); 28 | break; 29 | } 30 | } 31 | 32 | while (!q.empty()) { 33 | i = q.front(); 34 | q.pop(); 35 | order.push_back(i); 36 | for (j = 0; j < n; ++j) { 37 | if (graph[i][j] && (--indegree[j] == 0)) { 38 | q.push(j); 39 | } 40 | } 41 | } 42 | 43 | indegree.clear(); 44 | } 45 | 46 | int main() 47 | { 48 | vector > graph; 49 | vector order; 50 | int n; 51 | int nk; 52 | int i, j; 53 | int tmp; 54 | 55 | while (cin >> n && n > 0) { 56 | graph.resize(n); 57 | for (i = 0; i < n; ++i) { 58 | graph[i].resize(n, false); 59 | } 60 | 61 | for (i = 0; i < n; ++i) { 62 | cin >> nk; 63 | for (j = 0; j < nk; ++j) { 64 | cin >> tmp; 65 | graph[i][tmp] = true; 66 | } 67 | } 68 | 69 | topologicalSort(graph, order); 70 | 71 | if ((int)order.size() == n) { 72 | for (i = 0; i < n; ++i) { 73 | cout << order[i] << ' '; 74 | } 75 | cout << endl; 76 | } else { 77 | cout << "The graph has a cycle." << endl; 78 | } 79 | 80 | for (i = 0; i < n; ++i) { 81 | graph[i].clear(); 82 | } 83 | graph.clear(); 84 | order.clear(); 85 | } 86 | 87 | return 0; 88 | } -------------------------------------------------------------------------------- /chapter6-heap-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for selection sort. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | static inline int leftChild(int n) 7 | { 8 | return n * 2 + 1; 9 | } 10 | 11 | static inline int rightChild(int n) 12 | { 13 | return n * 2 + 2; 14 | } 15 | 16 | static inline void swap(int &x, int &y) 17 | { 18 | int tmp; 19 | 20 | tmp = x; 21 | x = y; 22 | y = tmp; 23 | } 24 | 25 | static inline int max(const int &x, const int &y) 26 | { 27 | return x > y ? x : y; 28 | } 29 | 30 | static void percolateDown(vector &v, int i, int n) 31 | { 32 | if (n <= 1 || i < 0 || i >= n) { 33 | return; 34 | } 35 | int max_val; 36 | 37 | while (leftChild(i) < n) { 38 | if (leftChild(i) == n - 1) { 39 | max_val = v[leftChild(i)]; 40 | } else { 41 | max_val = max(v[leftChild(i)], v[rightChild(i)]); 42 | } 43 | if (v[i] < max_val) { 44 | if (max_val == v[leftChild(i)]) { 45 | swap(v[i], v[leftChild(i)]); 46 | i = leftChild(i); 47 | } else { 48 | swap(v[i], v[rightChild(i)]); 49 | i = rightChild(i); 50 | } 51 | } else { 52 | break; 53 | } 54 | } 55 | } 56 | 57 | void heapSort(vector &v) 58 | { 59 | int n; 60 | int i; 61 | 62 | n = (int)v.size(); 63 | for (i = (n - 1) / 2; i >= 0; --i) { 64 | percolateDown(v, i, n); 65 | } 66 | 67 | int val; 68 | for (i = 0; i < n - 1; ++i) { 69 | val = v[0]; 70 | v[0] = v[n - 1 - i]; 71 | percolateDown(v, 0, n - 1 - i); 72 | v[n - 1 - i] = val; 73 | } 74 | } 75 | 76 | int main() 77 | { 78 | vector v; 79 | int n, i; 80 | 81 | while (cin >> n && n > 0) { 82 | v.resize(n); 83 | for (i = 0; i < n; ++i) { 84 | cin >> v[i]; 85 | } 86 | heapSort(v); 87 | for (i = 0; i < n; ++i) { 88 | cout << v[i] << ' '; 89 | } 90 | cout << endl; 91 | } 92 | 93 | return 0; 94 | } -------------------------------------------------------------------------------- /chapter9-unweighted-shortest-path.cpp: -------------------------------------------------------------------------------- 1 | // A simple illustration for unweighted shortest path. Graph represented by adjacency matrix. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void unweightedShortestPath(const vector > &graph, 8 | vector &dist, vector &reachable) 9 | { 10 | // The minimal distances from 0th vertex to others. 11 | int n; 12 | int i, j; 13 | 14 | n = (int)graph.size(); 15 | dist.resize(n); 16 | reachable.resize(n); 17 | 18 | if (n < 1) { 19 | return; 20 | } 21 | 22 | for (i = 0; i < n; ++i) { 23 | reachable[i] = false; 24 | } 25 | 26 | queue q; 27 | 28 | dist[0] = 0; 29 | reachable[0] = true; 30 | 31 | q.push(0); 32 | while (!q.empty()) { 33 | i = q.front(); 34 | q.pop(); 35 | for (j = 0; j < n; ++j) { 36 | if (!graph[i][j] || reachable[j]) { 37 | continue; 38 | } 39 | dist[j] = dist[i] + 1; 40 | reachable[j] = true; 41 | q.push(j); 42 | } 43 | } 44 | } 45 | 46 | int main() 47 | { 48 | vector > graph; 49 | vector dist; 50 | vector reachable; 51 | int n; 52 | int nk; 53 | int i, j; 54 | int tmp; 55 | 56 | while (cin >> n && n > 0) { 57 | graph.resize(n); 58 | for (i = 0; i < n; ++i) { 59 | graph[i].resize(n, false); 60 | } 61 | 62 | for (i = 0; i < n; ++i) { 63 | cin >> nk; 64 | for (j = 0; j < nk; ++j) { 65 | cin >> tmp; 66 | graph[i][tmp] = true; 67 | } 68 | } 69 | 70 | unweightedShortestPath(graph, dist, reachable); 71 | 72 | for (i = 0; i < n; ++i) { 73 | cout << i << ": "; 74 | if (reachable[i]) { 75 | cout << dist[i] << endl; 76 | } else { 77 | cout << "Unreachable" << endl; 78 | } 79 | } 80 | 81 | for (i = 0; i < n; ++i) { 82 | graph[i].clear(); 83 | } 84 | graph.clear(); 85 | } 86 | 87 | return 0; 88 | } -------------------------------------------------------------------------------- /chapter9-all-pairs-shortest-path.cpp: -------------------------------------------------------------------------------- 1 | // A simple illustration for all pairs shortest path using Floyd Algorithm. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | const int INFINITY = 1000000000; 7 | 8 | void floydAlgorithm(const vector > &graph, 9 | vector > &dist) 10 | { 11 | int n; 12 | int i, j, k; 13 | 14 | n = (int)graph.size(); 15 | dist.resize(n); 16 | for (i = 0; i < n; ++i) { 17 | dist[i].resize(n, INFINITY); 18 | } 19 | 20 | for (i = 0; i < n; ++i) { 21 | for (j = 0; j < n; ++j) { 22 | dist[i][j] = graph[i][j]; 23 | } 24 | } 25 | 26 | for (k = 0; k < n; ++k) { 27 | for (i = 0; i < n; ++i) { 28 | for (j = 0; j < n; ++j) { 29 | if (dist[i][k] + dist[k][j] >= dist[i][j]) { 30 | continue; 31 | } 32 | dist[i][j] = dist[i][k] + dist[k][j]; 33 | } 34 | } 35 | } 36 | } 37 | 38 | int main() 39 | { 40 | vector > graph; 41 | vector > dist; 42 | int n; 43 | int nk; 44 | int i, j; 45 | int tmp, tmp_dist; 46 | 47 | while (cin >> n && n > 0) { 48 | graph.resize(n); 49 | for (i = 0; i < n; ++i) { 50 | graph[i].resize(n, INFINITY); 51 | } 52 | 53 | for (i = 0; i < n; ++i) { 54 | cin >> nk; 55 | for (j = 0; j < nk; ++j) { 56 | cin >> tmp >> tmp_dist; 57 | graph[i][tmp] = tmp_dist; 58 | } 59 | } 60 | 61 | floydAlgorithm(graph, dist); 62 | 63 | for (i = 0; i < n; ++i) { 64 | for (j = 0; j < n; ++j) { 65 | cout << "[" << i << "][" << j << "]: "; 66 | if (dist[i][j] < INFINITY) { 67 | cout << dist[i][j] << endl; 68 | } else { 69 | cout << "Unreachable" << endl; 70 | } 71 | } 72 | } 73 | 74 | for (i = 0; i < n; ++i) { 75 | graph[i].clear(); 76 | } 77 | graph.clear(); 78 | 79 | for (i = 0; i < n; ++i) { 80 | dist[i].clear(); 81 | } 82 | dist.clear(); 83 | } 84 | 85 | return 0; 86 | } -------------------------------------------------------------------------------- /chapter6-quick-sort.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for quick sort. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | const int CUT_OFF = 4; 7 | 8 | static void swap(int &x, int &y) 9 | { 10 | int tmp; 11 | 12 | tmp = x; 13 | x = y; 14 | y = tmp; 15 | } 16 | 17 | static int medianThree(vector &v, int left, int right) 18 | { 19 | int center = (left + right) / 2; 20 | 21 | if (v[left] > v[right]) { 22 | swap(v[left], v[right]); 23 | } 24 | if (v[left] > v[center]) { 25 | swap(v[left], v[center]); 26 | } 27 | if (v[center] > v[right]) { 28 | swap(v[center], v[right]); 29 | } 30 | swap(v[center], v[right - 1]); 31 | 32 | return v[right - 1]; 33 | } 34 | 35 | static void quickSortRecursive(vector &v, int left, int right) 36 | { 37 | if (right - left + 1 >= CUT_OFF) { 38 | int i, j; 39 | int pivot = medianThree(v, left, right); 40 | 41 | i = left; 42 | j = right - 1; 43 | while (true) { 44 | while (v[++i] < pivot) {} 45 | while (v[--j] > pivot) {} 46 | if (i < j) { 47 | swap(v[i], v[j]); 48 | } else { 49 | break; 50 | } 51 | } 52 | swap(v[i], v[right - 1]); 53 | quickSortRecursive(v, left, i - 1); 54 | quickSortRecursive(v, i + 1, right); 55 | } else { 56 | int i, j; 57 | int tmp; 58 | 59 | for (i = left + 1; i <= right; ++i) { 60 | tmp = v[i]; 61 | for (j = i; j > left && v[j - 1] > tmp; --j) { 62 | v[j] = v[j - 1]; 63 | } 64 | v[j] = tmp; 65 | } 66 | } 67 | } 68 | 69 | void quickSort(vector &v) 70 | { 71 | int n = (int)v.size(); 72 | quickSortRecursive(v, 0, n - 1); 73 | } 74 | 75 | int main() 76 | { 77 | vector v; 78 | int n, i; 79 | 80 | while (cin >> n && n > 0) { 81 | v.resize(n); 82 | for (i = 0; i < n; ++i) { 83 | cin >> v[i]; 84 | } 85 | quickSort(v); 86 | for (i = 0; i < n; ++i) { 87 | cout << v[i] << ' '; 88 | } 89 | cout << endl; 90 | } 91 | 92 | return 0; 93 | } -------------------------------------------------------------------------------- /chapter9-weighted-shortest-path.cpp: -------------------------------------------------------------------------------- 1 | // A simple illustration for weighted shortest path. Graph represented by adjacency matrix. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | const int INFINITY = 1000000000; 8 | 9 | void weightedShortestPath(const vector > &graph, 10 | vector &dist, vector &reachable) 11 | { 12 | // The minimal distances from 0th vertice to others. 13 | int n; 14 | int i, j; 15 | 16 | n = (int)graph.size(); 17 | dist.resize(n); 18 | reachable.resize(n); 19 | 20 | if (n < 1) { 21 | return; 22 | } 23 | 24 | for (i = 0; i < n; ++i) { 25 | reachable[i] = false; 26 | } 27 | 28 | queue q; 29 | 30 | dist[0] = 0; 31 | reachable[0] = true; 32 | 33 | q.push(0); 34 | while (!q.empty()) { 35 | i = q.front(); 36 | q.pop(); 37 | for (j = 0; j < n; ++j) { 38 | if (graph[i][j] == INFINITY || (reachable[j] && 39 | dist[i] + graph[i][j] >= dist[j])) { 40 | continue; 41 | } 42 | dist[j] = dist[i] + graph[i][j]; 43 | if (!reachable[j]) { 44 | q.push(j); 45 | } 46 | reachable[j] = true; 47 | } 48 | } 49 | } 50 | 51 | int main() 52 | { 53 | vector > graph; 54 | vector dist; 55 | vector reachable; 56 | int n; 57 | int nk; 58 | int i, j; 59 | int tmp, tmp_dist; 60 | 61 | while (cin >> n && n > 0) { 62 | graph.resize(n); 63 | for (i = 0; i < n; ++i) { 64 | graph[i].resize(n, INFINITY); 65 | } 66 | 67 | for (i = 0; i < n; ++i) { 68 | cin >> nk; 69 | for (j = 0; j < nk; ++j) { 70 | cin >> tmp >> tmp_dist; 71 | graph[i][tmp] = tmp_dist; 72 | } 73 | } 74 | 75 | weightedShortestPath(graph, dist, reachable); 76 | 77 | for (i = 0; i < n; ++i) { 78 | cout << i << ": "; 79 | if (reachable[i]) { 80 | cout << dist[i] << endl; 81 | } else { 82 | cout << "Unreachable" << endl; 83 | } 84 | } 85 | 86 | for (i = 0; i < n; ++i) { 87 | graph[i].clear(); 88 | } 89 | graph.clear(); 90 | } 91 | 92 | return 0; 93 | } -------------------------------------------------------------------------------- /chapter10-a-simple-nim.cpp: -------------------------------------------------------------------------------- 1 | // This is said to be an interview question about game. 2 | // This solution is by dynamic programming. 3 | // Description: 4 | // If there're 50 stones at the beginning, you and your component take turns to take away 1, 2, 4 or 8 stones. 5 | // Whoever takes away the last stone loses the game. 6 | // Does this game has a winning strategy for any side? 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | void game(const int n, const vector &move, vector &dp) 13 | { 14 | int i; 15 | // dp[i] means the game result when the total number of stones is i. 16 | // 1 for offensive win, -1 for defensive win, 0 for uncertain(fair play). 17 | dp.resize(n + 1, 0); 18 | 19 | int n_move = (int)move.size(); 20 | int n_win; 21 | dp[move[0]] = -1; 22 | 23 | int j; 24 | for (i = move[0] + 1; i <= n; ++i) { 25 | n_win = 0; 26 | for (j = 0; j < n_move; ++j) { 27 | if (i - move[j] <= 0) { 28 | ++n_win; 29 | continue; 30 | } 31 | if (dp[i - move[j]] == -1) { 32 | // one of the parent node in the game tree is lose, 33 | // then you win. 34 | dp[i] = 1; 35 | break; 36 | } else if (dp[i - move[j]] == 1) { 37 | ++n_win; 38 | } 39 | } 40 | if (j == n_move && n_win == n_move) { 41 | // all parent nodes in the game tree are wins, then you lose 42 | dp[i] = -1; 43 | } 44 | } 45 | } 46 | 47 | int main() 48 | { 49 | vector dp; 50 | vector move; 51 | int n; 52 | int i; 53 | int tmp; 54 | 55 | while (cin >> n && n > 0) { 56 | while (cin >> tmp && tmp > 0) { 57 | move.push_back(tmp); 58 | } 59 | game(n, move, dp); 60 | sort(move.begin(), move.end()); 61 | for (i = 1; i <= n; ++i) { 62 | cout << i << ':'; 63 | switch(dp[i]) { 64 | case -1: 65 | cout << "Defensive win." << endl; 66 | break; 67 | case 0: 68 | cout << "Fair play." << endl; 69 | break; 70 | case 1: 71 | cout << "Offensive win." << endl; 72 | break; 73 | } 74 | } 75 | 76 | dp.clear(); 77 | move.clear(); 78 | } 79 | 80 | return 0; 81 | } -------------------------------------------------------------------------------- /chapter4-binary-tree.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for binary tree. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct TreeNode { 7 | int val; 8 | TreeNode *left; 9 | TreeNode *right; 10 | TreeNode(int _val): val(_val), left(nullptr), right(nullptr) {}; 11 | }; 12 | 13 | // One of the (de)serialization method I wrote. 14 | // Here is a serialization sample for this piece of code: {3,1,#,#,10,6,#,#,11,#,14,#,#} 15 | // 3 16 | // / \ 17 | // 1 10 18 | // / \ 19 | // 6 11 20 | // \ 21 | // 14 22 | class BinaryTreeSerializer { 23 | public: 24 | string serialize(TreeNode *root) { 25 | string res = "{"; 26 | 27 | // preorder traversal 28 | serializeTraversal(root, res); 29 | res[res.length() - 1] = '}'; 30 | 31 | return res; 32 | }; 33 | 34 | TreeNode *deserialize(string s) { 35 | vector data; 36 | int i, j, len; 37 | 38 | len = (int)s.length(); 39 | i = 1; 40 | while (true) { 41 | j = i + 1; 42 | while (s[j] != ',' && s[j] != '}') { 43 | ++j; 44 | } 45 | data.push_back(s.substr(i, j - i)); 46 | i = j + 1; 47 | if (i >= len) { 48 | break; 49 | } 50 | } 51 | 52 | int iter = 0; 53 | TreeNode *root = nullptr; 54 | 55 | // preorder traversal 56 | deserializeTraversal(data, root, iter); 57 | 58 | return root; 59 | }; 60 | private: 61 | static char ss[10]; 62 | 63 | void serializeTraversal(TreeNode *root, string &res) { 64 | if (root == nullptr) { 65 | res += "#,"; 66 | } else { 67 | sprintf(ss, "%d", root->val); 68 | res += string(ss); 69 | res.push_back(','); 70 | serializeTraversal(root->left, res); 71 | serializeTraversal(root->right, res); 72 | } 73 | }; 74 | 75 | void deserializeTraversal(vector &data, TreeNode *&root, int &iter) { 76 | ++iter; 77 | if (data[iter - 1] == "#") { 78 | root = nullptr; 79 | } else { 80 | int val; 81 | 82 | sscanf(data[iter - 1].c_str(), "%d", &val); 83 | root = new TreeNode(val); 84 | deserializeTraversal(data, root->left, iter); 85 | deserializeTraversal(data, root->right, iter); 86 | } 87 | }; 88 | }; 89 | 90 | int main() 91 | { 92 | return 0; 93 | } -------------------------------------------------------------------------------- /chapter9-prims-algorithm.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for Prim's Algorithm, for minimum spanning tree problem. 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int INFINITY = 1000000000; 9 | 10 | struct Edge { 11 | int x; 12 | int y; 13 | int cost; 14 | Edge(int _x = 0, int _y = 0, int _cost = 0): x(_x), y(_y), cost(_cost) {}; 15 | }; 16 | 17 | struct GreaterFunctor { 18 | bool operator () (const Edge &e1, const Edge &e2) { 19 | return e1.cost > e2.cost; 20 | } 21 | }; 22 | 23 | int primsAlgorithm(const vector > &graph) 24 | { 25 | // Prim's Algorithm for weighted undirected graph. 26 | 27 | int n; 28 | n = (int)graph.size(); 29 | if (n < 2) { 30 | return 0; 31 | } 32 | 33 | int i; 34 | // Minimal heap, the top is smallest. 35 | priority_queue, GreaterFunctor> pq; 36 | vector visited; 37 | int visited_count; 38 | int min_cost; 39 | 40 | visited.resize(n, false); 41 | 42 | // Start constructing the tree from 0th vertex. 43 | min_cost = 0; 44 | visited[0] = true; 45 | for (i = 1; i < n; ++i) { 46 | if (graph[0][i] == INFINITY) { 47 | continue; 48 | } 49 | pq.push(Edge(0, i, graph[0][i])); 50 | } 51 | visited_count = n - 1; 52 | 53 | Edge e; 54 | while (!pq.empty()) { 55 | e = pq.top(); 56 | pq.pop(); 57 | if (visited[e.y]) { 58 | continue; 59 | } 60 | min_cost += e.cost; 61 | visited[e.y] = true; 62 | --visited_count; 63 | if (visited_count == 0) { 64 | break; 65 | } 66 | 67 | for (i = 0; i < n; ++i) { 68 | if (i == e.y || graph[e.y][i] == INFINITY || visited[i]) { 69 | continue; 70 | } 71 | pq.push(Edge(e.y, i, graph[e.y][i])); 72 | } 73 | } 74 | 75 | while (!pq.empty()) { 76 | pq.pop(); 77 | } 78 | 79 | return min_cost; 80 | } 81 | 82 | int main() 83 | { 84 | vector > graph; 85 | int n; 86 | int nk; 87 | int i, j; 88 | int tmp, tmp_dist; 89 | int min_cost; 90 | 91 | while (cin >> n && n > 0) { 92 | graph.resize(n); 93 | for (i = 0; i < n; ++i) { 94 | graph[i].resize(n, INFINITY); 95 | } 96 | 97 | for (i = 0; i < n; ++i) { 98 | cin >> nk; 99 | for (j = 0; j < nk; ++j) { 100 | cin >> tmp >> tmp_dist; 101 | graph[i][tmp] = graph[tmp][i] = tmp_dist; 102 | } 103 | } 104 | 105 | min_cost = primsAlgorithm(graph); 106 | 107 | cout << "The weighted sum of minimum spanning tree is " << min_cost << "." << endl; 108 | 109 | for (i = 0; i < n; ++i) { 110 | graph[i].clear(); 111 | } 112 | graph.clear(); 113 | } 114 | 115 | return 0; 116 | } -------------------------------------------------------------------------------- /chapter9-cut-vertices.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for cut vertex detection on undirected graph. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void findCutVertex(const vector > &graph, int idx, const int n, 8 | int &counter, vector &num, vector &low, vector &parent, 9 | vector &result) 10 | { 11 | int i; 12 | 13 | low[idx] = num[idx] = counter++; 14 | for (i = 0; i < n; ++i) { 15 | if (!graph[idx][i]) { 16 | continue; 17 | } 18 | 19 | if (num[i] < 0) { 20 | // Unvisited vertex 21 | parent[i] = idx; 22 | findCutVertex(graph, i, n, counter, num, low, parent, result); 23 | if (low[i] >= num[idx]) { 24 | result[idx] = true; 25 | } 26 | low[idx] = min(low[idx], low[i]); 27 | } else if (parent[idx] != i) { 28 | // Visited vertex 29 | low[idx] = min(low[idx], num[i]); 30 | } 31 | } 32 | } 33 | 34 | void cutVertexDetection(const vector > &graph, 35 | vector &is_cut_vertex) 36 | { 37 | // Cut vertex detection for undirected graph. 38 | int n; 39 | 40 | n = (int)graph.size(); 41 | is_cut_vertex.resize(n, false); 42 | 43 | if (n == 1) { 44 | is_cut_vertex[0] = true; 45 | return; 46 | } 47 | 48 | vector parent; 49 | vector num; 50 | vector low; 51 | int counter; 52 | 53 | parent.resize(n, -1); 54 | num.resize(n, -1); 55 | low.resize(n, -1); 56 | counter = 0; 57 | findCutVertex(graph, 0, n, counter, num, low, parent, is_cut_vertex); 58 | 59 | // The root node must be checked separately. 60 | counter = 0; 61 | for (int i = 1; i < n; ++i) { 62 | if (parent[i] == 0) { 63 | ++counter; 64 | } 65 | } 66 | is_cut_vertex[0] = (counter > 1); 67 | 68 | parent.clear(); 69 | num.clear(); 70 | low.clear(); 71 | } 72 | 73 | int main() 74 | { 75 | vector > graph; 76 | vector is_cut_vertex; 77 | int n; 78 | int nk; 79 | int i, j; 80 | int tmp; 81 | 82 | while (cin >> n && n > 0) { 83 | graph.resize(n); 84 | for (i = 0; i < n; ++i) { 85 | graph[i].resize(n, false); 86 | } 87 | 88 | for (i = 0; i < n; ++i) { 89 | cin >> nk; 90 | for (j = 0; j < nk; ++j) { 91 | cin >> tmp; 92 | graph[i][tmp] = graph[tmp][i] = true; 93 | } 94 | } 95 | 96 | cutVertexDetection(graph, is_cut_vertex); 97 | cout << "The following vertices are cut vertices:" << endl; 98 | cout << '{'; 99 | for (i = 0; i < n; ++i) { 100 | if (is_cut_vertex[i]) { 101 | cout << i << ' '; 102 | } 103 | } 104 | cout << '}' << endl; 105 | 106 | for (i = 0; i < n; ++i) { 107 | graph[i].clear(); 108 | } 109 | graph.clear(); 110 | is_cut_vertex.clear(); 111 | } 112 | 113 | return 0; 114 | } -------------------------------------------------------------------------------- /chapter9-kruskals-algorithm.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for Prim's Algorithm, for minimum spanning tree problem. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | const int INFINITY = 1000000000; 8 | 9 | struct Edge { 10 | int x; 11 | int y; 12 | int cost; 13 | Edge(int _x = 0, int _y = 0, int _cost = 0): x(_x), y(_y), cost(_cost) {}; 14 | }; 15 | 16 | bool comparator(const Edge &e1, const Edge &e2) { 17 | return e1.cost < e2.cost; 18 | } 19 | 20 | int findRoot(vector &dj, int x) 21 | { 22 | int r, k; 23 | 24 | r = x; 25 | while (r != dj[r]) { 26 | r = dj[r]; 27 | } 28 | 29 | // Path compression speeds up the disjoint set. 30 | k = x; 31 | while (x != r) { 32 | x = dj[x]; 33 | dj[k] = r; 34 | k = x; 35 | } 36 | 37 | return r; 38 | } 39 | 40 | int kruskalsAlgorithm(const vector > &graph) 41 | { 42 | // Kruskal's Algorithm for weighted undirected graph. 43 | int n; 44 | n = (int)graph.size(); 45 | if (n < 2) { 46 | return 0; 47 | } 48 | 49 | // Disjoint set 50 | vector dj; 51 | vector edges; 52 | int rx, ry; 53 | int i, j; 54 | 55 | for (i = 0; i < n; ++i) { 56 | for (j = i + 1; j < n; ++j) { 57 | if (graph[i][j] == INFINITY) { 58 | continue; 59 | } 60 | edges.push_back(Edge(i, j, graph[i][j])); 61 | } 62 | } 63 | sort(edges.begin(), edges.end(), comparator); 64 | 65 | dj.resize(n); 66 | for (i = 0; i < n; ++i) { 67 | dj[i] = i; 68 | } 69 | 70 | int edge_count = n - 1; 71 | int min_cost = 0; 72 | int ec = (int)edges.size(); 73 | for (i = 0; i < ec; ++i) { 74 | rx = findRoot(dj, edges[i].x); 75 | ry = findRoot(dj, edges[i].y); 76 | if (rx == ry) { 77 | continue; 78 | } 79 | dj[rx] = ry; 80 | findRoot(dj, edges[i].x); 81 | 82 | min_cost += edges[i].cost; 83 | --edge_count; 84 | if (edge_count == 0) { 85 | break; 86 | } 87 | } 88 | edges.clear(); 89 | 90 | return min_cost; 91 | } 92 | 93 | int main() 94 | { 95 | vector > graph; 96 | int n; 97 | int nk; 98 | int i, j; 99 | int tmp, tmp_dist; 100 | int min_cost; 101 | 102 | while (cin >> n && n > 0) { 103 | graph.resize(n); 104 | for (i = 0; i < n; ++i) { 105 | graph[i].resize(n, INFINITY); 106 | } 107 | 108 | for (i = 0; i < n; ++i) { 109 | cin >> nk; 110 | for (j = 0; j < nk; ++j) { 111 | cin >> tmp >> tmp_dist; 112 | graph[i][tmp] = graph[tmp][i] = tmp_dist; 113 | } 114 | } 115 | 116 | min_cost = kruskalsAlgorithm(graph); 117 | 118 | cout << "The weighted sum of minimum spanning tree is " << min_cost << "." << endl; 119 | 120 | for (i = 0; i < n; ++i) { 121 | graph[i].clear(); 122 | } 123 | graph.clear(); 124 | } 125 | 126 | return 0; 127 | } -------------------------------------------------------------------------------- /chapter3-singly-linked-list.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for singly linked list. 2 | struct ListNode { 3 | int val; 4 | ListNode *next; 5 | ListNode(int _val = 0): val(_val), next(nullptr) {}; 6 | }; 7 | 8 | class SinglyLinkedList { 9 | public: 10 | SinglyLinkedList() { 11 | m_size = 0; 12 | m_head = nullptr; 13 | m_tail = nullptr; 14 | } 15 | 16 | void insertFront(int val) { 17 | if (m_size == 0) { 18 | m_head = m_tail = new ListNode(val); 19 | } else { 20 | ListNode *ptr = new ListNode(val); 21 | ptr->next = m_head; 22 | m_head = ptr; 23 | } 24 | ++m_size; 25 | } 26 | 27 | void insertBack(int val) { 28 | if (m_size == 0) { 29 | m_head = m_tail = new ListNode(val); 30 | } else { 31 | m_tail->next = new ListNode(val); 32 | m_tail = m_tail->next; 33 | } 34 | ++m_size; 35 | } 36 | 37 | void insertNode(int pos, int val) { 38 | int i; 39 | 40 | if (i <= 0) { 41 | insertFront(val); 42 | } else if (i >= m_size) { 43 | insertBack(val); 44 | } else { 45 | ListNode *ptr1, *ptr2; 46 | 47 | ptr1 = m_head; 48 | for (i = 0; i < pos - 1; ++i) { 49 | ptr1 = ptr1->next; 50 | } 51 | ptr2 = new ListNode(val); 52 | ptr2->next = ptr1->next; 53 | ptr1->next = ptr2; 54 | ++m_size; 55 | } 56 | } 57 | 58 | void deleteNode(int pos) { 59 | if (pos < 0 || pos > m_size - 1) { 60 | return; 61 | } 62 | 63 | ListNode *ptr1, *ptr2; 64 | if (pos == 0) { 65 | ptr1 = m_head; 66 | if (m_size == 1) { 67 | m_head = m_tail = nullptr; 68 | } else { 69 | m_head = m_head->next; 70 | } 71 | delete ptr1; 72 | } else { 73 | ptr1 = m_head; 74 | for (int i = 0; i < pos - 1; ++i) { 75 | ptr1 = ptr1->next; 76 | } 77 | ptr2 = ptr1->next; 78 | ptr1->next = ptr2->next; 79 | if (ptr2->next == nullptr) { 80 | m_tail = ptr1; 81 | } 82 | delete ptr2; 83 | } 84 | --m_size; 85 | } 86 | 87 | void updateNode(int pos, int val) { 88 | if (pos < 0 || pos > m_size - 1) { 89 | return; 90 | } 91 | 92 | ListNode *ptr = m_head; 93 | for (int i = 0; i < pos; ++i) { 94 | ptr = ptr->next; 95 | } 96 | ptr->val = val; 97 | } 98 | 99 | ListNode *findNode(int val) { 100 | ListNode *ptr = m_head; 101 | while (ptr != nullptr) { 102 | if (ptr->val == val) { 103 | return ptr; 104 | } 105 | ptr = ptr->next; 106 | } 107 | 108 | return nullptr; 109 | } 110 | 111 | ~SinglyLinkedList() { 112 | ListNode *ptr = m_head; 113 | while (m_head != nullptr) { 114 | m_head = m_head->next; 115 | delete ptr; 116 | ptr = m_head; 117 | } 118 | m_head = m_tail = nullptr; 119 | } 120 | private: 121 | int m_size; 122 | ListNode *m_head; 123 | ListNode *m_tail; 124 | }; 125 | 126 | int main() 127 | { 128 | return 0; 129 | } -------------------------------------------------------------------------------- /chapter10-turnpike-reconstrution.cpp: -------------------------------------------------------------------------------- 1 | // Turnpike reconstruction problem. 2 | // Description: 3 | // Given n * (n - 1) / 2 distances, find out if you can determine the 4 | // relative coordinates of n points. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | int myabs(int x) 13 | { 14 | return x > 0 ? x : -x; 15 | } 16 | 17 | bool turnpikeReconstruction(int idx, vector &x, map &dist_set, 18 | const int far) 19 | { 20 | if (idx == 0) { 21 | return true; 22 | } 23 | 24 | int cur_n; 25 | int cur_far; 26 | int i; 27 | map::iterator it; 28 | 29 | cur_n = (int)x.size(); 30 | cur_far = dist_set.rbegin()->first; 31 | for (i = 0; i < cur_n; ++i) { 32 | it = dist_set.find(myabs(cur_far - x[i])); 33 | if (it == dist_set.end() || it->second == 0) { 34 | break; 35 | } 36 | --it->second; 37 | if (it->second == 0) { 38 | dist_set.erase(it); 39 | } 40 | } 41 | if (i == cur_n) { 42 | x.push_back(cur_far); 43 | if (turnpikeReconstruction(idx - 1, x, dist_set, far)) { 44 | return true; 45 | } 46 | x.pop_back(); 47 | } 48 | cur_n = i; 49 | for (i = 0; i < cur_n; ++i) { 50 | ++dist_set[myabs(cur_far - x[i])]; 51 | } 52 | 53 | cur_n = (int)x.size(); 54 | cur_far = dist_set.rbegin()->first; 55 | for (i = 0; i < cur_n; ++i) { 56 | it = dist_set.find(myabs(far - cur_far - x[i])); 57 | if (it == dist_set.end() || it->second == 0) { 58 | break; 59 | } 60 | --it->second; 61 | if (it->second == 0) { 62 | dist_set.erase(it); 63 | } 64 | } 65 | if (i == cur_n) { 66 | x.push_back(far - cur_far); 67 | if (turnpikeReconstruction(idx - 1, x, dist_set, far)) { 68 | return true; 69 | } 70 | x.pop_back(); 71 | } 72 | cur_n = i; 73 | for (i = 0; i < cur_n; ++i) { 74 | ++dist_set[myabs(far - cur_far - x[i])]; 75 | } 76 | 77 | return false; 78 | } 79 | 80 | int main() 81 | { 82 | int i; 83 | int n, n2; 84 | vector x; 85 | int dist; 86 | map dist_set; 87 | int far; 88 | 89 | while (cin >> n2 && n2 > 0) { 90 | for (i = 0; i < n2; ++i) { 91 | cin >> dist; 92 | ++dist_set[dist]; 93 | } 94 | n = (int)sqrt(n2 * 2.0) + 1; 95 | far = dist_set.rbegin()->first; 96 | --dist_set[far]; 97 | if (dist_set.rbegin()->second == 0) { 98 | dist_set.erase(far); 99 | } 100 | 101 | x.push_back(0); 102 | x.push_back(far); 103 | if (!turnpikeReconstruction(n - 2, x, dist_set, far)) { 104 | cout << "No solution." << endl; 105 | } else { 106 | sort(x.begin(), x.end()); 107 | for (i = 0; i < n; ++i) { 108 | cout << x[i] << ' '; 109 | } 110 | cout << endl; 111 | } 112 | 113 | x.clear(); 114 | dist_set.clear(); 115 | } 116 | 117 | return 0; 118 | } -------------------------------------------------------------------------------- /chapter10-closest-pair-of-points.cpp: -------------------------------------------------------------------------------- 1 | // Divide-and-conquer solution for Closest Pair of Points problem. 2 | // This piece of code is also accepted on Zhejiang University Online Judge 3 | // Problem ID 2107. 4 | // http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1107 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | struct Point { 12 | double x; 13 | double y; 14 | Point(double _x = 0.0, double _y = 0.0): x(_x), y(_y) {} 15 | }; 16 | 17 | bool comparatorX(const Point &a, const Point &b) 18 | { 19 | if (a.x == b.x) { 20 | return a.y < b.y; 21 | } else { 22 | return a.x < b.x; 23 | } 24 | } 25 | 26 | bool comparatorY(const Point &a, const Point &b) 27 | { 28 | if (a.y == b.y) { 29 | return a.x < b.x; 30 | } else { 31 | return a.y < b.y; 32 | } 33 | } 34 | 35 | double dist(const Point &a, const Point &b) 36 | { 37 | return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 38 | } 39 | 40 | double closestPairOfPointsRecursive(const vector &points, int left, 41 | int right) 42 | { 43 | if (right - left + 1 == 2) { 44 | return dist(points[left], points[left + 1]); 45 | } else if (right - left + 1 == 3) { 46 | return min(dist(points[left], points[left + 1]), 47 | min(dist(points[left + 1], points[left + 2]), 48 | dist(points[left], points[left + 2]))); 49 | } 50 | 51 | int mid = left + (right - left) / 2; 52 | double delta = min(closestPairOfPointsRecursive(points, left, mid), 53 | closestPairOfPointsRecursive(points, mid + 1, right)); 54 | vector p; 55 | 56 | int i, j; 57 | i = mid; 58 | while (i >= left && points[i].x > points[mid].x - delta) { 59 | p.push_back(points[i]); 60 | --i; 61 | } 62 | 63 | i = mid + 1; 64 | while (i <= right && points[i].x < points[mid].x + delta) { 65 | p.push_back(points[i]); 66 | ++i; 67 | } 68 | 69 | int np; 70 | double result = delta; 71 | 72 | sort(p.begin(), p.end(), comparatorY); 73 | np = (int)p.size(); 74 | for (i = 0; i < np; ++i) { 75 | for (j = i + 1; j < np; ++j) { 76 | if (p[j].y - p[i].y > result) { 77 | break; 78 | } 79 | result = min(result, dist(p[i], p[j])); 80 | } 81 | } 82 | p.clear(); 83 | 84 | return result; 85 | } 86 | 87 | double closestPairOfPoints(vector &points) 88 | { 89 | int n = points.size(); 90 | sort(points.begin(), points.end(), comparatorX); 91 | return closestPairOfPointsRecursive(points, 0, n - 1); 92 | } 93 | 94 | int main() 95 | { 96 | vector points; 97 | int n; 98 | int i; 99 | 100 | while (scanf("%d", &n) == 1 && n > 0) { 101 | points.resize(n); 102 | for (i = 0; i < n; ++i) { 103 | scanf("%lf%lf", &points[i].x, &points[i].y); 104 | } 105 | // printf("%.2f\n", closestPairOfPoints(points) / 2.0); 106 | printf("%.2f\n", closestPairOfPoints(points)); 107 | } 108 | 109 | return 0; 110 | } -------------------------------------------------------------------------------- /chapter10-huffman-encoding.cpp: -------------------------------------------------------------------------------- 1 | // A simple illustration for 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | // The character statistics type 10 | typedef unordered_map StatType; 11 | // The character encoding type 12 | typedef unordered_map EncodeType; 13 | 14 | struct TreeNode { 15 | char ch; 16 | int weight; 17 | TreeNode *left; 18 | TreeNode *right; 19 | 20 | TreeNode(char _ch, int _weight): ch(_ch), weight(_weight), 21 | left(nullptr), right(nullptr) {} 22 | }; 23 | 24 | struct GreaterFunctor { 25 | bool operator () (const TreeNode *x, const TreeNode *y) { 26 | return x->weight > y->weight; 27 | } 28 | }; 29 | 30 | void deleteTree(TreeNode *&root) 31 | { 32 | if (root == nullptr) { 33 | return; 34 | } else { 35 | deleteTree(root->left); 36 | deleteTree(root->right); 37 | delete root; 38 | root = nullptr; 39 | } 40 | } 41 | 42 | void calculateEncoding(const TreeNode *root, EncodeType &encoding, string &path) 43 | { 44 | if (root == nullptr) { 45 | return; 46 | } 47 | 48 | if (root->ch != '\0') { 49 | encoding[root->ch] = path; 50 | return; 51 | } 52 | 53 | path.push_back('0'); 54 | calculateEncoding(root->left, encoding, path); 55 | path.pop_back(); 56 | 57 | path.push_back('1'); 58 | calculateEncoding(root->right, encoding, path); 59 | path.pop_back(); 60 | } 61 | 62 | void huffmanEncoding(const StatType &statistics, EncodeType &encoding) 63 | { 64 | priority_queue, GreaterFunctor> pq; 65 | 66 | int n; 67 | 68 | n = 0; 69 | for (StatType::const_iterator sta_it = statistics.begin(); 70 | sta_it != statistics.end(); ++sta_it) { 71 | pq.push(new TreeNode(sta_it->first, sta_it->second)); 72 | ++n; 73 | } 74 | 75 | TreeNode *p1, *p2, *p3; 76 | int i; 77 | for (i = 0; i < n - 1; ++i) { 78 | p1 = pq.top(); 79 | pq.pop(); 80 | p2 = pq.top(); 81 | pq.pop(); 82 | 83 | p3 = new TreeNode('\0', p1->weight + p2->weight); 84 | p3->left = p1; 85 | p3->right = p2; 86 | pq.push(p3); 87 | } 88 | 89 | TreeNode *root = pq.top(); 90 | pq.pop(); 91 | 92 | string code = ""; 93 | calculateEncoding(root, encoding, code); 94 | deleteTree(root); 95 | } 96 | 97 | int main() 98 | { 99 | int i, n; 100 | string s; 101 | int weight; 102 | StatType statistics; 103 | EncodeType encoding; 104 | 105 | while (cin >> n && n > 0) { 106 | for (i = 0; i < n; ++i) { 107 | cin >> s >> weight; 108 | statistics[s[0]] = weight; 109 | } 110 | huffmanEncoding(statistics, encoding); 111 | 112 | for (EncodeType::const_iterator enc_it = encoding.begin(); 113 | enc_it != encoding.end(); ++enc_it) { 114 | cout << enc_it->first << ':' << enc_it->second << endl; 115 | } 116 | cout << endl; 117 | 118 | statistics.clear(); 119 | encoding.clear(); 120 | } 121 | 122 | return 0; 123 | } -------------------------------------------------------------------------------- /chapter3-doubly-linked-list.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for doubly linked list. 2 | struct ListNode { 3 | int val; 4 | ListNode *prev; 5 | ListNode *next; 6 | ListNode(int _val = 0): val(_val), next(nullptr), prev(nullptr) {}; 7 | }; 8 | 9 | class DoublyLinkedList { 10 | public: 11 | DoublyLinkedList() { 12 | m_size = 0; 13 | m_head = nullptr; 14 | m_tail = nullptr; 15 | } 16 | 17 | void insertFront(int val) { 18 | if (m_size == 0) { 19 | m_head = m_tail = new ListNode(val); 20 | } else { 21 | ListNode *ptr = new ListNode(val); 22 | ptr->next = m_head; 23 | m_head->prev = ptr; 24 | m_head = ptr; 25 | } 26 | ++m_size; 27 | } 28 | 29 | void insertBack(int val) { 30 | if (m_size == 0) { 31 | m_head = m_tail = new ListNode(val); 32 | } else { 33 | m_tail->next = new ListNode(val); 34 | m_tail->next->prev = m_tail; 35 | m_tail = m_tail->next; 36 | } 37 | ++m_size; 38 | } 39 | 40 | void insertNode(int pos, int val) { 41 | int i; 42 | 43 | if (i <= 0) { 44 | insertFront(val); 45 | } else if (i >= m_size) { 46 | insertBack(val); 47 | } else { 48 | ListNode *ptr1, *ptr2; 49 | 50 | ptr1 = m_head; 51 | for (i = 0; i < pos - 1; ++i) { 52 | ptr1 = ptr1->next; 53 | } 54 | ptr2 = new ListNode(val); 55 | ptr2->next = ptr1->next; 56 | ptr1->next->prev = ptr2; 57 | ptr1->next = ptr2; 58 | ptr2->prev = ptr1; 59 | ++m_size; 60 | } 61 | } 62 | 63 | void deleteNode(int pos) { 64 | if (pos < 0 || pos > m_size - 1) { 65 | return; 66 | } 67 | 68 | ListNode *ptr1, *ptr2; 69 | if (pos == 0) { 70 | ptr1 = m_head; 71 | if (m_size == 1) { 72 | m_head = m_tail = nullptr; 73 | } else { 74 | m_head = m_head->next; 75 | m_head->prev = nullptr; 76 | } 77 | delete ptr1; 78 | } else { 79 | ptr1 = m_head; 80 | for (int i = 0; i < pos - 1; ++i) { 81 | ptr1 = ptr1->next; 82 | } 83 | ptr2 = ptr1->next; 84 | ptr1->next = ptr2->next; 85 | if (ptr2->next == nullptr) { 86 | m_tail = ptr1; 87 | } else { 88 | ptr2->next->prev = ptr1; 89 | } 90 | delete ptr2; 91 | } 92 | --m_size; 93 | } 94 | 95 | void updateNode(int pos, int val) { 96 | if (pos < 0 || pos > m_size - 1) { 97 | return; 98 | } 99 | 100 | ListNode *ptr = m_head; 101 | for (int i = 0; i < pos; ++i) { 102 | ptr = ptr->next; 103 | } 104 | ptr->val = val; 105 | } 106 | 107 | ListNode *findNode(int val) { 108 | ListNode *ptr = m_head; 109 | while (ptr != nullptr) { 110 | if (ptr->val == val) { 111 | return ptr; 112 | } 113 | ptr = ptr->next; 114 | } 115 | 116 | return nullptr; 117 | } 118 | 119 | ~DoublyLinkedList() { 120 | ListNode *ptr = m_head; 121 | while (m_head != nullptr) { 122 | m_head = m_head->next; 123 | delete ptr; 124 | ptr = m_head; 125 | } 126 | m_head = m_tail = nullptr; 127 | } 128 | private: 129 | int m_size; 130 | ListNode *m_head; 131 | ListNode *m_tail; 132 | }; 133 | 134 | int main() 135 | { 136 | return 0; 137 | } -------------------------------------------------------------------------------- /chapter7-hash-map.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for hash map. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class HashMap { 8 | public: 9 | HashMap() { 10 | _buckets.resize(_bucket_num); 11 | int i; 12 | 13 | for (i = 0; i < _bucket_num; ++i) { 14 | _buckets[i] = nullptr; 15 | } 16 | }; 17 | 18 | bool contains(int key) { 19 | key = (key > 0) ? key : -key; 20 | key = key % _bucket_num; 21 | LinkedList *ptr = _buckets[key]; 22 | 23 | while (ptr != nullptr) { 24 | if (ptr->key == key) { 25 | return true; 26 | } 27 | } 28 | 29 | return false; 30 | }; 31 | 32 | int& operator [] (int key) { 33 | key = (key > 0) ? key : -key; 34 | key = key % _bucket_num; 35 | LinkedList *ptr = _buckets[key]; 36 | 37 | if (ptr == nullptr) { 38 | _buckets[key] = new LinkedList(key); 39 | return _buckets[key]->val; 40 | } 41 | 42 | LinkedList *ptr2 = ptr->next; 43 | if (ptr->key == key) { 44 | return ptr->val; 45 | } 46 | 47 | while (ptr2 != nullptr) { 48 | if (ptr2->key == key) { 49 | return ptr2->val; 50 | } else { 51 | ptr = ptr->next; 52 | ptr2 = ptr2->next; 53 | } 54 | } 55 | ptr->next = new LinkedList(key); 56 | ptr = ptr->next; 57 | return ptr->val; 58 | } 59 | 60 | void erase(int key) { 61 | key = (key > 0) ? key : -key; 62 | key = key % _bucket_num; 63 | LinkedList *ptr = _buckets[key]; 64 | 65 | if (ptr == nullptr) { 66 | return; 67 | } else if (ptr->next == nullptr) { 68 | if (ptr->key == key) { 69 | delete _buckets[key]; 70 | _buckets[key] = nullptr; 71 | } 72 | return; 73 | } 74 | 75 | if (ptr->key == key) { 76 | _buckets[key] = ptr->next; 77 | delete ptr; 78 | return; 79 | } 80 | 81 | LinkedList *ptr2; 82 | ptr2 = ptr->next; 83 | 84 | while (ptr2 != nullptr) { 85 | if (ptr2->key == key) { 86 | ptr->next = ptr2->next; 87 | delete ptr2; 88 | return; 89 | } else { 90 | ptr = ptr->next; 91 | ptr2 = ptr2->next; 92 | } 93 | } 94 | } 95 | 96 | ~HashMap() { 97 | int i; 98 | LinkedList *ptr; 99 | 100 | for (i = 0; i < _bucket_num; ++i) { 101 | ptr = _buckets[i]; 102 | while (ptr != nullptr) { 103 | ptr = ptr->next; 104 | delete _buckets[i]; 105 | _buckets[i] = ptr; 106 | } 107 | } 108 | _buckets.clear(); 109 | } 110 | private: 111 | struct LinkedList { 112 | int key; 113 | int val; 114 | LinkedList *next; 115 | LinkedList(int _key = 0, int _val = 0): key(_key), val(_val), next(nullptr) {}; 116 | }; 117 | 118 | static const int _bucket_num = 10000; 119 | vector _buckets; 120 | }; 121 | 122 | int main() 123 | { 124 | HashMap hm; 125 | string cmd; 126 | int op1, op2; 127 | 128 | while (cin >> cmd) { 129 | if (cmd == "set") { 130 | cin >> op1 >> op2; 131 | hm[op1] = op2; 132 | } else if (cmd == "get") { 133 | cin >> op1; 134 | cout << hm[op1] << endl; 135 | } else if (cmd == "find") { 136 | cin >> op1; 137 | cout << (hm.contains(op1) ? "true" : "false") << endl; 138 | } 139 | } 140 | 141 | return 0; 142 | } -------------------------------------------------------------------------------- /chapter5-priority-queue.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for priority queue using binary heap. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | template 8 | class PriorityQueue { 9 | public: 10 | PriorityQueue() { 11 | m_data.push_back(0); 12 | } 13 | 14 | PriorityQueue(const vector &data) { 15 | m_data.push_back(0); 16 | for (size_t i = 0; i < data.size(); ++i) { 17 | m_data.push_back(data[i]); 18 | } 19 | _makeHeap(); 20 | } 21 | 22 | bool empty() { 23 | return m_data.size() == 1; 24 | } 25 | 26 | size_t size() { 27 | return m_data.size() - 1; 28 | } 29 | 30 | T top() { 31 | return m_data[1]; 32 | } 33 | 34 | void push(const T &val) { 35 | m_data.push_back(val); 36 | 37 | int n = size(); 38 | int i = n; 39 | 40 | while (i > 1) { 41 | if (m_data[i / 2] < m_data[i]) { 42 | _swap(m_data[i / 2], m_data[i]); 43 | i /= 2; 44 | } else { 45 | break; 46 | } 47 | } 48 | } 49 | 50 | void pop() { 51 | int n = size(); 52 | m_data[1] = m_data[n]; 53 | m_data.pop_back(); 54 | --n; 55 | 56 | int i = 1; 57 | T max_val; 58 | while (i * 2 <= n) { 59 | max_val = i * 2 == n ? m_data[i * 2] : _max(m_data[i * 2], m_data[i * 2 + 1]); 60 | if (m_data[i] < max_val) { 61 | if (max_val == m_data[i * 2] || i * 2 == n) { 62 | _swap(m_data[i], m_data[i * 2]); 63 | i = i * 2; 64 | } else { 65 | _swap(m_data[i], m_data[i * 2 + 1]); 66 | i = i * 2 + 1; 67 | } 68 | } else { 69 | break; 70 | } 71 | } 72 | } 73 | 74 | void clear() { 75 | m_data.resize(1); 76 | } 77 | 78 | ~PriorityQueue() { 79 | m_data.clear(); 80 | } 81 | private: 82 | vector m_data; 83 | 84 | T _max(const T &x, const T &y) { 85 | return x > y ? x : y; 86 | } 87 | 88 | void _swap(T &x, T &y) { 89 | T tmp; 90 | 91 | tmp = x; 92 | x = y; 93 | y = tmp; 94 | } 95 | 96 | void _makeHeap() { 97 | int n = size(); 98 | int i, j; 99 | T max_val; 100 | 101 | for (j = n / 2; j >= 1; --j) { 102 | i = j; 103 | while (i * 2 <= n) { 104 | max_val = i * 2 == n ? m_data[i * 2] : _max(m_data[i * 2], m_data[i * 2 + 1]); 105 | if (m_data[i] < max_val) { 106 | if (max_val == m_data[i * 2] || i * 2 == n) { 107 | _swap(m_data[i], m_data[i * 2]); 108 | i = i * 2; 109 | } else { 110 | _swap(m_data[i], m_data[i * 2 + 1]); 111 | i = i * 2 + 1; 112 | } 113 | } else { 114 | break; 115 | } 116 | } 117 | } 118 | 119 | n = size(); 120 | cout << '['; 121 | for (int i = 1; i <= n; ++i) { 122 | cout << m_data[i] << ' '; 123 | } 124 | cout << ']' << endl; 125 | } 126 | }; 127 | 128 | int main() 129 | { 130 | vector v; 131 | v.push_back(1); 132 | v.push_back(2); 133 | v.push_back(3); 134 | v.push_back(4); 135 | v.push_back(5); 136 | v.push_back(6); 137 | v.push_back(7); 138 | v.push_back(8); 139 | PriorityQueue pq(v); 140 | string s; 141 | int n; 142 | 143 | while (cin >> s) { 144 | if (s == "push") { 145 | cin >> n; 146 | pq.push(n); 147 | } else if (s == "pop") { 148 | pq.pop(); 149 | } else if (s == "top") { 150 | cout << pq.top() << endl; 151 | } else if (s == "end") { 152 | while (!pq.empty()) { 153 | pq.pop(); 154 | } 155 | break; 156 | } 157 | } 158 | 159 | return 0; 160 | } -------------------------------------------------------------------------------- /chapter9-maximum-flow.cpp: -------------------------------------------------------------------------------- 1 | // My first practice on maximum flow problem. This is an implementation using Edmonds-Karp Algorithm. 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int INFINITY = 1000000000; 9 | 10 | bool findAugmentPath(const vector > &rg, vector &path, 11 | const int start, const int end) 12 | { 13 | // Find an augment path with BFS. 14 | queue q; 15 | vector back_trace; 16 | int n; 17 | int i; 18 | 19 | n = rg.size(); 20 | back_trace.resize(n, -1); 21 | 22 | int tmp; 23 | 24 | back_trace[start] = start; 25 | q.push(start); 26 | while (!q.empty()) { 27 | if (back_trace[end] >= 0) { 28 | // An augment path is found. 29 | break; 30 | } 31 | tmp = q.front(); 32 | q.pop(); 33 | for (i = 0; i < n; ++i) { 34 | if (rg[tmp][i] == INFINITY) { 35 | continue; 36 | } 37 | if (i == tmp || back_trace[i] >= 0) { 38 | continue; 39 | } 40 | back_trace[i] = tmp; 41 | q.push(i); 42 | } 43 | } 44 | 45 | if (q.empty()) { 46 | return false; 47 | } 48 | 49 | path.clear(); 50 | tmp = end; 51 | while (tmp != start) { 52 | path.push_back(tmp); 53 | tmp = back_trace[tmp]; 54 | } 55 | path.push_back(tmp); 56 | reverse(path.begin(), path.end()); 57 | 58 | while (!q.empty()) { 59 | q.pop(); 60 | } 61 | back_trace.clear(); 62 | 63 | return true; 64 | } 65 | 66 | void addFlow(vector > &rg, const vector &path, const int flow) 67 | { 68 | int i; 69 | 70 | for (i = 0; i < (int)path.size() - 1; ++i) { 71 | if (rg[path[i]][path[i + 1]] == flow) { 72 | rg[path[i]][path[i + 1]] = INFINITY; 73 | } else { 74 | rg[path[i]][path[i + 1]] -= flow; 75 | } 76 | 77 | if (rg[path[i + 1]][path[i]] == INFINITY) { 78 | rg[path[i + 1]][path[i]] = flow; 79 | } else { 80 | rg[path[i + 1]][path[i]] += flow; 81 | } 82 | } 83 | } 84 | 85 | int maximumFlow(const vector > &graph, int start, int end) 86 | { 87 | // The residual graph 88 | vector > rg; 89 | vector path; 90 | int flow, maximum_flow; 91 | int i; 92 | 93 | if (graph.size() < 2 || start == end) { 94 | return 0; 95 | } 96 | 97 | rg = graph; 98 | maximum_flow = 0; 99 | while (findAugmentPath(rg, path, start, end)) { 100 | flow = rg[path[0]][path[1]]; 101 | for (i = 1; i < (int)path.size() - 1; ++i) { 102 | flow = min(flow, rg[path[i]][path[i + 1]]); 103 | } 104 | addFlow(rg, path, flow); 105 | maximum_flow += flow; 106 | } 107 | 108 | return maximum_flow; 109 | } 110 | 111 | int main() 112 | { 113 | vector > graph; 114 | vector dist; 115 | vector reachable; 116 | int n; 117 | int nk; 118 | int i, j; 119 | int tmp, tmp_dist; 120 | int maximum_flow; 121 | int start, end; 122 | 123 | while (cin >> n && n > 0) { 124 | graph.resize(n); 125 | for (i = 0; i < n; ++i) { 126 | graph[i].resize(n, INFINITY); 127 | } 128 | 129 | for (i = 0; i < n; ++i) { 130 | cin >> nk; 131 | for (j = 0; j < nk; ++j) { 132 | cin >> tmp >> tmp_dist; 133 | graph[i][tmp] = tmp_dist; 134 | } 135 | } 136 | 137 | cin >> start >> end; 138 | maximum_flow = maximumFlow(graph, start, end); 139 | 140 | cout << "Maximum flow is " << maximum_flow << "." << endl; 141 | 142 | for (i = 0; i < n; ++i) { 143 | graph[i].clear(); 144 | } 145 | graph.clear(); 146 | } 147 | 148 | return 0; 149 | } -------------------------------------------------------------------------------- /chapter10-minimax-game-strategy.cpp: -------------------------------------------------------------------------------- 1 | // My first attempt on Minimax , using tic-tac-toe game as a sample. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | int function_call_count; 7 | 8 | bool computerWin(const vector &board) 9 | { 10 | int i, j; 11 | 12 | for (i = 0; i < 3; ++i) { 13 | for (j = 0; j < 3; ++j) { 14 | if (board[i * 3 + j] != -1) { 15 | break; 16 | } 17 | } 18 | if (j == 3) { 19 | return true; 20 | } 21 | } 22 | 23 | for (i = 0; i < 3; ++i) { 24 | for (j = 0; j < 3; ++j) { 25 | if (board[j * 3 + i] != -1) { 26 | break; 27 | } 28 | } 29 | if (j == 3) { 30 | return true; 31 | } 32 | } 33 | 34 | if (board[0] == board[4] && board[4] == board[8] && board[8] == -1) { 35 | return true; 36 | } 37 | 38 | if (board[2] == board[4] && board[4] == board[6] && board[6] == -1) { 39 | return true; 40 | } 41 | 42 | return false; 43 | } 44 | 45 | bool humanWin(const vector &board) 46 | { 47 | int i, j; 48 | 49 | for (i = 0; i < 3; ++i) { 50 | for (j = 0; j < 3; ++j) { 51 | if (board[i * 3 + j] != 1) { 52 | break; 53 | } 54 | } 55 | if (j == 3) { 56 | return true; 57 | } 58 | } 59 | 60 | for (i = 0; i < 3; ++i) { 61 | for (j = 0; j < 3; ++j) { 62 | if (board[j * 3 + i] != 1) { 63 | break; 64 | } 65 | } 66 | if (j == 3) { 67 | return true; 68 | } 69 | } 70 | 71 | if (board[0] == board[4] && board[4] == board[8] && board[8] == 1) { 72 | return true; 73 | } 74 | 75 | if (board[2] == board[4] && board[4] == board[6] && board[6] == 1) { 76 | return true; 77 | } 78 | 79 | return false; 80 | } 81 | 82 | bool fullBoard(const vector &board) 83 | { 84 | for (int i = 0; i < 9; ++i) { 85 | if (board[i] == 0) { 86 | return false; 87 | } 88 | } 89 | 90 | return true; 91 | } 92 | 93 | void findComputerMove(vector &board, int &best_move, int &result) 94 | { 95 | void findHumanMove(vector &, int &, int &); 96 | int dc, i, response; 97 | 98 | ++function_call_count; 99 | best_move = -1; 100 | 101 | if (fullBoard(board)) { 102 | result = 0; 103 | return; 104 | } 105 | 106 | if (computerWin(board)) { 107 | result = -1; 108 | return; 109 | } 110 | 111 | for (i = 0; i < 9; ++i) { 112 | if (board[i] != 0) { 113 | continue; 114 | } 115 | board[i] = -1; 116 | findHumanMove(board, dc, response); 117 | board[i] = 0; 118 | 119 | if (best_move == -1 || response < result) { 120 | result = response; 121 | best_move = i; 122 | } 123 | } 124 | } 125 | 126 | void findHumanMove(vector &board, int &best_move, int &result) 127 | { 128 | void findComputerMove(vector &, int &, int &); 129 | int dc, i, response; 130 | 131 | ++function_call_count; 132 | best_move = -1; 133 | 134 | if (fullBoard(board)) { 135 | result = 0; 136 | return; 137 | } 138 | 139 | if (humanWin(board)) { 140 | result = 1; 141 | return; 142 | } 143 | 144 | for (i = 0; i < 9; ++i) { 145 | if (board[i] != 0) { 146 | continue; 147 | } 148 | board[i] = 1; 149 | findComputerMove(board, dc, response); 150 | board[i] = 0; 151 | 152 | if (best_move == -1 || response > result) { 153 | result = response; 154 | best_move = i; 155 | } 156 | } 157 | } 158 | 159 | void printBoard(const vector &board) 160 | { 161 | cout << " 1 2 3" << endl; 162 | int i, j; 163 | 164 | for (i = 0; i < 3; ++i) { 165 | cout << i + 1; 166 | for (j = 0; j < 3; ++j) { 167 | cout << ' '; 168 | switch(board[i * 3 + j]) { 169 | case -1: 170 | cout << 'X'; 171 | break; 172 | case 0: 173 | cout << '.'; 174 | break; 175 | case 1: 176 | cout << 'O'; 177 | break; 178 | } 179 | } 180 | cout << endl; 181 | } 182 | } 183 | 184 | int main() 185 | { 186 | vector board; 187 | int n; 188 | int result; 189 | 190 | board.resize(9, 0); 191 | while (cin >> n) { 192 | if (n < 0 || n >= 9 || board[n]) { 193 | cout << "Invalid move" << endl; 194 | continue; 195 | } 196 | 197 | board[n] = 1; 198 | printBoard(board); 199 | if (humanWin(board)) { 200 | cout << "You win." << endl; 201 | break; 202 | } 203 | 204 | if (fullBoard(board)) { 205 | cout << "Draw." << endl; 206 | break; 207 | } 208 | 209 | result = 1; 210 | function_call_count = 0; 211 | findComputerMove(board, n, result); 212 | cout << "Number of function calls: " << function_call_count << endl; 213 | board[n] = -1; 214 | printBoard(board); 215 | if (computerWin(board)) { 216 | cout << "Computer win." << endl; 217 | break; 218 | } 219 | 220 | if (fullBoard(board)) { 221 | cout << "Draw." << endl; 222 | break; 223 | } 224 | } 225 | 226 | return 0; 227 | } -------------------------------------------------------------------------------- /chapter7-hash-set.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for hash set. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | template 8 | struct HashFunctor { 9 | size_t operator () (const KeyType &key) { 10 | const char *ptr = (const char *)&key; 11 | size_t size = sizeof(key); 12 | size_t result; 13 | 14 | result = 0; 15 | for (size_t i = 0; i < size; ++i) { 16 | result = (result << 1) ^ *(ptr + i); 17 | } 18 | 19 | return result; 20 | } 21 | }; 22 | 23 | template<> 24 | struct HashFunctor { 25 | size_t operator() (const string &key) { 26 | size_t size = key.length(); 27 | size_t result; 28 | 29 | result = 0; 30 | for (size_t i = 0; i < size; ++i) { 31 | result = (result << 1) ^ key[i]; 32 | } 33 | 34 | return result; 35 | } 36 | }; 37 | 38 | template 39 | class HashSet { 40 | public: 41 | HashSet() { 42 | m_size = 0; 43 | m_capacity = MIN_BUCKET_NUM; 44 | m_data.resize(m_capacity); 45 | m_occupied.resize(m_capacity); 46 | 47 | for (size_t i = 0; i < m_capacity; ++i) { 48 | m_occupied[i] = false; 49 | } 50 | } 51 | 52 | void insert(const KeyType& key) { 53 | size_t h = _findKey(key); 54 | 55 | if (m_occupied[h]) { 56 | // value already inserted 57 | return; 58 | } 59 | 60 | m_data[h] = key; 61 | m_occupied[h] = true; 62 | ++m_size; 63 | 64 | if (load_factor() >= 0.5) { 65 | _rehash(m_capacity * 2 + 1); 66 | } 67 | } 68 | 69 | void remove(const KeyType& key) { 70 | size_t h = _findKey(key); 71 | 72 | if (!m_occupied[h]) { 73 | // value not found 74 | return; 75 | } 76 | 77 | m_occupied[h] = false; 78 | --m_size; 79 | 80 | if (m_capacity > MIN_BUCKET_NUM && load_factor() <= 0.05) { 81 | _rehash(m_capacity / 2); 82 | } 83 | } 84 | 85 | void update(const KeyType& old_key, const KeyType& new_key) { 86 | remove(old_key); 87 | insert(new_key); 88 | } 89 | 90 | bool find(const KeyType& key) { 91 | size_t h = _findKey(key); 92 | 93 | return m_occupied[h]; 94 | } 95 | 96 | size_t size() { 97 | return m_size; 98 | } 99 | 100 | void clear() { 101 | m_size = 0; 102 | for (size_t i = 0; i < m_capacity; ++i) { 103 | m_occupied[i] = false; 104 | } 105 | } 106 | 107 | double load_factor() { 108 | return (double)m_size / (double)m_capacity; 109 | } 110 | 111 | ~HashSet() { 112 | m_data.clear(); 113 | m_occupied.clear(); 114 | } 115 | private: 116 | static const size_t MIN_BUCKET_NUM = 5; 117 | size_t m_size; 118 | size_t m_capacity; 119 | vector m_data; 120 | vector m_occupied; 121 | HashFunctor m_hasher; 122 | 123 | size_t _findKey(const KeyType& key) { 124 | size_t hash_value = m_hasher(key); 125 | size_t h; 126 | size_t i; 127 | 128 | i = 0; 129 | while (i < m_capacity) { 130 | // only works for linear probing 131 | // if applied to quadratic probing, the number of buckets must be carefully chosen. 132 | h = (hash_value + _probeFunction(i)) % m_capacity; 133 | if (!m_occupied[h] || key == m_data[h]) { 134 | return h; 135 | } else { 136 | ++i; 137 | } 138 | } 139 | 140 | return m_capacity; 141 | } 142 | 143 | size_t _probeFunction(int i) { 144 | return i; 145 | } 146 | 147 | void _rehash(size_t new_capacity) { 148 | vector old_data; 149 | vector old_occupied; 150 | 151 | old_data = m_data; 152 | old_occupied = m_occupied; 153 | 154 | m_data.resize(new_capacity); 155 | m_occupied.resize(new_capacity); 156 | 157 | size_t i; 158 | size_t old_capacity; 159 | 160 | m_size = 0; 161 | old_capacity = m_capacity; 162 | m_capacity = new_capacity; 163 | for (i = 0; i < m_capacity; ++i) { 164 | m_occupied[i] = false; 165 | } 166 | 167 | for (i = 0; i < old_capacity; ++i) { 168 | if (old_occupied[i]) { 169 | insert(old_data[i]); 170 | } 171 | } 172 | 173 | old_data.clear(); 174 | old_occupied.clear(); 175 | } 176 | }; 177 | 178 | int main() 179 | { 180 | typedef long long KeyType; 181 | HashSet hash; 182 | string cmd; 183 | KeyType data; 184 | 185 | while (cin >> cmd) { 186 | if (cmd == "insert") { 187 | cin >> data; 188 | hash.insert(data); 189 | } else if (cmd == "remove") { 190 | cin >> data; 191 | hash.remove(data); 192 | } else if (cmd == "find") { 193 | cin >> data; 194 | cout << (hash.find(data) ? "true" : "false") << endl; 195 | } else if (cmd == "clear") { 196 | hash.clear(); 197 | } else if (cmd == "size") { 198 | cout << hash.size() << endl; 199 | } else if (cmd == "lambda") { 200 | cout << hash.load_factor() << endl; 201 | } else if (cmd == "end") { 202 | break; 203 | } 204 | } 205 | hash.clear(); 206 | 207 | return 0; 208 | } -------------------------------------------------------------------------------- /chapter10-strassen-algorithm.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for Strassen Algorithm. Matrix size is limited to powers of 2 only. 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | void getSubmatrix(const vector > &m, vector > &sub, int part) 7 | { 8 | int n = (int)m.size(); 9 | int i, j; 10 | int n1 = n / 2; 11 | 12 | int top = part / 2 * n1; 13 | int left = part % 2 * n1; 14 | for (i = 0; i < n1; ++i) { 15 | for (j = 0; j < n1; ++j) { 16 | sub[i][j] = m[top + i][left + j]; 17 | } 18 | } 19 | } 20 | 21 | void addMatrix(const vector > &a, const vector > &b, 22 | vector > &c, int n) 23 | { 24 | int i, j; 25 | 26 | for (i = 0; i < n; ++i) { 27 | for (j = 0; j < n; ++j) { 28 | c[i][j] = a[i][j] + b[i][j]; 29 | } 30 | } 31 | } 32 | 33 | void subtractMatrix(const vector > &a, const vector > &b, 34 | vector > &c, int n) 35 | { 36 | int i, j; 37 | 38 | for (i = 0; i < n; ++i) { 39 | for (j = 0; j < n; ++j) { 40 | c[i][j] = a[i][j] - b[i][j]; 41 | } 42 | } 43 | } 44 | 45 | void setSubmatrix(const vector > &sub, vector > &m, int part) 46 | { 47 | int n = (int)m.size(); 48 | int i, j; 49 | int n1 = n / 2; 50 | 51 | int top = part / 2 * n1; 52 | int left = part % 2 * n1; 53 | for (i = 0; i < n1; ++i) { 54 | for (j = 0; j < n1; ++j) { 55 | m[top + i][left + j] = sub[i][j]; 56 | } 57 | } 58 | } 59 | 60 | void matrixMultiplicationRecursive(const vector > &a, 61 | const vector > &b, vector > &c, int n) 62 | { 63 | if (n == 1) { 64 | c[0][0] = a[0][0] * b[0][0]; 65 | return; 66 | } 67 | 68 | int i; 69 | int n1 = n / 2; 70 | 71 | vector > aa[4]; 72 | vector > bb[4]; 73 | 74 | for (i = 0; i < 4; ++i) { 75 | aa[i].resize(n1, vector(n1)); 76 | bb[i].resize(n1, vector(n1)); 77 | } 78 | 79 | for (i = 0; i < 4; ++i) { 80 | getSubmatrix(a, aa[i], i); 81 | getSubmatrix(b, bb[i], i); 82 | } 83 | 84 | vector > x, y; 85 | vector > m[7]; 86 | 87 | x.resize(n1, vector(n1)); 88 | y.resize(n1, vector(n1)); 89 | for (i = 0; i < 7; ++i) { 90 | m[i].resize(n1, vector(n1)); 91 | } 92 | 93 | subtractMatrix(aa[1], aa[3], x, n1); 94 | addMatrix(bb[2], bb[3], y, n1); 95 | matrixMultiplicationRecursive(x, y, m[0], n1); 96 | 97 | addMatrix(aa[0], aa[3], x, n1); 98 | addMatrix(bb[0], bb[3], y, n1); 99 | matrixMultiplicationRecursive(x, y, m[1], n1); 100 | 101 | subtractMatrix(aa[0], aa[2], x, n1); 102 | addMatrix(bb[0], bb[1], y, n1); 103 | matrixMultiplicationRecursive(x, y, m[2], n1); 104 | 105 | addMatrix(aa[0], aa[1], x, n1); 106 | matrixMultiplicationRecursive(x, bb[3], m[3], n1); 107 | 108 | subtractMatrix(bb[1], bb[3], y, n1); 109 | matrixMultiplicationRecursive(aa[0], y, m[4], n1); 110 | 111 | subtractMatrix(bb[2], bb[0], y, n1); 112 | matrixMultiplicationRecursive(aa[3], y, m[5], n1); 113 | 114 | addMatrix(aa[2], aa[3], x, n1); 115 | matrixMultiplicationRecursive(x, bb[0], m[6], n1); 116 | 117 | addMatrix(m[0], m[1], x, n1); 118 | subtractMatrix(x, m[3], x, n1); 119 | addMatrix(x, m[5], x, n1); 120 | setSubmatrix(x, c, 0); 121 | 122 | addMatrix(m[3], m[4], x, n1); 123 | setSubmatrix(x, c, 1); 124 | 125 | addMatrix(m[5], m[6], x, n1); 126 | setSubmatrix(x, c, 2); 127 | 128 | subtractMatrix(m[1], m[2], x, n1); 129 | addMatrix(x, m[4], x, n1); 130 | subtractMatrix(x, m[6], x, n1); 131 | setSubmatrix(x, c, 3); 132 | 133 | for (i = 0; i < 4; ++i) { 134 | aa[i].clear(); 135 | bb[i].clear(); 136 | } 137 | for (i = 0; i < 7; ++i) { 138 | m[i].clear(); 139 | } 140 | x.clear(); 141 | y.clear(); 142 | } 143 | 144 | void matrixMultiplication(const vector > &a, 145 | const vector > &b, vector > &c) 146 | { 147 | int n = (int)a.size(); 148 | 149 | matrixMultiplicationRecursive(a, b, c, n); 150 | } 151 | 152 | int main() 153 | { 154 | int n; 155 | int i, j; 156 | vector > a, b, c; 157 | 158 | while (cin >> n && n > 0) { 159 | a.resize(n, vector(n)); 160 | b.resize(n, vector(n)); 161 | c.resize(n, vector(n)); 162 | 163 | for (i = 0; i < n; ++i) { 164 | for (j = 0; j < n; ++j) { 165 | cin >> a[i][j]; 166 | } 167 | } 168 | 169 | for (i = 0; i < n; ++i) { 170 | for (j = 0; j < n; ++j) { 171 | cin >> b[i][j]; 172 | } 173 | } 174 | 175 | matrixMultiplication(a, b, c); 176 | 177 | for (i = 0; i < n; ++i) { 178 | for (j = 0; j < n; ++j) { 179 | cout << c[i][j] << ' '; 180 | } 181 | cout << endl; 182 | } 183 | cout << endl; 184 | 185 | a.clear(); 186 | b.clear(); 187 | c.clear(); 188 | } 189 | 190 | return 0; 191 | } -------------------------------------------------------------------------------- /chapter10-skip-list.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for skip list. 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | template 9 | struct ListNode { 10 | TKey *key; 11 | ListNode *down; 12 | ListNode *next; 13 | 14 | ListNode(): key(nullptr), down(nullptr), next(nullptr) {} 15 | }; 16 | 17 | template 18 | class SkipList { 19 | public: 20 | SkipList() { 21 | m_root = new ListNode(); 22 | m_size = 0; 23 | m_level = 0; 24 | } 25 | 26 | bool contains(const TKey &key) { 27 | if (m_size == 0) { 28 | return false; 29 | } 30 | 31 | ListNode *ptr = m_root; 32 | while (true) { 33 | if (ptr->next != nullptr) { 34 | if (key < *(ptr->next->key)) { 35 | if (ptr->down != nullptr) { 36 | ptr = ptr->down; 37 | } else { 38 | return false; 39 | } 40 | } else if (key > *(ptr->next->key)) { 41 | ptr = ptr->next; 42 | } else { 43 | return true; 44 | } 45 | } else { 46 | if (ptr->down != nullptr) { 47 | ptr = ptr->down; 48 | } else { 49 | return false; 50 | } 51 | } 52 | } 53 | } 54 | 55 | void insert(const TKey &key) { 56 | if (contains(key)) { 57 | return; 58 | } 59 | 60 | ListNode *ptr; 61 | int new_level = _randomLevel(); 62 | 63 | if (new_level > m_level) { 64 | // Extra levels need to be added. 65 | for (int i = m_level; i < new_level; ++i) { 66 | ptr = new ListNode(); 67 | ptr->down = m_root; 68 | m_root = ptr; 69 | } 70 | m_level = new_level; 71 | } 72 | 73 | int lvl = m_level; 74 | ListNode *last, *cur; 75 | 76 | ptr = m_root; 77 | last = cur = nullptr; 78 | while (true) { 79 | if (ptr->next != nullptr) { 80 | if (key < *(ptr->next->key)) { 81 | if (lvl <= new_level) { 82 | cur = new ListNode(); 83 | if (last == nullptr) { 84 | cur->key = new TKey(key); 85 | } else { 86 | cur->key = last->key; 87 | last->down = cur; 88 | } 89 | last = cur; 90 | cur->next = ptr->next; 91 | ptr->next = cur; 92 | } 93 | 94 | if (ptr->down != nullptr) { 95 | ptr = ptr->down; 96 | --lvl; 97 | } else { 98 | break; 99 | } 100 | } else if (key > *(ptr->next->key)) { 101 | ptr = ptr->next; 102 | } else { 103 | break; 104 | } 105 | } else { 106 | if (lvl <= new_level) { 107 | cur = new ListNode(); 108 | if (last == nullptr) { 109 | cur->key = new TKey(key); 110 | } else { 111 | cur->key = last->key; 112 | last->down = cur; 113 | } 114 | last = cur; 115 | cur->next = ptr->next; 116 | ptr->next = cur; 117 | } 118 | 119 | if (ptr->down != nullptr) { 120 | ptr = ptr->down; 121 | --lvl; 122 | } else { 123 | break; 124 | } 125 | } 126 | } 127 | ++m_size; 128 | } 129 | 130 | void erase(const TKey &key) { 131 | if (!contains(key)) { 132 | return; 133 | } 134 | 135 | ListNode *ptr = m_root; 136 | ListNode *cur; 137 | while (true) { 138 | if (ptr->next != nullptr) { 139 | if (key < *(ptr->next->key)) { 140 | if (ptr->down != nullptr) { 141 | ptr = ptr->down; 142 | } else { 143 | break; 144 | } 145 | } else if (key > *(ptr->next->key)) { 146 | ptr = ptr->next; 147 | } else { 148 | cur = ptr->next; 149 | ptr->next = cur->next; 150 | if (ptr->down != nullptr) { 151 | delete cur; 152 | ptr = ptr->down; 153 | } else { 154 | delete cur->key; 155 | delete cur; 156 | break; 157 | } 158 | } 159 | } else { 160 | if (ptr->down != nullptr) { 161 | ptr = ptr->down; 162 | } else { 163 | break; 164 | } 165 | } 166 | } 167 | --m_size; 168 | 169 | ptr = m_root; 170 | while (ptr->next == nullptr) { 171 | // Empty levels are removed. 172 | if (ptr->down == nullptr) { 173 | break; 174 | } else { 175 | m_root = m_root->down; 176 | delete ptr; 177 | ptr = m_root; 178 | --m_level; 179 | } 180 | } 181 | } 182 | 183 | size_t size() { 184 | return m_size; 185 | } 186 | 187 | void clear() { 188 | _clearUp(); 189 | 190 | m_root = new ListNode(); 191 | m_size = 0; 192 | m_level = 0; 193 | } 194 | 195 | void debugPrint() { 196 | ListNode *p1, *p2; 197 | 198 | cout << '{' << endl; 199 | p1 = m_root; 200 | while (p1 != nullptr) { 201 | p2 = p1->next; 202 | cout << " "; 203 | while (p2 != nullptr) { 204 | cout << *(p2->key) << ' '; 205 | p2 = p2->next; 206 | } 207 | cout << endl; 208 | p1 = p1->down; 209 | } 210 | cout << '}' << endl; 211 | } 212 | 213 | ~SkipList() { 214 | _clearUp(); 215 | } 216 | private: 217 | int m_level; 218 | int m_size; 219 | ListNode *m_root; 220 | 221 | void _clearUp() { 222 | ListNode *head = m_root; 223 | ListNode *p1, *p2; 224 | 225 | while (head != nullptr) { 226 | p1 = head; 227 | head = head->down; 228 | while (p1 != nullptr) { 229 | p2 = p1->next; 230 | if (p1->key != nullptr && p1->down == nullptr) { 231 | delete p1->key; 232 | } 233 | delete p1; 234 | p1 = p2; 235 | } 236 | } 237 | } 238 | 239 | int _randomLevel() { 240 | int level = 0; 241 | 242 | while (rand() & 1) { 243 | ++level; 244 | } 245 | 246 | return level; 247 | } 248 | }; 249 | 250 | int main() 251 | { 252 | srand((unsigned int)time(nullptr)); 253 | string s; 254 | SkipList sl; 255 | int key; 256 | 257 | while (cin >> s) { 258 | if (s == "i") { 259 | cin >> key; 260 | sl.insert(key); 261 | } else if (s == "c") { 262 | cin >> key; 263 | cout << (sl.contains(key) ? "Yes" : "No") << endl; 264 | } else if (s == "e") { 265 | cin >> key; 266 | sl.erase(key); 267 | } else if (s == "cl") { 268 | sl.clear(); 269 | } 270 | sl.debugPrint(); 271 | } 272 | sl.clear(); 273 | 274 | return 0; 275 | } -------------------------------------------------------------------------------- /chapter10-alpha-beta-pruning.cpp: -------------------------------------------------------------------------------- 1 | // Optimization for Minimax game strategy, using Alpha-Beta Pruning. 2 | // You can watch over the 'function_call_count' variable. 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | int function_call_count; 8 | 9 | bool computerWin(const vector &board) 10 | { 11 | int i, j; 12 | 13 | for (i = 0; i < 3; ++i) { 14 | for (j = 0; j < 3; ++j) { 15 | if (board[i * 3 + j] != -1) { 16 | break; 17 | } 18 | } 19 | if (j == 3) { 20 | return true; 21 | } 22 | } 23 | 24 | for (i = 0; i < 3; ++i) { 25 | for (j = 0; j < 3; ++j) { 26 | if (board[j * 3 + i] != -1) { 27 | break; 28 | } 29 | } 30 | if (j == 3) { 31 | return true; 32 | } 33 | } 34 | 35 | if (board[0] == board[4] && board[4] == board[8] && board[8] == -1) { 36 | return true; 37 | } 38 | 39 | if (board[2] == board[4] && board[4] == board[6] && board[6] == -1) { 40 | return true; 41 | } 42 | 43 | return false; 44 | } 45 | 46 | bool humanWin(const vector &board) 47 | { 48 | int i, j; 49 | 50 | for (i = 0; i < 3; ++i) { 51 | for (j = 0; j < 3; ++j) { 52 | if (board[i * 3 + j] != 1) { 53 | break; 54 | } 55 | } 56 | if (j == 3) { 57 | return true; 58 | } 59 | } 60 | 61 | for (i = 0; i < 3; ++i) { 62 | for (j = 0; j < 3; ++j) { 63 | if (board[j * 3 + i] != 1) { 64 | break; 65 | } 66 | } 67 | if (j == 3) { 68 | return true; 69 | } 70 | } 71 | 72 | if (board[0] == board[4] && board[4] == board[8] && board[8] == 1) { 73 | return true; 74 | } 75 | 76 | if (board[2] == board[4] && board[4] == board[6] && board[6] == 1) { 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | bool fullBoard(const vector &board) 84 | { 85 | for (int i = 0; i < 9; ++i) { 86 | if (board[i] == 0) { 87 | return false; 88 | } 89 | } 90 | 91 | return true; 92 | } 93 | 94 | void findComputerMove(vector &board, int &best_move, int &result, 95 | int alpha, int beta) 96 | { 97 | void findHumanMove(vector &, int &, int &, int, int); 98 | int dc, i, response; 99 | 100 | ++function_call_count; 101 | best_move = -1; 102 | 103 | if (fullBoard(board)) { 104 | result = 0; 105 | return; 106 | } 107 | 108 | if (humanWin(board)) { 109 | result = 1; 110 | return; 111 | } 112 | 113 | if (computerWin(board)) { 114 | result = -1; 115 | return; 116 | } 117 | 118 | result = alpha; 119 | for (i = 0; i < 9 && result > beta; ++i) { 120 | if (board[i] != 0) { 121 | continue; 122 | } 123 | board[i] = -1; 124 | findHumanMove(board, dc, response, result, beta); 125 | board[i] = 0; 126 | 127 | if (best_move == -1 || response < result) { 128 | result = response; 129 | best_move = i; 130 | } 131 | } 132 | } 133 | 134 | void findHumanMove(vector &board, int &best_move, int &result, int alpha, 135 | int beta) 136 | { 137 | void findComputerMove(vector &, int &, int &, int, int); 138 | int dc, i, response; 139 | 140 | ++function_call_count; 141 | best_move = -1; 142 | 143 | if (fullBoard(board)) { 144 | result = 0; 145 | return; 146 | } 147 | 148 | if (computerWin(board)) { 149 | result = -1; 150 | return; 151 | } 152 | 153 | if (humanWin(board)) { 154 | result = 1; 155 | return; 156 | } 157 | 158 | result = beta; 159 | for (i = 0; i < 9 && result < alpha; ++i) { 160 | if (board[i] != 0) { 161 | continue; 162 | } 163 | board[i] = 1; 164 | findComputerMove(board, dc, response, alpha, result); 165 | board[i] = 0; 166 | 167 | if (best_move == -1 || response > result) { 168 | result = response; 169 | best_move = i; 170 | } 171 | } 172 | } 173 | 174 | void printBoard(const vector &board) 175 | { 176 | cout << " 1 2 3" << endl; 177 | int i, j; 178 | 179 | for (i = 0; i < 3; ++i) { 180 | cout << i + 1; 181 | for (j = 0; j < 3; ++j) { 182 | cout << ' '; 183 | switch(board[i * 3 + j]) { 184 | case -1: 185 | cout << 'X'; 186 | break; 187 | case 0: 188 | cout << '.'; 189 | break; 190 | case 1: 191 | cout << 'O'; 192 | break; 193 | } 194 | } 195 | cout << endl; 196 | } 197 | } 198 | 199 | int main() 200 | { 201 | vector board; 202 | int n; 203 | int result; 204 | 205 | board.resize(9, 0); 206 | while (cin >> n) { 207 | if (n < 0 || n >= 9 || board[n]) { 208 | cout << "Invalid move" << endl; 209 | continue; 210 | } 211 | 212 | board[n] = 1; 213 | printBoard(board); 214 | if (humanWin(board)) { 215 | cout << "You win." << endl; 216 | break; 217 | } 218 | 219 | if (fullBoard(board)) { 220 | cout << "Draw." << endl; 221 | break; 222 | } 223 | 224 | result = 1; 225 | function_call_count = 0; 226 | findComputerMove(board, n, result, 1, -1); 227 | cout << "Number of function calls: " << function_call_count << endl; 228 | board[n] = -1; 229 | printBoard(board); 230 | if (computerWin(board)) { 231 | cout << "Computer win." << endl; 232 | break; 233 | } 234 | 235 | if (fullBoard(board)) { 236 | cout << "Draw." << endl; 237 | break; 238 | } 239 | } 240 | 241 | return 0; 242 | } 243 | -------------------------------------------------------------------------------- /chapter4-binary-search-tree.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for binary search tree. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct TreeNode { 8 | int val; 9 | TreeNode *left; 10 | TreeNode *right; 11 | TreeNode(int _val): val(_val), left(nullptr), right(nullptr) {}; 12 | }; 13 | 14 | class BinarySearchTree { 15 | public: 16 | BinarySearchTree() { 17 | m_root = nullptr; 18 | } 19 | 20 | bool empty() { 21 | return m_root == nullptr; 22 | } 23 | 24 | void clear() { 25 | _deleteTree(m_root); 26 | } 27 | 28 | void insertNode(const int &val) { 29 | if (m_root == nullptr) { 30 | m_root = new TreeNode(val); 31 | return; 32 | } 33 | TreeNode *ptr = _findNode(val); 34 | if (val < ptr->val) { 35 | ptr->left = new TreeNode(val); 36 | } else if (val > ptr->val) { 37 | ptr->right = new TreeNode(val); 38 | } 39 | } 40 | 41 | void deleteNode(const int &val) { 42 | if (m_root == nullptr) { 43 | return; 44 | } 45 | 46 | TreeNode *par, *cur; 47 | 48 | par = nullptr; 49 | cur = m_root; 50 | while (cur != nullptr) { 51 | if (val < cur->val) { 52 | par = cur; 53 | cur = cur->left; 54 | } else if (val > cur->val) { 55 | par = cur; 56 | cur = cur->right; 57 | } else { 58 | break; 59 | } 60 | } 61 | 62 | if (cur == nullptr) { 63 | return; 64 | } 65 | 66 | if (cur->left != nullptr) { 67 | _shiftLeft(cur); 68 | return; 69 | } 70 | 71 | if (cur->right != nullptr) { 72 | _shiftRight(cur); 73 | return; 74 | } 75 | 76 | if (par == nullptr) { 77 | delete cur; 78 | m_root = nullptr; 79 | } else if (cur == par->left) { 80 | delete cur; 81 | par->left = nullptr; 82 | } else { 83 | delete cur; 84 | par->right = nullptr; 85 | } 86 | } 87 | 88 | void updateNode(const int &old_val, const int &new_val) { 89 | deleteNode(old_val); 90 | insertNode(new_val); 91 | } 92 | 93 | bool contains(const int &val) { 94 | TreeNode *ptr = _findNode(val); 95 | return ptr == nullptr ? false : ptr->val == val ? true : false; 96 | } 97 | 98 | string preorderTraversal() { 99 | string result; 100 | _preorderTraversalRecursive(m_root, result); 101 | return result; 102 | } 103 | 104 | string inorderTraversal() { 105 | string result; 106 | _inorderTraversalRecursive(m_root, result); 107 | return result; 108 | } 109 | 110 | string postorderTraversal() { 111 | string result; 112 | _postorderTraversalRecursive(m_root, result); 113 | return result; 114 | } 115 | 116 | ~BinarySearchTree() { 117 | clear(); 118 | } 119 | private: 120 | TreeNode *m_root; 121 | 122 | void _deleteTree(TreeNode *&root) { 123 | if (root == nullptr) { 124 | return; 125 | } 126 | _deleteTree(root->left); 127 | _deleteTree(root->right); 128 | delete root; 129 | root = nullptr; 130 | } 131 | 132 | TreeNode* _findNode(const int &val) { 133 | TreeNode *ptr; 134 | 135 | ptr = m_root; 136 | while (ptr != nullptr) { 137 | if (val < ptr->val) { 138 | if (ptr->left != nullptr) { 139 | ptr = ptr->left; 140 | } else { 141 | return ptr; 142 | } 143 | } else if (val > ptr->val) { 144 | if (ptr->right != nullptr) { 145 | ptr = ptr->right; 146 | } else { 147 | return ptr; 148 | } 149 | } else { 150 | return ptr; 151 | } 152 | } 153 | return ptr; 154 | } 155 | 156 | void _preorderTraversalRecursive(const TreeNode *root, string &result) { 157 | result.push_back('{'); 158 | if (root == nullptr) { 159 | // '#' represents NULL. 160 | result.push_back('#'); 161 | } else { 162 | result.append(to_string(root->val)); 163 | _preorderTraversalRecursive(root->left, result); 164 | _preorderTraversalRecursive(root->right, result); 165 | } 166 | result.push_back('}'); 167 | } 168 | 169 | void _inorderTraversalRecursive(const TreeNode *root, string &result) { 170 | result.push_back('{'); 171 | if (root == nullptr) { 172 | // '#' represents NULL. 173 | result.push_back('#'); 174 | } else { 175 | _inorderTraversalRecursive(root->left, result); 176 | result.append(to_string(root->val)); 177 | _inorderTraversalRecursive(root->right, result); 178 | } 179 | result.push_back('}'); 180 | } 181 | 182 | void _postorderTraversalRecursive(const TreeNode *root, string &result) { 183 | result.push_back('{'); 184 | if (root == nullptr) { 185 | // '#' represents NULL. 186 | result.push_back('#'); 187 | } else { 188 | _postorderTraversalRecursive(root->left, result); 189 | _postorderTraversalRecursive(root->right, result); 190 | result.append(to_string(root->val)); 191 | } 192 | result.push_back('}'); 193 | } 194 | 195 | void _shiftLeft(TreeNode *root) { 196 | TreeNode *cur, *par; 197 | 198 | // root and root->left is guaranteed to be non-empty. 199 | par = root; 200 | cur = par->left; 201 | 202 | while (cur->right != nullptr) { 203 | par = cur; 204 | cur = cur->right; 205 | } 206 | root->val = cur->val; 207 | 208 | if (cur->left != nullptr) { 209 | _shiftLeft(cur); 210 | return; 211 | } 212 | 213 | if (cur->right != nullptr) { 214 | _shiftRight(cur); 215 | return; 216 | } 217 | 218 | if (cur->val < par->val) { 219 | delete par->left; 220 | par->left = nullptr; 221 | } else { 222 | delete par->right; 223 | par->right = nullptr; 224 | } 225 | } 226 | 227 | void _shiftRight(TreeNode *root) { 228 | TreeNode *cur, *par; 229 | 230 | // root and root->right is guaranteed to be non-empty. 231 | par = root; 232 | cur = par->right; 233 | 234 | while (cur->left != nullptr) { 235 | par = cur; 236 | cur = cur->left; 237 | } 238 | root->val = cur->val; 239 | 240 | if (cur->left != nullptr) { 241 | _shiftLeft(cur); 242 | return; 243 | } 244 | 245 | if (cur->right != nullptr) { 246 | _shiftRight(cur); 247 | return; 248 | } 249 | 250 | if (cur->val < par->val) { 251 | delete par->left; 252 | par->left = nullptr; 253 | } else { 254 | delete par->right; 255 | par->right = nullptr; 256 | } 257 | } 258 | }; 259 | 260 | int main() 261 | { 262 | BinarySearchTree bst; 263 | 264 | bst.insertNode(5); 265 | bst.insertNode(3); 266 | bst.insertNode(14); 267 | bst.insertNode(2); 268 | bst.insertNode(4); 269 | bst.insertNode(9); 270 | bst.insertNode(15); 271 | bst.insertNode(7); 272 | bst.insertNode(8); 273 | cout << bst.preorderTraversal() << endl; 274 | bst.deleteNode(14); 275 | cout << bst.preorderTraversal() << endl; 276 | bst.deleteNode(5); 277 | cout << bst.preorderTraversal() << endl; 278 | 279 | bst.clear(); 280 | bst.insertNode(1); 281 | cout << bst.preorderTraversal() << endl; 282 | bst.deleteNode(1); 283 | cout << bst.preorderTraversal() << endl; 284 | 285 | return 0; 286 | } -------------------------------------------------------------------------------- /chapter4-splay-tree.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for splay tree, modified from my avl tree. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct TreeNode { 8 | int val; 9 | TreeNode *left; 10 | TreeNode *right; 11 | TreeNode *parent; 12 | TreeNode(int _val): val(_val), left(nullptr), right(nullptr), parent(nullptr) {}; 13 | }; 14 | 15 | class SplayTree { 16 | public: 17 | SplayTree() { 18 | m_root = nullptr; 19 | } 20 | 21 | bool empty() { 22 | return m_root == nullptr; 23 | } 24 | 25 | void clear() { 26 | _deleteTree(m_root); 27 | } 28 | 29 | void insertNode(const int &val) { 30 | if (m_root == nullptr) { 31 | m_root = new TreeNode(val); 32 | return; 33 | } 34 | 35 | TreeNode *ptr = _findNode(val); 36 | 37 | if (val == ptr->val) { 38 | return; 39 | } 40 | 41 | if (val < ptr->val) { 42 | ptr->left = new TreeNode(val); 43 | ptr->left->parent = ptr; 44 | ptr = ptr->left; 45 | } else { 46 | ptr->right = new TreeNode(val); 47 | ptr->right->parent = ptr; 48 | ptr = ptr->right; 49 | } 50 | _splayNode(ptr); 51 | } 52 | 53 | void deleteNode(const int &val) { 54 | if (m_root == nullptr) { 55 | return; 56 | } 57 | 58 | TreeNode *par, *cur; 59 | 60 | cur = _findNode(val); 61 | if (cur == nullptr || cur->val != val) { 62 | return; 63 | } 64 | // the node is splayed to the root, cur must be m_root. 65 | par = cur->parent; 66 | 67 | TreeNode *ptr; 68 | 69 | if (cur->left != nullptr) { 70 | ptr = _shiftLeft(cur); 71 | return; 72 | } 73 | 74 | if (cur->right != nullptr) { 75 | ptr = _shiftRight(cur); 76 | return; 77 | } 78 | 79 | if (par == nullptr) { 80 | delete cur; 81 | m_root = nullptr; 82 | } else if (val < par->val) { 83 | delete cur; 84 | par->left = nullptr; 85 | } else { 86 | delete cur; 87 | par->right = nullptr; 88 | } 89 | } 90 | 91 | void updateNode(const int &old_val, const int &new_val) { 92 | deleteNode(old_val); 93 | insertNode(new_val); 94 | } 95 | 96 | bool contains(const int &val) { 97 | TreeNode *ptr = _findNode(val); 98 | return ptr == nullptr ? false : ptr->val == val ? true : false; 99 | } 100 | 101 | string preorderTraversal() { 102 | string result; 103 | _preorderTraversalRecursive(m_root, result); 104 | return result; 105 | } 106 | 107 | string inorderTraversal() { 108 | string result; 109 | _inorderTraversalRecursive(m_root, result); 110 | return result; 111 | } 112 | 113 | string postorderTraversal() { 114 | string result; 115 | _postorderTraversalRecursive(m_root, result); 116 | return result; 117 | } 118 | 119 | ~SplayTree() { 120 | clear(); 121 | } 122 | private: 123 | TreeNode *m_root; 124 | 125 | void _deleteTree(TreeNode *&root) { 126 | if (root == nullptr) { 127 | return; 128 | } 129 | _deleteTree(root->left); 130 | _deleteTree(root->right); 131 | delete root; 132 | root = nullptr; 133 | } 134 | 135 | TreeNode* _findNode(const int &val) { 136 | TreeNode *ptr; 137 | 138 | ptr = m_root; 139 | while (ptr != nullptr) { 140 | if (val == ptr->val) { 141 | return ptr; 142 | } 143 | if (val < ptr->val) { 144 | if (ptr->left != nullptr) { 145 | ptr = ptr->left; 146 | } else { 147 | return ptr; 148 | } 149 | } else { 150 | if (ptr->right != nullptr) { 151 | ptr = ptr->right; 152 | } else { 153 | return ptr; 154 | } 155 | } 156 | } 157 | if (ptr->val == val) { 158 | _splayNode(ptr); 159 | return m_root; 160 | } 161 | 162 | return ptr; 163 | } 164 | 165 | void _preorderTraversalRecursive(const TreeNode *root, string &result) { 166 | result.push_back('{'); 167 | if (root == nullptr) { 168 | // '#' represents NULL. 169 | result.push_back('#'); 170 | } else { 171 | result.append(to_string(root->val)); 172 | _preorderTraversalRecursive(root->left, result); 173 | _preorderTraversalRecursive(root->right, result); 174 | } 175 | result.push_back('}'); 176 | } 177 | 178 | void _inorderTraversalRecursive(const TreeNode *root, string &result) { 179 | result.push_back('{'); 180 | if (root == nullptr) { 181 | // '#' represents NULL. 182 | result.push_back('#'); 183 | } else { 184 | _inorderTraversalRecursive(root->left, result); 185 | result.append(to_string(root->val)); 186 | _inorderTraversalRecursive(root->right, result); 187 | } 188 | result.push_back('}'); 189 | } 190 | 191 | void _postorderTraversalRecursive(const TreeNode *root, string &result) { 192 | result.push_back('{'); 193 | if (root == nullptr) { 194 | // '#' represents NULL. 195 | result.push_back('#'); 196 | } else { 197 | _postorderTraversalRecursive(root->left, result); 198 | _postorderTraversalRecursive(root->right, result); 199 | result.append(to_string(root->val)); 200 | } 201 | result.push_back('}'); 202 | } 203 | 204 | TreeNode *_shiftLeft(TreeNode *root) { 205 | TreeNode *cur, *par; 206 | 207 | // root and root->left is guaranteed to be non-empty. 208 | par = root; 209 | cur = par->left; 210 | 211 | while (cur->right != nullptr) { 212 | par = cur; 213 | cur = cur->right; 214 | } 215 | root->val = cur->val; 216 | 217 | if (cur->left != nullptr) { 218 | return _shiftLeft(cur); 219 | } 220 | 221 | if (cur->right != nullptr) { 222 | return _shiftRight(cur); 223 | } 224 | 225 | if (cur == par->left) { 226 | delete par->left; 227 | par->left = nullptr; 228 | } else { 229 | delete par->right; 230 | par->right = nullptr; 231 | } 232 | 233 | return par; 234 | } 235 | 236 | TreeNode *_shiftRight(TreeNode *root) { 237 | TreeNode *cur, *par; 238 | 239 | // root and root->right is guaranteed to be non-empty. 240 | par = root; 241 | cur = par->right; 242 | 243 | while (cur->left != nullptr) { 244 | par = cur; 245 | cur = cur->left; 246 | } 247 | root->val = cur->val; 248 | 249 | if (cur->left != nullptr) { 250 | return _shiftLeft(cur); 251 | } 252 | 253 | if (cur->right != nullptr) { 254 | return _shiftRight(cur); 255 | } 256 | 257 | if (cur == par->left) { 258 | delete par->left; 259 | par->left = nullptr; 260 | } else { 261 | delete par->right; 262 | par->right = nullptr; 263 | } 264 | 265 | return par; 266 | } 267 | 268 | void _singleRotationLeft(TreeNode *cur) { 269 | // Subtree A is deeper than subtree B. 270 | // Before rotation: 271 | // X 272 | // / \ 273 | // Y C 274 | // / \ 275 | // A B 276 | // ---------- 277 | // After rotation: 278 | // Y 279 | // / \ 280 | // A X 281 | // / \ 282 | // B C 283 | TreeNode *par = cur->parent; 284 | TreeNode *B; 285 | TreeNode *X, *Y; 286 | 287 | X = cur; 288 | Y = cur->left; 289 | B = Y->right; 290 | 291 | Y->right = X; 292 | X->parent = Y; 293 | X->left = B; 294 | if (B != nullptr) { 295 | B->parent = Y; 296 | } 297 | 298 | if (par == nullptr) { 299 | m_root = Y; 300 | } else if (par->left == cur) { 301 | par->left = Y; 302 | } else { 303 | par->right = Y; 304 | } 305 | Y->parent = par; 306 | } 307 | 308 | void _singleRotationRight(TreeNode *cur) { 309 | // Subtree C is deeper than subtree B. 310 | // Before rotation: 311 | // X 312 | // / \ 313 | // A Y 314 | // / \ 315 | // B C 316 | // ---------- 317 | // After rotation: 318 | // Y 319 | // / \ 320 | // X C 321 | // / \ 322 | // A B 323 | TreeNode *par = cur->parent; 324 | TreeNode *B; 325 | TreeNode *X, *Y; 326 | 327 | X = cur; 328 | Y = cur->right; 329 | B = Y->left; 330 | 331 | Y->left = X; 332 | X->parent = Y; 333 | X->right = B; 334 | if (B != nullptr) { 335 | B->parent = X; 336 | } 337 | 338 | if (par == nullptr) { 339 | m_root = Y; 340 | } else if (par->left == cur) { 341 | par->left = Y; 342 | } else { 343 | par->right = Y; 344 | } 345 | Y->parent = par; 346 | } 347 | 348 | void _doubleRotationLeftLeft(TreeNode *cur) { 349 | // This is only for splay tree, not AVL. 350 | // Before rotation: 351 | // X 352 | // / \ 353 | // Y D 354 | // / \ 355 | // Z C 356 | // / \ 357 | // A B 358 | // ---------- 359 | // After rotation: 360 | // Z 361 | // / \ 362 | // A Y 363 | // / \ 364 | // B X 365 | // / \ 366 | // C D 367 | TreeNode *par = cur->parent; 368 | TreeNode *B, *C; 369 | TreeNode *X, *Y, *Z; 370 | 371 | X = cur; 372 | Y = X->left; 373 | Z = Y->left; 374 | B = Z->right; 375 | C = Y->right; 376 | 377 | Z->right = Y; 378 | Y->parent = Z; 379 | Y->right = X; 380 | X->parent = Y; 381 | Y->left = B; 382 | if (B != nullptr) { 383 | B->parent = Y; 384 | } 385 | X->left = C; 386 | if (C != nullptr) { 387 | C->parent = X; 388 | } 389 | 390 | if (par == nullptr) { 391 | m_root = Z; 392 | } else if (par->left == cur) { 393 | par->left = Z; 394 | } else { 395 | par->right = Z; 396 | } 397 | Z->parent = par; 398 | } 399 | 400 | void _doubleRotationLeftRight(TreeNode *cur) { 401 | // Subtree Z is deeper than subtree A. Single rotation won't work, so let's use this one instead. 402 | // Before rotation: 403 | // X 404 | // / \ 405 | // Y D 406 | // / \ 407 | // A Z 408 | // / \ 409 | // B C 410 | // ---------- 411 | // After rotation: 412 | // Z 413 | // / \ 414 | // Y X 415 | // / \ / \ 416 | // A B C D 417 | TreeNode *par = cur->parent; 418 | TreeNode *B, *C; 419 | TreeNode *X, *Y, *Z; 420 | 421 | X = cur; 422 | Y = X->left; 423 | Z = Y->right; 424 | B = Z->left; 425 | C = Z->right; 426 | 427 | Z->left = Y; 428 | Y->parent = Z; 429 | Z->right = X; 430 | X->parent = Z; 431 | Y->right = B; 432 | if (B != nullptr) { 433 | B->parent = X; 434 | } 435 | X->left = C; 436 | if (C != nullptr) { 437 | C->parent = X; 438 | } 439 | 440 | if (par == nullptr) { 441 | m_root = Z; 442 | } else if (par->left == cur) { 443 | par->left = Z; 444 | } else { 445 | par->right = Z; 446 | } 447 | Z->parent = par; 448 | } 449 | 450 | void _doubleRotationRightLeft(TreeNode *cur) { 451 | // Subtree Z is deeper than subtree D. Single rotation won't work, so let's use this one instead. 452 | // Before rotation: 453 | // X 454 | // / \ 455 | // A Y 456 | // / \ 457 | // Z D 458 | // / \ 459 | // B C 460 | // ---------- 461 | // After rotation: 462 | // Z 463 | // / \ 464 | // X Y 465 | // / \ / \ 466 | // A B C D 467 | TreeNode *par = cur->parent; 468 | TreeNode *B, *C; 469 | TreeNode *X, *Y, *Z; 470 | 471 | X = cur; 472 | Y = X->right; 473 | Z = Y->left; 474 | B = Z->left; 475 | C = Z->right; 476 | 477 | Z->left = X; 478 | X->parent = Z; 479 | Z->right = Y; 480 | Y->parent = Z; 481 | X->right = B; 482 | if (B != nullptr) { 483 | B->parent = X; 484 | } 485 | Y->left = C; 486 | if (C != nullptr) { 487 | C->parent = Y; 488 | } 489 | 490 | if (par == nullptr) { 491 | m_root = Z; 492 | } else if (par->left == cur) { 493 | par->left = Z; 494 | } else { 495 | par->right = Z; 496 | } 497 | Z->parent = par; 498 | } 499 | 500 | void _doubleRotationRightRight(TreeNode *cur) { 501 | // This is only for splay tree, not AVL. 502 | // Before rotation: 503 | // X 504 | // / \ 505 | // A Y 506 | // / \ 507 | // B Z 508 | // / \ 509 | // C D 510 | // ---------- 511 | // After rotation: 512 | // Z 513 | // / \ 514 | // Y D 515 | // / \ 516 | // X C 517 | // / \ 518 | // A B 519 | TreeNode *par = cur->parent; 520 | TreeNode *B, *C; 521 | TreeNode *X, *Y, *Z; 522 | 523 | X = cur; 524 | Y = X->right; 525 | Z = Y->right; 526 | B = Y->left; 527 | C = Z->left; 528 | 529 | Z->left = Y; 530 | Y->parent = Z; 531 | Y->left = X; 532 | X->parent = Y; 533 | X->right = B; 534 | if (B != nullptr) { 535 | B->parent = X; 536 | } 537 | Y->right = C; 538 | if (C != nullptr) { 539 | C->parent = Y; 540 | } 541 | 542 | if (par == nullptr) { 543 | m_root = Z; 544 | } else if (par->left == cur) { 545 | par->left = Z; 546 | } else { 547 | par->right = Z; 548 | } 549 | Z->parent = par; 550 | } 551 | 552 | void _splayNode(TreeNode *cur) { 553 | if (m_root == nullptr || cur == nullptr) { 554 | return; 555 | } 556 | 557 | TreeNode *par, *grand; 558 | 559 | while (cur != nullptr && cur->parent != nullptr) { 560 | par = cur->parent; 561 | grand = par->parent; 562 | if (grand == nullptr) { 563 | if (par->left == cur) { 564 | _singleRotationLeft(par); 565 | } else { 566 | _singleRotationRight(par); 567 | } 568 | return; 569 | } 570 | if (grand->left == par) { 571 | if (par->left == cur) { 572 | _doubleRotationLeftLeft(grand); 573 | } else { 574 | _doubleRotationLeftRight(grand); 575 | } 576 | } else { 577 | if (par->left == cur) { 578 | _doubleRotationRightLeft(grand); 579 | } else { 580 | _doubleRotationRightRight(grand); 581 | } 582 | } 583 | } 584 | } 585 | }; 586 | 587 | int main() 588 | { 589 | SplayTree tree; 590 | 591 | tree.clear(); 592 | tree.insertNode(1); 593 | cout << tree.preorderTraversal() << endl; 594 | tree.insertNode(2); 595 | cout << tree.preorderTraversal() << endl; 596 | tree.insertNode(3); 597 | cout << tree.preorderTraversal() << endl; 598 | tree.insertNode(4); 599 | cout << tree.preorderTraversal() << endl; 600 | tree.insertNode(5); 601 | cout << tree.preorderTraversal() << endl; 602 | tree.insertNode(6); 603 | cout << tree.preorderTraversal() << endl; 604 | // until now the tree is skewed. 605 | // look at this step. 606 | tree.insertNode(-1); 607 | cout << tree.preorderTraversal() << endl; 608 | tree.deleteNode(6); 609 | cout << tree.preorderTraversal() << endl; 610 | tree.deleteNode(5); 611 | cout << tree.preorderTraversal() << endl; 612 | tree.deleteNode(4); 613 | cout << tree.preorderTraversal() << endl; 614 | tree.deleteNode(3); 615 | cout << tree.preorderTraversal() << endl; 616 | tree.deleteNode(2); 617 | cout << tree.preorderTraversal() << endl; 618 | tree.deleteNode(1); 619 | cout << tree.preorderTraversal() << endl; 620 | 621 | return 0; 622 | } -------------------------------------------------------------------------------- /chapter4-avl-tree.cpp: -------------------------------------------------------------------------------- 1 | // My implementation for avl tree. 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct TreeNode { 8 | int val; 9 | int height; 10 | TreeNode *left; 11 | TreeNode *right; 12 | TreeNode *parent; 13 | TreeNode(int _val): val(_val), height(1), left(nullptr), right(nullptr), parent(nullptr) {}; 14 | }; 15 | 16 | class AVLTree { 17 | public: 18 | AVLTree() { 19 | m_root = nullptr; 20 | } 21 | 22 | bool empty() { 23 | return m_root == nullptr; 24 | } 25 | 26 | void clear() { 27 | _deleteTree(m_root); 28 | } 29 | 30 | void insertNode(const int &val) { 31 | if (m_root == nullptr) { 32 | m_root = new TreeNode(val); 33 | return; 34 | } 35 | 36 | TreeNode *ptr = _findNode(val); 37 | 38 | if (val == ptr->val) { 39 | return; 40 | } 41 | 42 | if (val < ptr->val) { 43 | ptr->left = new TreeNode(val); 44 | ptr->left->parent = ptr; 45 | } else if (val > ptr->val) { 46 | ptr->right = new TreeNode(val); 47 | ptr->right->parent = ptr; 48 | } 49 | 50 | int hl, hr; 51 | TreeNode *ptr2; 52 | while (ptr != nullptr) { 53 | ptr2 = ptr->parent; 54 | _getHeight(ptr); 55 | hl = _height(ptr->left); 56 | hr = _height(ptr->right); 57 | switch(hl - hr) { 58 | case -2: 59 | switch (_height(ptr->right->left) - _height(ptr->right->right)) { 60 | case -1: 61 | _singleRotationRight(ptr); 62 | break; 63 | case +1: 64 | _doubleRotationRightLeft(ptr); 65 | break; 66 | } 67 | break; 68 | case +2: 69 | switch (_height(ptr->left->left) - _height(ptr->left->right)) { 70 | case -1: 71 | _doubleRotationLeftRight(ptr); 72 | break; 73 | case +1: 74 | _singleRotationLeft(ptr); 75 | break; 76 | } 77 | break; 78 | } 79 | ptr = ptr2; 80 | } 81 | } 82 | 83 | void deleteNode(const int &val) { 84 | if (m_root == nullptr) { 85 | return; 86 | } 87 | 88 | TreeNode *par, *cur; 89 | 90 | cur = _findNode(val); 91 | if (cur == nullptr || cur->val != val) { 92 | return; 93 | } 94 | par = cur->parent; 95 | 96 | TreeNode *ptr; 97 | do { 98 | if (cur->left != nullptr) { 99 | ptr = _shiftLeft(cur); 100 | break; 101 | } 102 | 103 | if (cur->right != nullptr) { 104 | ptr = _shiftRight(cur); 105 | break; 106 | } 107 | 108 | if (par == nullptr) { 109 | delete cur; 110 | m_root = nullptr; 111 | } else if (val < par->val) { 112 | delete cur; 113 | par->left = nullptr; 114 | } else { 115 | delete cur; 116 | par->right = nullptr; 117 | } 118 | ptr = par; 119 | } while (0); 120 | 121 | int hl, hr; 122 | TreeNode *ptr2; 123 | while (ptr != nullptr) { 124 | ptr2 = ptr->parent; 125 | _getHeight(ptr); 126 | hl = _height(ptr->left); 127 | hr = _height(ptr->right); 128 | switch(hl - hr) { 129 | case -2: 130 | switch (_height(ptr->right->left) - _height(ptr->right->right)) { 131 | case -1: 132 | _singleRotationRight(ptr); 133 | break; 134 | case +1: 135 | _doubleRotationRightLeft(ptr); 136 | break; 137 | } 138 | break; 139 | case +2: 140 | switch (_height(ptr->left->left) - _height(ptr->left->right)) { 141 | case -1: 142 | _doubleRotationLeftRight(ptr); 143 | break; 144 | case +1: 145 | _singleRotationLeft(ptr); 146 | break; 147 | } 148 | break; 149 | } 150 | ptr = ptr2; 151 | } 152 | } 153 | 154 | void updateNode(const int &old_val, const int &new_val) { 155 | deleteNode(old_val); 156 | insertNode(new_val); 157 | } 158 | 159 | bool contains(const int &val) { 160 | TreeNode *ptr = _findNode(val); 161 | return ptr == nullptr ? false : ptr->val == val ? true : false; 162 | } 163 | 164 | string preorderTraversal() { 165 | string result; 166 | _preorderTraversalRecursive(m_root, result); 167 | return result; 168 | } 169 | 170 | string inorderTraversal() { 171 | string result; 172 | _inorderTraversalRecursive(m_root, result); 173 | return result; 174 | } 175 | 176 | string postorderTraversal() { 177 | string result; 178 | _postorderTraversalRecursive(m_root, result); 179 | return result; 180 | } 181 | 182 | ~AVLTree() { 183 | clear(); 184 | } 185 | private: 186 | TreeNode *m_root; 187 | 188 | void _deleteTree(TreeNode *&root) { 189 | if (root == nullptr) { 190 | return; 191 | } 192 | _deleteTree(root->left); 193 | _deleteTree(root->right); 194 | delete root; 195 | root = nullptr; 196 | } 197 | 198 | TreeNode* _findNode(const int &val) { 199 | TreeNode *ptr; 200 | 201 | ptr = m_root; 202 | while (ptr != nullptr) { 203 | if (val == ptr->val) { 204 | return ptr; 205 | } 206 | if (val < ptr->val) { 207 | if (ptr->left != nullptr) { 208 | ptr = ptr->left; 209 | } else { 210 | return ptr; 211 | } 212 | } else { 213 | if (ptr->right != nullptr) { 214 | ptr = ptr->right; 215 | } else { 216 | return ptr; 217 | } 218 | } 219 | } 220 | return ptr; 221 | } 222 | 223 | void _preorderTraversalRecursive(const TreeNode *root, string &result) { 224 | result.push_back('{'); 225 | if (root == nullptr) { 226 | // '#' represents NULL. 227 | result.push_back('#'); 228 | } else { 229 | result.append(to_string(root->val)); 230 | _preorderTraversalRecursive(root->left, result); 231 | _preorderTraversalRecursive(root->right, result); 232 | } 233 | result.push_back('}'); 234 | } 235 | 236 | void _inorderTraversalRecursive(const TreeNode *root, string &result) { 237 | result.push_back('{'); 238 | if (root == nullptr) { 239 | // '#' represents NULL. 240 | result.push_back('#'); 241 | } else { 242 | _inorderTraversalRecursive(root->left, result); 243 | result.append(to_string(root->val)); 244 | _inorderTraversalRecursive(root->right, result); 245 | } 246 | result.push_back('}'); 247 | } 248 | 249 | void _postorderTraversalRecursive(const TreeNode *root, string &result) { 250 | result.push_back('{'); 251 | if (root == nullptr) { 252 | // '#' represents NULL. 253 | result.push_back('#'); 254 | } else { 255 | _postorderTraversalRecursive(root->left, result); 256 | _postorderTraversalRecursive(root->right, result); 257 | result.append(to_string(root->val)); 258 | } 259 | result.push_back('}'); 260 | } 261 | 262 | TreeNode *_shiftLeft(TreeNode *root) { 263 | TreeNode *cur, *par; 264 | 265 | // root and root->left is guaranteed to be non-empty. 266 | par = root; 267 | cur = par->left; 268 | 269 | while (cur->right != nullptr) { 270 | par = cur; 271 | cur = cur->right; 272 | } 273 | root->val = cur->val; 274 | 275 | if (cur->left != nullptr) { 276 | return _shiftLeft(cur); 277 | } 278 | 279 | if (cur->right != nullptr) { 280 | return _shiftRight(cur); 281 | } 282 | 283 | if (cur == par->left) { 284 | delete par->left; 285 | par->left = nullptr; 286 | } else { 287 | delete par->right; 288 | par->right = nullptr; 289 | } 290 | 291 | return par; 292 | } 293 | 294 | TreeNode *_shiftRight(TreeNode *root) { 295 | TreeNode *cur, *par; 296 | 297 | // root and root->right is guaranteed to be non-empty. 298 | par = root; 299 | cur = par->right; 300 | 301 | while (cur->left != nullptr) { 302 | par = cur; 303 | cur = cur->left; 304 | } 305 | root->val = cur->val; 306 | 307 | if (cur->left != nullptr) { 308 | return _shiftLeft(cur); 309 | } 310 | 311 | if (cur->right != nullptr) { 312 | return _shiftRight(cur); 313 | } 314 | 315 | if (cur == par->left) { 316 | delete par->left; 317 | par->left = nullptr; 318 | } else { 319 | delete par->right; 320 | par->right = nullptr; 321 | } 322 | 323 | return par; 324 | } 325 | 326 | int _max(const int &x, const int &y) { 327 | return x > y ? x : y; 328 | } 329 | 330 | int _height(const TreeNode *ptr) { 331 | return ptr == nullptr ? 0 : ptr->height; 332 | } 333 | 334 | void _getHeight(TreeNode *ptr) { 335 | if (ptr == nullptr) { 336 | return; 337 | } 338 | ptr->height = _max(_height(ptr->left), _height(ptr->right)) + 1; 339 | } 340 | 341 | void _singleRotationLeft(TreeNode *cur) { 342 | // Subtree A is deeper than subtree B. 343 | // Before rotation: 344 | // X 345 | // / \ 346 | // Y C 347 | // / \ 348 | // A B 349 | // ---------- 350 | // After rotation: 351 | // Y 352 | // / \ 353 | // A X 354 | // / \ 355 | // B C 356 | TreeNode *par = cur->parent; 357 | TreeNode *B; 358 | TreeNode *X, *Y; 359 | 360 | X = cur; 361 | Y = cur->left; 362 | B = Y->right; 363 | 364 | Y->right = X; 365 | X->parent = Y; 366 | X->left = B; 367 | if (B != nullptr) { 368 | B->parent = Y; 369 | } 370 | 371 | if (par == nullptr) { 372 | m_root = Y; 373 | } else if (par->left == cur) { 374 | par->left = Y; 375 | } else { 376 | par->right = Y; 377 | } 378 | Y->parent = par; 379 | 380 | _getHeight(X); 381 | _getHeight(Y); 382 | _getHeight(par); 383 | } 384 | 385 | void _singleRotationRight(TreeNode *cur) { 386 | // Subtree C is deeper than subtree B. 387 | // Before rotation: 388 | // X 389 | // / \ 390 | // A Y 391 | // / \ 392 | // B C 393 | // ---------- 394 | // After rotation: 395 | // Y 396 | // / \ 397 | // X C 398 | // / \ 399 | // A B 400 | TreeNode *par = cur->parent; 401 | TreeNode *B; 402 | TreeNode *X, *Y; 403 | 404 | X = cur; 405 | Y = cur->right; 406 | B = Y->left; 407 | 408 | Y->left = X; 409 | X->parent = Y; 410 | X->right = B; 411 | if (B != nullptr) { 412 | B->parent = X; 413 | } 414 | 415 | if (par == nullptr) { 416 | m_root = Y; 417 | } else if (par->left == cur) { 418 | par->left = Y; 419 | } else { 420 | par->right = Y; 421 | } 422 | Y->parent = par; 423 | 424 | _getHeight(X); 425 | _getHeight(Y); 426 | _getHeight(par); 427 | } 428 | 429 | void _doubleRotationLeftRight(TreeNode *cur) { 430 | // Subtree Z is deeper than subtree A. Single rotation won't work, so let's use this one instead. 431 | // Before rotation: 432 | // X 433 | // / \ 434 | // Y D 435 | // / \ 436 | // A Z 437 | // / \ 438 | // B C 439 | // ---------- 440 | // After rotation: 441 | // Z 442 | // / \ 443 | // Y X 444 | // / \ / \ 445 | // A B C D 446 | TreeNode *par = cur->parent; 447 | TreeNode *B, *C; 448 | TreeNode *X, *Y, *Z; 449 | 450 | X = cur; 451 | Y = X->left; 452 | Z = Y->right; 453 | B = Z->left; 454 | C = Z->right; 455 | 456 | Z->left = Y; 457 | Y->parent = Z; 458 | Z->right = X; 459 | X->parent = Z; 460 | Y->right = B; 461 | if (B != nullptr) { 462 | B->parent = X; 463 | } 464 | X->left = C; 465 | if (C != nullptr) { 466 | C->parent = X; 467 | } 468 | 469 | if (par == nullptr) { 470 | m_root = Z; 471 | } else if (par->left == cur) { 472 | par->left = Z; 473 | } else { 474 | par->right = Z; 475 | } 476 | Z->parent = par; 477 | 478 | _getHeight(X); 479 | _getHeight(Y); 480 | _getHeight(Z); 481 | _getHeight(par); 482 | } 483 | 484 | void _doubleRotationRightLeft(TreeNode *cur) { 485 | // Subtree Z is deeper than subtree D. Single rotation won't work, so let's use this one instead. 486 | // Before rotation: 487 | // X 488 | // / \ 489 | // A Y 490 | // / \ 491 | // Z D 492 | // / \ 493 | // B C 494 | // ---------- 495 | // After rotation: 496 | // Z 497 | // / \ 498 | // X Y 499 | // / \ / \ 500 | // A B C D 501 | TreeNode *par = cur->parent; 502 | TreeNode *B, *C; 503 | TreeNode *X, *Y, *Z; 504 | 505 | X = cur; 506 | Y = X->right; 507 | Z = Y->left; 508 | B = Z->left; 509 | C = Z->right; 510 | 511 | Z->left = X; 512 | X->parent = Z; 513 | Z->right = Y; 514 | Y->parent = Z; 515 | X->right = B; 516 | if (B != nullptr) { 517 | B->parent = X; 518 | } 519 | Y->left = C; 520 | if (C != nullptr) { 521 | C->parent = Y; 522 | } 523 | 524 | if (par == nullptr) { 525 | m_root = Z; 526 | } else if (par->left == cur) { 527 | par->left = Z; 528 | } else { 529 | par->right = Z; 530 | } 531 | Z->parent = par; 532 | 533 | _getHeight(X); 534 | _getHeight(Y); 535 | _getHeight(Z); 536 | _getHeight(par); 537 | } 538 | }; 539 | 540 | int main() 541 | { 542 | AVLTree avl; 543 | 544 | // test for single rotation 545 | avl.insertNode(1); 546 | cout << avl.preorderTraversal() << endl; 547 | avl.insertNode(2); 548 | cout << avl.preorderTraversal() << endl; 549 | avl.insertNode(3); 550 | cout << avl.preorderTraversal() << endl; 551 | avl.insertNode(4); 552 | cout << avl.preorderTraversal() << endl; 553 | avl.insertNode(5); 554 | cout << avl.preorderTraversal() << endl; 555 | avl.insertNode(6); 556 | cout << avl.preorderTraversal() << endl; 557 | avl.insertNode(7); 558 | cout << avl.preorderTraversal() << endl; 559 | avl.insertNode(8); 560 | cout << avl.preorderTraversal() << endl; 561 | avl.insertNode(9); 562 | cout << avl.preorderTraversal() << endl; 563 | cout << endl; 564 | 565 | // test for double rotation 566 | avl.clear(); 567 | avl.insertNode(3); 568 | cout << avl.preorderTraversal() << endl; 569 | avl.insertNode(1); 570 | cout << avl.preorderTraversal() << endl; 571 | avl.insertNode(2); 572 | cout << avl.preorderTraversal() << endl; 573 | cout << endl; 574 | 575 | // test for deletion, left 576 | avl.clear(); 577 | avl.insertNode(3); 578 | cout << avl.preorderTraversal() << endl; 579 | avl.insertNode(2); 580 | cout << avl.preorderTraversal() << endl; 581 | avl.insertNode(4); 582 | cout << avl.preorderTraversal() << endl; 583 | avl.insertNode(1); 584 | cout << avl.preorderTraversal() << endl; 585 | avl.deleteNode(3); 586 | cout << avl.preorderTraversal() << endl; 587 | avl.deleteNode(2); 588 | cout << avl.preorderTraversal() << endl; 589 | avl.deleteNode(4); 590 | cout << avl.preorderTraversal() << endl; 591 | cout << endl; 592 | 593 | // test for deletion, right 594 | avl.clear(); 595 | avl.insertNode(2); 596 | cout << avl.preorderTraversal() << endl; 597 | avl.insertNode(1); 598 | cout << avl.preorderTraversal() << endl; 599 | avl.insertNode(3); 600 | cout << avl.preorderTraversal() << endl; 601 | avl.insertNode(4); 602 | cout << avl.preorderTraversal() << endl; 603 | avl.deleteNode(2); 604 | cout << avl.preorderTraversal() << endl; 605 | avl.deleteNode(1); 606 | cout << avl.preorderTraversal() << endl; 607 | avl.deleteNode(3); 608 | cout << avl.preorderTraversal() << endl; 609 | cout << endl; 610 | 611 | return 0; 612 | } --------------------------------------------------------------------------------