├── .gitignore ├── Class-Contents-Only-by-C++ ├── Algorithms │ ├── Search │ │ ├── Basic Operation of BST.cpp │ │ └── Search.md │ └── Sort │ │ ├── Exchange Sort │ │ ├── Bubble Sort.cpp │ │ ├── Optimized Quick Sort.cpp │ │ └── Quick Sort.cpp │ │ ├── Insertion Sort │ │ ├── Binary Insertion Sort.cpp │ │ ├── Shell Sort.cpp │ │ └── Straight Insertion Sort.cpp │ │ ├── Merge Sort │ │ ├── Bottom-Up Merge Sort.cpp │ │ ├── NO.21 Merge Two Sorted Lists with cpp.md │ │ ├── NO.21 Merge Two Sorted Lists.cpp │ │ ├── NO.23 Merge K Sorted Lists.cpp │ │ ├── NO.23 Merge K Sorted Lists.md │ │ ├── Top-Down Merge Sort.cpp │ │ └── Two-Way Merge Sort.cpp │ │ ├── Selection Sort │ │ ├── Heap Sort.cpp │ │ ├── Pancake Sort.cpp │ │ └── Simple Selection Sort.cpp │ │ ├── Sort.md │ │ └── images │ │ ├── Bottom-Up Merge Sort.png │ │ ├── Bubble Sort.jpg │ │ ├── Shell Sort.png │ │ ├── Simple Selection Sort.png │ │ ├── Straight Insertion Sort.png │ │ └── Top-Down Merge Sort.png ├── Data-Structures │ ├── Graph │ │ ├── BFS of Example Graph.cpp │ │ ├── DFS of Example Graph.cpp │ │ ├── The ADT of Graph (adjList).cpp │ │ ├── The ADT of Graph (adjMatrix).cpp │ │ ├── images │ │ │ ├── Adjacency List.png │ │ │ ├── Adjacency Matrix 1.png │ │ │ ├── Adjacency Matrix 2.png │ │ │ ├── Dynamic Adjacency List.png │ │ │ ├── Inverse Adjacency List.png │ │ │ ├── Weighted Adjacency Matrix.png │ │ │ └── simple_graph.jpg │ │ └── 图.md │ ├── Heap │ │ ├── Basic Operation of Binary Heap.cpp │ │ ├── images │ │ │ ├── Min-Max Heap.png │ │ │ └── Two-Ended Heap.png │ │ └── 堆.md │ ├── Linear-Structure │ │ ├── Double Linked List Implementation.cpp │ │ ├── Find Kth Node From Bottom (Double Pointers Method).cpp │ │ ├── Find Kth Node From Bottom (Single Pointer Method).cpp │ │ ├── Linked List Implemented with Pointers.cpp │ │ ├── Reverse the Linked List (Rearrange Pointers).cpp │ │ ├── Reverse the Linked List (delete&insert).cpp │ │ ├── Sequential List Implemented with Arrays.cpp │ │ └── 线性表.md │ ├── Stack&Queue │ │ ├── Queue │ │ │ ├── Linked Queue.cpp │ │ │ ├── Sequential Queue.cpp │ │ │ ├── The ADT of Queue.cpp │ │ │ └── 队列.md │ │ ├── Stack │ │ │ ├── Linked Stack.cpp │ │ │ ├── Sequential Stack.cpp │ │ │ ├── The ADT of Stack.cpp │ │ │ └── 栈.md │ │ └── images │ │ │ └── Linked Stack.jpg │ └── Tree │ │ ├── Create Huffman Tree.cpp │ │ ├── Odd-Even Tree inOrder.cpp │ │ ├── Odd-Even Tree preOrder.cpp │ │ ├── Print Infix Expression.cpp │ │ ├── Serialization & Deserialization.cpp │ │ ├── Special OE Tree inOrder.cpp │ │ ├── The Implementation of Binary Tree.cpp │ │ ├── Traverse Binary Tree with Non Recrusion.cpp │ │ ├── images │ │ ├── Binary Linked List.png │ │ ├── Children Representation 1.png │ │ ├── Children Representation 2.png │ │ ├── Children-Sibling Representation.png │ │ ├── Complete Binary Tree.png │ │ ├── Exchange Binary Tree.png │ │ ├── Exchange Forest.png │ │ ├── Full Binary Tree.png │ │ ├── Huffman Encoder.png │ │ ├── Parent Representation.png │ │ ├── Perfect Binary Tree.png │ │ ├── Suffix Tree.png │ │ ├── The Squential Storage of Complete Binary Tree 1.png │ │ ├── The Squential Storage of Complete Binary Tree 2.png │ │ ├── The Squential Storage of Non-Complete Binary Tree 1.png │ │ ├── The Squential Storage of Non-Complete Binary Tree 2.png │ │ ├── Three-Pronged Linked List.png │ │ └── Trie Tree.png │ │ └── 树.md ├── Introduction.md └── images │ └── Commonly Used Complexity Functions.png ├── Homework-by-C++ ├── Homework-Week-1 │ ├── Hw 1_1 最大公约数和最小公倍数.cpp │ ├── Hw 1_2 最大值和最小值.cpp │ ├── Hw 1_3 数雷.cpp │ └── Hw 1_4 全排列.cpp ├── Homework-Week-10 │ ├── Hw 10_1 求叶子结点个数.cpp │ └── Hw 10_2 求二叉树高度.cpp ├── Homework-Week-11 │ ├── Hw 11_1 根据后序序列和中序序列确定二叉树.cpp │ └── Hw 11_2 哈夫曼树.cpp ├── Homework-Week-12 │ ├── Hw 12_1 堆的操作.cpp │ └── Hw 12_2 堆的建立.cpp ├── Homework-Week-13 │ ├── Hw 13_1 折半(二分)查找.cpp │ └── Hw 13_2 部落冲突.cpp ├── Homework-Week-14 │ └── Hw 14_1 判断是否二叉排序树.cpp ├── Homework-Week-15 │ └── Hw 15_1 整型关键字的散列映射.cpp ├── Homework-Week-16 │ ├── Hw 16_1 图的深度优先搜索.cpp │ └── Hw 16_2 抓住那头牛.cpp ├── Homework-Week-2 │ ├── Hw 2_1 冰雹猜想.cpp │ └── Hw 2_2 打印图形.cpp ├── Homework-Week-3 │ ├── Hw 3_1 顺序表的删除.cpp │ └── Hw 3_2 寻找链表元素的前驱节点.cpp ├── Homework-Week-4 │ ├── Hw 4_1 字符串匹配问题.cpp │ ├── Hw 4_1 字符串匹配问题.exe │ ├── Hw 4_1 字符串匹配问题.md │ ├── Hw 4_2 后缀表达式求值.cpp │ ├── Hw 4_3 大師と仙人との奇遇.cpp │ └── Hw 4_3 大師と仙人との奇遇.md ├── Homework-Week-5 │ └── Hw 5_1 插入排序.cpp ├── Homework-Week-8 │ ├── Hw 8_1 冒泡排序.cpp │ ├── Hw 8_2 小球装箱游戏.cpp │ └── Hw 8_2 小球装箱游戏.md └── Homework-Week-9 │ ├── Hw 9_1 二路归并排序.cpp │ └── Hw 9_2 成绩排名.cpp ├── Homework-by-python ├── Homework-Week-1 │ ├── Hw 1_1 最大公约数和最小公倍数.md │ ├── Hw 1_1 最大公约数和最小公倍数.py │ ├── Hw 1_2 最大值和最小值.md │ ├── Hw 1_2 最大值和最小值.py │ ├── Hw 1_3 数雷.md │ ├── Hw 1_3 数雷.py │ ├── Hw 1_4 全排列.md │ └── Hw 1_4 全排列.py ├── Homework-Week-2 │ ├── Hw 2 on choice.md │ ├── Hw 2 on judgement.md │ ├── Hw 2_1 冰雹猜想.py │ └── Hw 2_2 打印图形.py ├── Homework-Week-4 │ ├── Hw 4_1 字符串匹配问题.ipynb │ ├── Hw 4_1 字符串匹配问题.py │ ├── Hw 4_2 后缀表达式求值.ipynb │ ├── Hw 4_2 后缀表达式求值.py │ ├── Hw 4_3 大師と仙人との奇遇.ipynb │ └── Hw 4_3 大師と仙人との奇遇.py ├── Homework-Week-5 │ └── Hw 5_1 插入排序.py ├── Homework-Week-8 │ ├── Hw 8_1 冒泡排序.py │ └── Hw 8_2 小球装箱游戏.py └── Homework-Week-9 │ ├── Hw 9_1 二路归并排序.py │ └── Hw 9_2 成绩排名.py ├── Lab-by-C++ ├── Lab-1 │ ├── Lab 1_1 模拟队列.cpp │ ├── Lab 1_2 括弧匹配检验.cpp │ ├── Lab 1_3 胡同.cpp │ ├── Lab 1_4 包装机.cpp │ └── Lab 1_5 列车车厢重排.cpp ├── Lab-2 │ ├── Lab 2_1 冒泡排序.cpp │ ├── Lab 2_2 快速排序的过程.cpp │ ├── Lab 2_3 数表.cpp │ ├── Lab 2_4 求交换次数.cpp │ └── Lab 2_5 最大三角形.cpp ├── Lab-3 │ ├── Lab 3_1 正整数质因数分解.cpp │ ├── Lab 3_2 二分查找.cpp │ ├── Lab 3_3 寻找大富翁.cpp │ ├── Lab 3_4 关于堆的判断.cpp │ └── Lab 3_5 浦島太郎の玉手箱開き.cpp └── Lab-4 │ ├── Lab 4_1 求同年同月同日生的最大人数.cpp │ ├── Lab 4_2 寻找签到题(二叉排序树).cpp │ ├── Lab 4_3 航空公司VIP客户查询.cpp │ ├── Lab 4_4 二叉搜索树的四种遍历.cpp │ └── Lab 4_5 平均查找长度之线性再散列.cpp └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | *.exe -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Search/Basic Operation of BST.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | struct TreeNode { 6 | int val; 7 | TreeNode *left, *right; 8 | TreeNode(int value) : val(value), left(nullptr), right(nullptr) {} 9 | }; 10 | 11 | TreeNode* searchBST(TreeNode* root, int val) { 12 | if (root == nullptr || root->val == val) { 13 | return root; 14 | } 15 | return (val < root->val) ? searchBST(root->left, val) : searchBST(root->right, val); 16 | } 17 | 18 | TreeNode* searchBSTIterative(TreeNode* root, int val) { 19 | while (root != nullptr && root->val != val) { 20 | root = val < root->val ? root->left : root->right; 21 | } 22 | return root; 23 | } 24 | 25 | TreeNode* insertIntoBST(TreeNode* root, int val) { 26 | if (root == nullptr) { 27 | return new TreeNode(val); 28 | } 29 | if (val < root->val) { 30 | root->left = insertIntoBST(root->left, val); 31 | } else if (val > root->val) { 32 | root->right = insertIntoBST(root->right, val); 33 | } 34 | return root; 35 | } 36 | 37 | TreeNode* minValueNode(TreeNode* node) { 38 | TreeNode* current = node; 39 | while (current && current->left != nullptr) { 40 | current = current->left; 41 | } 42 | return current; 43 | } 44 | 45 | TreeNode* deleteNode(TreeNode* root, int key) { 46 | if (root == nullptr) { 47 | return root; 48 | } 49 | 50 | if (key < root->val) { 51 | root->left = deleteNode(root->left, key); 52 | } else if (key > root->val) { 53 | root->right = deleteNode(root->right, key); 54 | } else { 55 | // 1. 无子节点 56 | if (root->left == nullptr && root->right == nullptr) { 57 | delete root; 58 | return nullptr; 59 | } 60 | // 2. 只有一个子节点 61 | else if (root->left == nullptr) { 62 | TreeNode* temp = root->right; 63 | delete root; 64 | return temp; 65 | } 66 | else if (root->right == nullptr) { 67 | TreeNode* temp = root->left; 68 | delete root; 69 | return temp; 70 | } 71 | // 3. 有两个子节点 72 | else { 73 | TreeNode* temp = minValueNode(root->right); 74 | root->val = temp->val; 75 | root->right = deleteNode(root->right, temp->val); 76 | } 77 | } 78 | return root; 79 | } 80 | 81 | void preorderPrint(TreeNode* node) { 82 | if (node == nullptr) return; 83 | cout << node->val << " "; 84 | preorderPrint(node->left); 85 | preorderPrint(node->right); 86 | } 87 | 88 | int main() { 89 | TreeNode* root = nullptr; 90 | 91 | // 插入节点 92 | root = insertIntoBST(root, 7); 93 | root = insertIntoBST(root, 4); 94 | root = insertIntoBST(root, 9); 95 | root = insertIntoBST(root, 2); 96 | root = insertIntoBST(root, 6); 97 | root = insertIntoBST(root, 8); 98 | root = insertIntoBST(root, 10); 99 | root = insertIntoBST(root, 1); 100 | root = insertIntoBST(root, 3); 101 | root = insertIntoBST(root, 5); 102 | 103 | cout << "原始树的前序遍历: "; 104 | preorderPrint(root); 105 | cout << endl; 106 | 107 | root = deleteNode(root, 4); 108 | cout << "删除节点 4 后的前序遍历: "; 109 | preorderPrint(root); 110 | cout << endl; 111 | 112 | delete root; 113 | 114 | system("pause"); 115 | return 0; 116 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Exchange Sort/Bubble Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void BubbleSort(vector& arr) { 7 | int n = arr.size(); 8 | bool swapped; 9 | for (int i = 0; i < n - 1; ++i) { 10 | swapped = false; 11 | for (int j = 0; j < n - i - 1; ++j) { 12 | if (arr[j] > arr[j + 1]) { 13 | swap(arr[j], arr[j + 1]); 14 | swapped = true; 15 | } 16 | } 17 | if (!swapped) 18 | break; 19 | } 20 | } 21 | 22 | int main() { 23 | vector arr; 24 | int n, element; 25 | 26 | cout << "请输入元素的数量:"; 27 | cin >> n; 28 | 29 | cout << "请输入 " << n << " 个元素:"; 30 | for (int i = 0; i < n; i++) 31 | { 32 | cin >> element; 33 | arr.push_back(element); 34 | } 35 | 36 | BubbleSort(arr); 37 | 38 | cout << "排序后的数组:"; 39 | for (int i = 0; i < n; i ++){ 40 | cout << arr[i] << " "; 41 | } 42 | cout << endl; 43 | 44 | system("pause"); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Exchange Sort/Optimized Quick Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int medianOfThree(int& a, int& b, int& c) { 7 | if (a < b) { 8 | if (b < c) 9 | return b; 10 | else if (a < c) 11 | return c; 12 | else 13 | return a; 14 | } else { 15 | if (a < c) 16 | return a; 17 | else if (b < c) 18 | return c; 19 | else 20 | return b; 21 | } 22 | } 23 | 24 | int partition(vector& arr, int low, int high) { 25 | int mid = (low + high) / 2; 26 | int pivot = medianOfThree(arr[low], arr[mid], arr[high]); 27 | 28 | if (pivot == arr[mid]) { 29 | swap(arr[mid], arr[high]); 30 | } else if (pivot == arr[low]) { 31 | swap(arr[low], arr[high]); 32 | } 33 | 34 | int i = low - 1; 35 | 36 | for (int j = low; j < high; j++) { 37 | if (arr[j] < pivot) { 38 | i++; 39 | swap(arr[i], arr[j]); 40 | } 41 | } 42 | swap(arr[i + 1], arr[high]); 43 | return i + 1; 44 | } 45 | 46 | void optimizedQuickSort(vector& arr, int low, int high) { 47 | if (low < high) { 48 | int pi = partition(arr, low, high); 49 | 50 | optimizedQuickSort(arr, low, pi - 1); 51 | optimizedQuickSort(arr, pi + 1, high); 52 | } 53 | } 54 | 55 | int main() { 56 | vector arr; 57 | int n, element; 58 | 59 | cout << "请输入元素的数量:"; 60 | cin >> n; 61 | 62 | cout << "请输入 " << n << " 个元素:"; 63 | for (int i = 0; i < n; i++) 64 | { 65 | cin >> element; 66 | arr.push_back(element); 67 | } 68 | 69 | optimizedQuickSort(arr, 0, n - 1); 70 | 71 | cout << "排序后的数组:"; 72 | for (int i = 0; i < n; i ++){ 73 | cout << arr[i] << " "; 74 | } 75 | cout << endl; 76 | 77 | system("pause"); 78 | return 0; 79 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Exchange Sort/Quick Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int partition(vector& arr, int low, int high) { 7 | int pivot = arr[high]; // Choose the last element as the pivot (always) 8 | int i = low - 1; 9 | 10 | for (int j = low; j < high; j++) { 11 | if (arr[j] < pivot) { 12 | i++; 13 | swap(arr[i], arr[j]); 14 | } 15 | } 16 | swap(arr[i + 1], arr[high]); 17 | return i + 1; 18 | } 19 | 20 | void quickSort(vector& arr, int low, int high) { 21 | if (low < high) { 22 | int pi = partition(arr, low, high); 23 | 24 | quickSort(arr, low, pi - 1); 25 | quickSort(arr, pi + 1, high); 26 | } 27 | } 28 | 29 | int main() { 30 | vector arr; 31 | int n, element; 32 | 33 | cout << "请输入元素的数量:"; 34 | cin >> n; 35 | 36 | cout << "请输入 " << n << " 个元素:"; 37 | for (int i = 0; i < n; i++) 38 | { 39 | cin >> element; 40 | arr.push_back(element); 41 | } 42 | 43 | quickSort(arr, 0, n - 1); 44 | 45 | cout << "排序后的数组:"; 46 | for (int i = 0; i < n; i ++){ 47 | cout << arr[i] << " "; 48 | } 49 | cout << endl; 50 | 51 | system("pause"); 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Insertion Sort/Binary Insertion Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void BinaryInsertionSort(vector& arr) { 7 | int n = arr.size(); 8 | for (int i = 1; i < n; i++) 9 | { 10 | int key = arr[i]; 11 | int left = 0; 12 | int right = i - 1; 13 | 14 | // 使用二分查找定位插入位置 15 | while (left <= right) { 16 | int mid = (left + right)/2; 17 | if (arr[mid] > key) { 18 | right = mid - 1; 19 | } else { 20 | left = mid + 1; 21 | } 22 | } 23 | 24 | // 移动元素并插入 25 | for (int j = i - 1; j >= left; j--) { 26 | arr[j + 1] = arr[j]; 27 | } 28 | arr[left] = key; 29 | } 30 | } 31 | 32 | int main() { 33 | vector arr; 34 | int n, element; 35 | 36 | cout << "请输入元素的数量:"; 37 | cin >> n; 38 | 39 | cout << "请输入 " << n << " 个元素:"; 40 | for (int i = 0; i < n; i++) 41 | { 42 | cin >> element; 43 | arr.push_back(element); 44 | } 45 | 46 | BinaryInsertionSort(arr); 47 | 48 | cout << "排序后的数组:"; 49 | for (int i = 0; i < n; i ++){ 50 | cout << arr[i] << " "; 51 | } 52 | cout << endl; 53 | 54 | system("pause"); 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Insertion Sort/Shell Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void ShellSort(vector& arr) { 7 | int n = arr.size(); 8 | for (int gap = n / 2; gap > 0; gap /= 2) { 9 | // 对每个子序列进行直接插入排序 10 | for (int i = gap; i < n; i++) { 11 | int temp = arr[i]; 12 | int j; 13 | for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) 14 | arr[j] = arr[j - gap]; 15 | arr[j] = temp; 16 | } 17 | } 18 | } 19 | 20 | int main() { 21 | vector arr; 22 | int n, element; 23 | 24 | cout << "请输入元素的数量:"; 25 | cin >> n; 26 | 27 | cout << "请输入 " << n << " 个元素:"; 28 | for (int i = 0; i < n; i++) 29 | { 30 | cin >> element; 31 | arr.push_back(element); 32 | } 33 | 34 | ShellSort(arr); 35 | 36 | cout << "排序后的数组:"; 37 | for (int i = 0; i < n; i ++){ 38 | cout << arr[i] << " "; 39 | } 40 | cout << endl; 41 | 42 | system("pause"); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Insertion Sort/Straight Insertion Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void StraightInsertionSort(vector& arr){ 7 | int n = arr.size(); 8 | for (int i = 1; i < n; i++) { 9 | int key = arr[i]; 10 | int j = i - 1; 11 | 12 | // 将arr[i]插入到已排序的arr[0..i-1]序列中 13 | while (j >= 0 && arr[j] > key) { 14 | arr[j + 1] = arr[j]; 15 | j = j - 1; 16 | } 17 | arr[j + 1] = key; 18 | } 19 | } 20 | 21 | int main() { 22 | vector arr; 23 | int n, element; 24 | 25 | cout << "请输入元素的数量:"; 26 | cin >> n; 27 | 28 | cout << "请输入 " << n << " 个元素:"; 29 | for (int i = 0; i < n; i++) 30 | { 31 | cin >> element; 32 | arr.push_back(element); 33 | } 34 | 35 | StraightInsertionSort(arr); 36 | 37 | cout << "排序后的数组:"; 38 | for (int i = 0; i < n; i ++){ 39 | cout << arr[i] << " "; 40 | } 41 | cout << endl; 42 | 43 | system("pause"); 44 | return 0; 45 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Merge Sort/Bottom-Up Merge Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void merge(vector& arr, int l, int r, int m) { 7 | int n1 = m - l + 1; 8 | int n2 = r - m; 9 | vector L(n1), R(n2); 10 | 11 | for (int i = 0; i < n1; ++i) 12 | L[i] = arr[l + i]; 13 | for (int j = 0; j < n2; ++j) 14 | R[j] = arr[m + 1 + j]; 15 | 16 | int i = 0, j = 0, k = l; 17 | 18 | while (i < n1 && j < n2) { 19 | if (L[i] <= R[j]) { 20 | arr[k] = L[i]; 21 | i++; 22 | } else { 23 | arr[k] = R[j]; 24 | j++; 25 | } 26 | k++; 27 | } 28 | 29 | while (i < n1) 30 | { 31 | arr[k] = L[i]; 32 | i++; 33 | k++; 34 | } 35 | while (j < n2) 36 | { 37 | arr[k] = R[j]; 38 | j++; 39 | k++; 40 | } 41 | } 42 | 43 | void bottomUpMergeSort(vector& arr) { 44 | int n = arr.size(); 45 | vector temp(n); 46 | for (int size = 1; size <= n - 1; size = 2*size) { 47 | for (int l_start = 0; l_start < n - 1; l_start += 2*size) { 48 | // Find ending point of left sub array. mid+1 is starting point of right 49 | int m = l_start + size - 1; 50 | int r_end = min(l_start + 2*size - 1, n - 1); 51 | 52 | 53 | // Merge Subarrays arr[l_start...m] & arr[m+1...r_end] 54 | merge(arr, l_start, r_end, m); 55 | } 56 | } 57 | } 58 | 59 | int main() { 60 | vector arr; 61 | int n, element; 62 | 63 | cout << "请输入元素的数量:"; 64 | cin >> n; 65 | 66 | cout << "请输入 " << n << " 个元素:"; 67 | for (int i = 0; i < n; i++) 68 | { 69 | cin >> element; 70 | arr.push_back(element); 71 | } 72 | 73 | bottomUpMergeSort(arr); 74 | 75 | cout << "排序后的数组:"; 76 | for (int i = 0; i < n; i ++){ 77 | cout << arr[i] << " "; 78 | } 79 | cout << endl; 80 | 81 | system("pause"); 82 | return 0; 83 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Merge Sort/NO.21 Merge Two Sorted Lists.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | class Solution { 12 | public: 13 | ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { 14 | if (!list1) return list2; 15 | if (!list2) return list1; 16 | 17 | ListNode* dummy = new ListNode(-1); 18 | ListNode* current = dummy; 19 | 20 | while(list1 && list2) { 21 | if(list1->val < list2->val) { 22 | current->next = list1; 23 | list1 = list1->next; 24 | } else { 25 | current->next = list2; 26 | list2 = list2->next; 27 | } 28 | current = current->next; 29 | } 30 | 31 | if(list1) { 32 | current->next = list1; 33 | } else { 34 | current->next = list2; 35 | } 36 | 37 | ListNode* result = dummy->next; 38 | delete dummy; 39 | 40 | return result; 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Merge Sort/NO.23 Merge K Sorted Lists.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Definition for singly-linked list. 9 | struct ListNode { 10 | int val; 11 | ListNode *next; 12 | ListNode() : val(0), next(nullptr) {} 13 | ListNode(int x) : val(x), next(nullptr) {} 14 | ListNode(int x, ListNode *next) : val(x), next(next) {} 15 | }; 16 | 17 | class Solution { 18 | public: 19 | ListNode* mergeKLists(vector& lists) { 20 | ListNode* dummy = new ListNode(-1); 21 | ListNode* current = dummy; 22 | 23 | // Custom comparator for the priority queue 24 | auto compare = [](const pair& a, const pair& b) { 25 | return a.first > b.first || (a.first == b.first && a.second > b.second); 26 | }; 27 | 28 | priority_queue, vector>, decltype(compare)> pq(compare); // min heap 29 | 30 | // Push the head of each list into the priority queue 31 | for (int i = 0; i < lists.size(); ++i) { 32 | if (lists[i]) { 33 | pq.emplace(lists[i]->val, i); 34 | lists[i] = lists[i]->next; 35 | } 36 | } 37 | 38 | while (!pq.empty()) { 39 | auto [val, idx] = pq.top(); // structured bindings (C++17 feature) 40 | pq.pop(); 41 | current->next = new ListNode(val); 42 | current = current->next; 43 | 44 | if (lists[idx]) { 45 | pq.emplace(lists[idx]->val, idx); 46 | lists[idx] = lists[idx]->next; 47 | } 48 | } 49 | 50 | ListNode* head = dummy->next; 51 | delete dummy; 52 | return head; 53 | } 54 | }; -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Merge Sort/NO.23 Merge K Sorted Lists.md: -------------------------------------------------------------------------------- 1 | # Merge K Sorted Lists 2 | 3 | 4 | - [Merge K Sorted Lists](#merge-k-sorted-lists) 5 | - [Talk about the "Custom comparator"](#talk-about-the-custom-comparator) 6 | - [Clarify the `pair`, `map`, `unordered_map` and `set`](#clarify-the-pair-map-unordered_map-and-set) 7 | 8 | ## Talk about the "Custom comparator" 9 | 10 | ```cpp 11 | auto compare = [](const pair& a, const pair& b) { 12 | return a.first > b.first || (a.first == b.first && a.second > b.second); 13 | }; 14 | ``` 15 | 16 | 1. **Lambda Functions**: 17 | 18 | ```cpp 19 | auto compare = [](const pair& a, const pair& b) { 20 | ... 21 | }; 22 | ``` 23 | 24 | - A lambda function is a concise way to define an anonymous function (i.e., a function without a name) directly in the place where it's used. 25 | - The `[]` is the capture clause. It can be used to specify which outside variables are available for the lambda. 26 | - The square brackets `[]` at the beginning of a lambda function are known as the *capture clause*. The capture clause defines how the lambda function can access variables from the enclosing scope. Here's a breakdown of its uses: 27 | 28 | - `[]`: Capture nothing. This means the lambda cannot access local variables outside of its own scope. 29 | - `[x]`: Capture the variable `x` by value. This means the lambda has its own copy of `x` and changes to `x` inside the lambda do not affect the outside variable. 30 | - `[&x]`: Capture the variable `x` by reference. This means the lambda can access and modify the actual `x` variable from the outside scope. 31 | - `[=]`: Capture all local variables by value. This makes a copy of all local variables for the lambda. 32 | - `[&]`: Capture all local variables by reference. The lambda can access and modify all local variables from the outside scope. 33 | - We can also mix and match, e.g., `[x, &y]` would capture `x` by value and `y` by reference. 34 | 35 | - The parameters of the lambda function are defined inside the `()`. Here, the lambda takes two `pair` parameters `a` and `b`. 36 | - The lambda's body is inside `{ ... }`. 37 | - `auto compare` means the variable `compare` will automatically take on the type of whatever is assigned to it—in this case, the lambda function. 38 | 39 | 2. **decltype**: 40 | 41 | ```cpp 42 | decltype(compare) 43 | ``` 44 | 45 | - `decltype` is a keyword that queries the type of an expression. In this case, it queries the type of the `compare` lambda function. 46 | - It's used to specify the type of the comparator for the priority queue without having to manually write out the complex type of the lambda function. 47 | 48 | 3. **Priority Queue**: 49 | 50 | ```cpp 51 | priority_queue<...> pq(compare); 52 | ``` 53 | 54 | - `priority_queue` is a template class. We provide type parameters inside the angle brackets `<...>`. 55 | - The constructor `pq(compare)` initializes the priority queue with the `compare` function as the comparator. 56 | 57 | *** 58 | 59 | ## Clarify the `pair`, `map`, `unordered_map` and `set` 60 | 61 | **1. `std::pair`:** 62 | 63 | - **Header File**: `` 64 | - **Description**: `std::pair` is a templated structure designed to hold two different items. It's a simple way to connect together two values of any type, which might be different. 65 | - **Use Cases**: Common scenarios include returning two values from a function, representing key-value pairs in maps, representing ranges (like the start and end iterators), or simply storing two related pieces of data together. 66 | - **Example**: 67 | 68 | ```cpp 69 | std::pair p = {1, "one"}; 70 | ``` 71 | 72 | **2. `std::map`:** 73 | 74 | - **Header File**: `` 75 | - **Description**: `std::map` is an associative container that associates values with keys, allowing fast retrieval of the value given the key. The keys are sorted, and each key can appear only once. 76 | - **Complexity**: 77 | - **Insert, Delete, Find**: These operations run in \(O(log n)\) time due to the Red-Black tree structure internally. 78 | - **Use Cases**: Useful when we need to store and retrieve data associated with a unique key, especially when the order of the keys is essential. It's particularly handy when frequent lookups based on a key are needed. 79 | - **Example**: 80 | 81 | ```cpp 82 | std::map ageMap; 83 | ageMap["Alice"] = 25; 84 | ``` 85 | 86 | **3. `std::unordered_map`:** 87 | 88 | - **Header File**: `` 89 | - **Description**: Like `std::map`, it associates keys with values. However, it uses hashing, meaning the keys aren't stored in any particular order, but retrieval can be faster. 90 | - **Complexity**: 91 | - **Insert, Delete, Find (average)**: \(O(1)\) since it uses hashing. 92 | - **Insert, Delete, Find (worst-case)**: \(O(n)\) if many keys collide to the same hash value. *(Hash Collision)* 93 | 94 | - **Use Cases**: When rapid average-case operations are vital and there's no need to maintain order. 95 | - **Example**: 96 | 97 | ```cpp 98 | std::unordered_map ageMap; 99 | ageMap["Bob"] = 30; 100 | ``` 101 | 102 | **4. `std::set`:** 103 | 104 | - **Header File**: `` 105 | - **Description**: `std::set` is an associative container that contains a sorted set of unique objects of type Key. It's typically implemented as a Red-Black tree. 106 | - **Complexity**: 107 | - **Insert, Delete, Find**: \(O(log n)\) due to its balanced tree structure. 108 | - **Use Cases**: When we need a collection of unique items, and we want them to be automatically sorted as we insert them. It's also beneficial for operations like set union, intersection, and difference. 109 | - **Example**: 110 | 111 | ```cpp 112 | std::set s; 113 | s.insert(1); 114 | s.insert(2); 115 | s.insert(1); // won't insert since 1 already exists 116 | ``` 117 | 118 | **Comparisons**: 119 | 120 | - **Data Structure vs. Algorithm**: It's crucial to note that `std::pair`, `std::map`, `std::unordered_map`, and `std::set` are all data structures. These structures are designed to store and organize data in specific ways to facilitate different operations and use-cases. 121 | 122 | - **Ordered vs. Unordered**: `std::map` and `std::set` both maintain the order of their keys or elements, respectively, due to their typical implementation as balanced trees (Red-Black trees). In contrast, `std::unordered_map` does not maintain order since it uses hashing to store the key-value pairs. 123 | 124 | - **Unique Elements**: While both `std::map` and `std::unordered_map` store key-value pairs with unique keys, `std::set` specifically stores unique elements without any associated values. 125 | 126 | - **Usage**: 127 | 128 | - If we need to store pairs of items without the need for lookups, `std::pair` is appropriate. 129 | - For storing key-value pairs with fast lookups based on a key and maintaining order, we'd use `std::map`. 130 | - If order isn't important but we want faster average-case lookup times, lean towards `std::unordered_map`. 131 | - For a collection of unique items that are automatically sorted as they are inserted, `std::set` is the preferred choice. 132 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Merge Sort/Top-Down Merge Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void merge(vector& arr, int l, int r, int m) { 7 | int n1 = m - l + 1; 8 | int n2 = r - m; 9 | vector L(n1), R(n2); 10 | 11 | for (int i = 0; i < n1; ++i) 12 | L[i] = arr[l + i]; 13 | for (int j = 0; j < n2; ++j) 14 | R[j] = arr[m + 1 + j]; 15 | 16 | int i = 0, j = 0, k = l; 17 | 18 | while (i < n1 && j < n2) { 19 | if (L[i] <= R[j]) { 20 | arr[k] = L[i]; 21 | i++; 22 | } else { 23 | arr[k] = R[j]; 24 | j++; 25 | } 26 | k++; 27 | } 28 | 29 | while (i < n1) 30 | { 31 | arr[k] = L[i]; 32 | i++; 33 | k++; 34 | } 35 | while (j < n2) 36 | { 37 | arr[k] = R[j]; 38 | j++; 39 | k++; 40 | } 41 | } 42 | 43 | /* 44 | This is the same as "twoWay Merge Sort" 45 | The Top-Down method uses recrusion 46 | */ 47 | void topDownMergeSort(vector& arr, int l, int r) { 48 | if (l < r) { 49 | int m = l + (r - l) / 2; 50 | 51 | topDownMergeSort(arr, l, m); 52 | topDownMergeSort(arr, m + 1, r); 53 | 54 | merge(arr, l, r, m); 55 | } 56 | } 57 | 58 | int main() { 59 | vector arr; 60 | int n, element; 61 | 62 | cout << "请输入元素的数量:"; 63 | cin >> n; 64 | 65 | cout << "请输入 " << n << " 个元素:"; 66 | for (int i = 0; i < n; i++) 67 | { 68 | cin >> element; 69 | arr.push_back(element); 70 | } 71 | 72 | topDownMergeSort(arr, 0, n - 1); 73 | 74 | cout << "排序后的数组:"; 75 | for (int i = 0; i < n; ++i) { 76 | cout << arr[i] << " "; 77 | } 78 | cout << endl; 79 | 80 | system("pause"); 81 | return 0; 82 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Merge Sort/Two-Way Merge Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void twoWayMerge(vector& arr, int l, int r, int m) { 7 | // create 2 temp arrays 8 | int n1 = m - l + 1; 9 | int n2 = r - m; 10 | vector L(n1), R(n2); 11 | 12 | // copy the datas to the 2 temp arrays 13 | for (int i = 0; i < n1; ++i) 14 | L[i] = arr[l + i]; 15 | for (int j = 0; j < n2; ++j) 16 | R[j] = arr[m + 1 + j]; 17 | 18 | // merge the 2 temp arrays into the original array 19 | int i = 0, j = 0, k = l; 20 | 21 | while (i < n1 && j < n2) { 22 | if (L[i] <= R[j]) { 23 | arr[k] = L[i]; 24 | i++; 25 | } else { 26 | arr[k] = R[j]; 27 | j++; 28 | } 29 | k++; 30 | } 31 | 32 | while (i < n1) 33 | { 34 | arr[k] = L[i]; 35 | i++; 36 | k++; 37 | } 38 | while (j < n2) 39 | { 40 | arr[k] = R[j]; 41 | j++; 42 | k++; 43 | } 44 | } 45 | 46 | void twoWayMergeSort(vector& arr, int l, int r) { 47 | if (l < r) { 48 | int m = l + (r - l) / 2; 49 | 50 | twoWayMergeSort(arr, l, m); 51 | twoWayMergeSort(arr, m + 1, r); 52 | 53 | twoWayMerge(arr, l, r, m); 54 | } 55 | } 56 | 57 | int main() { 58 | vector arr; 59 | int n, element; 60 | 61 | cout << "请输入元素的数量:"; 62 | cin >> n; 63 | 64 | cout << "请输入 " << n << " 个元素:"; 65 | for (int i = 0; i < n; i++) 66 | { 67 | cin >> element; 68 | arr.push_back(element); 69 | } 70 | 71 | twoWayMergeSort(arr, 0, n - 1); 72 | 73 | cout << "排序后的数组:"; 74 | for (int i = 0; i < n; ++i) { 75 | cout << arr[i] << " "; 76 | } 77 | cout << endl; 78 | 79 | system("pause"); 80 | return 0; 81 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Selection Sort/Heap Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void HeapSort(vector& arr) { 8 | // 构建最大堆 9 | make_heap(arr.begin(), arr.end()); 10 | 11 | for (int i = arr.size() - 1; i > 0; --i) { 12 | pop_heap(arr.begin(), arr.begin() + i + 1); 13 | // 将堆中的最大元素(位于 `arr.begin()`,即堆顶)和范围的最后一个元素(位于 `arr.begin() + i`)交换。 14 | // 排除已经移动到末尾的最大元素,对剩下的范围(从 `arr.begin()` 到 `arr.begin() + i`)重新进行堆化。 15 | } 16 | } 17 | // 注意上面这个函数的构造直接使用了algorithm库中操作堆的函数以至于不用我们亲自构建与操作。 18 | 19 | int main() { 20 | vector arr; 21 | int n, element; 22 | 23 | cout << "请输入元素的数量:"; 24 | cin >> n; 25 | 26 | cout << "请输入 " << n << " 个元素:"; 27 | for (int i = 0; i < n; i++) 28 | { 29 | cin >> element; 30 | arr.push_back(element); 31 | } 32 | 33 | HeapSort(arr); 34 | 35 | cout << "排序后的数组:"; 36 | for (int i = 0; i < n; i ++){ 37 | cout << arr[i] << " "; 38 | } 39 | cout << endl; 40 | 41 | system("pause"); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Selection Sort/Pancake Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 翻转函数,翻转arr[0..i] 8 | void flip(vector& arr, int i) { 9 | reverse(arr.begin(), arr.begin() + i + 1); 10 | } 11 | 12 | // 返回最大元素的索引 13 | int findMax(vector& arr, int n) { 14 | int max_index = 0; 15 | for (int i = 1; i <= n; i++) { 16 | if (arr[i] > arr[max_index]) { 17 | max_index = i; 18 | } 19 | } 20 | return max_index; 21 | } 22 | 23 | // 煎饼排序 24 | void PancakeSort(vector& arr) { 25 | int n = arr.size(); 26 | for (int curr_size = n; curr_size > 1; --curr_size) 27 | { 28 | int max_index = findMax(arr, curr_size - 1); 29 | 30 | if (max_index != curr_size - 1) { 31 | flip(arr, max_index); 32 | flip(arr, curr_size - 1); 33 | } 34 | } 35 | } 36 | 37 | int main() { 38 | vector arr; 39 | int n, element; 40 | 41 | cout << "请输入元素的数量:"; 42 | cin >> n; 43 | 44 | cout << "请输入 " << n << " 个元素:"; 45 | for (int i = 0; i < n; i++) 46 | { 47 | cin >> element; 48 | arr.push_back(element); 49 | } 50 | 51 | PancakeSort(arr); 52 | 53 | cout << "排序后的数组:"; 54 | for (int i = 0; i < n; i ++){ 55 | cout << arr[i] << " "; 56 | } 57 | cout << endl; 58 | 59 | system("pause"); 60 | return 0; 61 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/Selection Sort/Simple Selection Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void SimpleSelectionSort(vector& arr) { 7 | int n = arr.size(); 8 | for (int i = 0; i < n - 1; i++){ 9 | // 找到未排序部分的最小元素的索引 10 | int min_index = i; 11 | for(int j = i + 1; j < n; j++) { 12 | if (arr[j] < arr[min_index]) 13 | min_index = j; 14 | } 15 | 16 | swap(arr[i], arr[min_index]); 17 | } 18 | } 19 | 20 | int main() { 21 | vector arr; 22 | int n, element; 23 | 24 | cout << "请输入元素的数量:"; 25 | cin >> n; 26 | 27 | cout << "请输入 " << n << " 个元素:"; 28 | for (int i = 0; i < n; i++) 29 | { 30 | cin >> element; 31 | arr.push_back(element); 32 | } 33 | 34 | SimpleSelectionSort(arr); 35 | 36 | cout << "排序后的数组:"; 37 | for (int i = 0; i < n; i ++){ 38 | cout << arr[i] << " "; 39 | } 40 | cout << endl; 41 | 42 | system("pause"); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/images/Bottom-Up Merge Sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Algorithms/Sort/images/Bottom-Up Merge Sort.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/images/Bubble Sort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Algorithms/Sort/images/Bubble Sort.jpg -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/images/Shell Sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Algorithms/Sort/images/Shell Sort.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/images/Simple Selection Sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Algorithms/Sort/images/Simple Selection Sort.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/images/Straight Insertion Sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Algorithms/Sort/images/Straight Insertion Sort.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Algorithms/Sort/images/Top-Down Merge Sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Algorithms/Sort/images/Top-Down Merge Sort.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/BFS of Example Graph.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // 这个类表示使用邻接表的有向图 7 | class Graph { 8 | int V; // 顶点的数量 9 | vector> adj; // 邻接表 10 | 11 | public: 12 | Graph(int V) { 13 | this->V = V; 14 | adj.resize(V); 15 | } 16 | 17 | void addEdge(int v, int w) { 18 | adj[v].push_back(w); // 在v的列表中添加w 19 | } 20 | 21 | void BFS(int s) { 22 | vector visited(V, false); // 标记所有顶点为未访问 23 | queue queue; // 为BFS创建一个队列 24 | 25 | visited[s] = true; // 标记当前节点为已访问并入队 26 | queue.push(s); 27 | 28 | while (!queue.empty()) { 29 | s = queue.front(); 30 | cout << s << " "; 31 | queue.pop(); 32 | 33 | for (int adjacent : adj[s]) { 34 | if (!visited[adjacent]) { 35 | visited[adjacent] = true; 36 | queue.push(adjacent); 37 | } 38 | } 39 | } 40 | } 41 | }; 42 | 43 | int main() { 44 | Graph g(4); 45 | g.addEdge(0, 1); 46 | g.addEdge(0, 2); 47 | g.addEdge(1, 2); 48 | g.addEdge(2, 0); 49 | g.addEdge(2, 3); 50 | g.addEdge(3, 3); 51 | 52 | cout << "下面是从顶点2开始的广度优先遍历(Breadth First Traversal)\n"; 53 | g.BFS(2); 54 | 55 | system("pause"); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/DFS of Example Graph.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | class Graph { 7 | public: 8 | unordered_map visited;// 用于标记顶点是否已被访问 9 | unordered_map> adj;// 邻接表 10 | 11 | void addEdge(int v, int w) { 12 | adj[v].push_back(w); 13 | } 14 | 15 | void DFS(int v) { 16 | visited[v] = true; 17 | cout << v << " "; 18 | 19 | for (int adjacent : adj[v]) { 20 | if (!visited[adjacent]) { 21 | DFS(adjacent); 22 | } 23 | } 24 | } 25 | }; 26 | 27 | int main() { 28 | Graph g; 29 | g.addEdge(0, 1); 30 | g.addEdge(0, 2); 31 | g.addEdge(1, 2); 32 | g.addEdge(2, 0); 33 | g.addEdge(2, 3); 34 | g.addEdge(3, 3); 35 | 36 | cout << "下面是从顶点2开始的深度优先遍历(Depth First Traversal)\n"; 37 | g.DFS(2); 38 | 39 | system("pause"); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/The ADT of Graph (adjList).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | class Graph { 7 | private: 8 | int maxVertices; 9 | bool directed; 10 | vector> adjList; 11 | 12 | public: 13 | Graph(int maxVertices, bool directed = false) : maxVertices(maxVertices), directed(directed) { 14 | adjList.resize(maxVertices); 15 | }// 图的初始化 16 | 17 | // 析构函数无需显式定义,vector和list会自动管理内存 18 | 19 | void insertVertex(int v) { 20 | // 在邻接表中,通常不需要显式插入顶点 21 | }//插入顶点 22 | 23 | void insertEdge(int u, int v) { 24 | if (u < maxVertices && v < maxVertices) { 25 | adjList[u].push_back(v); 26 | if (!directed) { 27 | adjList[v].push_back(u); 28 | } 29 | } 30 | }//插入边 31 | 32 | void removeVertex(int v) { 33 | // 由于需要重新构造列表,删除顶点较为复杂 34 | }//删除顶点 35 | 36 | void removeEdge(int u, int v) { 37 | adjList[u].remove(v); 38 | if (!directed) { 39 | adjList[v].remove(u); 40 | } 41 | }//删除边 42 | 43 | int getPosition(int v) { 44 | return v; 45 | }//返回顶点在图中的位置 46 | 47 | int numberOfVertices() { 48 | return maxVertices; 49 | }//返回顶点数 50 | 51 | int numberOfEdges() { 52 | int count = 0; 53 | for (int i = 0; i < maxVertices; i++) { 54 | count += adjList[i].size(); 55 | } 56 | return directed ? count : count / 2; 57 | }//返回边数 58 | 59 | bool existEdge(int u, int v) { 60 | for (auto& vert : adjList[u]) { 61 | if (vert == v) return true; 62 | } 63 | return false; 64 | }//判断边是否存在 65 | 66 | }; 67 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/The ADT of Graph (adjMatrix).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | class Graph { 6 | private: 7 | int maxVertices;//最大顶点数 8 | bool directed;//是否为有向图 9 | vector> adjMatrix;//邻接矩阵 10 | 11 | public: 12 | Graph(int maxVertices, int noEdgeValue = 0, bool directed = false) 13 | : maxVertices(maxVertices), directed(directed), adjMatrix(maxVertices, vector(maxVertices, noEdgeValue)) {}//初始化 14 | 15 | // 析构函数无需显式定义,vector会自动管理内存 16 | 17 | void insertVertex(int v) { 18 | // 通常在使用邻接矩阵时,不需要特别处理插入顶点的操作 19 | }//插入顶点 20 | 21 | void insertEdge(int u, int v, int weight) { 22 | if (u >= 0 && u < maxVertices && v >= 0 && v < maxVertices) { 23 | adjMatrix[u][v] = weight; 24 | if (!directed) { 25 | adjMatrix[v][u] = weight; // 对于无向图,同时更新对称位置的权值 26 | } 27 | } 28 | }//插入边 29 | 30 | void removeVertex(int v) { 31 | // 在邻接矩阵表示中,通常不直接删除顶点,因为这需要重构整个矩阵 32 | }//删除顶点 33 | 34 | void removeEdge(int u, int v) { 35 | if (u >= 0 && u < maxVertices && v >= 0 && v < maxVertices) { 36 | adjMatrix[u][v] = noEdgeValue; 37 | if (!directed) { 38 | adjMatrix[v][u] = noEdgeValue;// 对于无向图,同时更新对称位置的权值 39 | } 40 | } 41 | }//删除边 42 | 43 | int getPosition(int v) { 44 | // 返回顶点在图中的位置,因为使用邻接矩阵,故这里直接返回顶点的值 45 | return v; 46 | }//返回顶点在图中的位置 47 | 48 | int getValue(int v) { 49 | // 通常顶点的值就是其位置 50 | return v; 51 | }//返回顶点的值 52 | 53 | void putValue(int v, int value) { 54 | // 在邻接矩阵中,通常不存储额外的顶点值 55 | }//设置顶点的值 56 | 57 | int numberOfVertices() { 58 | return maxVertices; 59 | }//返回顶点数 60 | 61 | int numberOfEdges() { 62 | int count = 0; 63 | for (int i = 0; i < maxVertices; i++) { 64 | for (int j = 0; j < maxVertices; j++) { 65 | if (adjMatrix[i][j] != noEdgeValue) count++; 66 | } 67 | } 68 | return directed ? count : count / 2; 69 | }//返回边数 70 | 71 | bool existEdge(int u, int v) { 72 | return u >= 0 && u < maxVertices && v >= 0 && v < maxVertices && adjMatrix[u][v] != noEdgeValue; 73 | }//判断边是否存在 74 | 75 | }; 76 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/images/Adjacency List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Graph/images/Adjacency List.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/images/Adjacency Matrix 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Graph/images/Adjacency Matrix 1.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/images/Adjacency Matrix 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Graph/images/Adjacency Matrix 2.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/images/Dynamic Adjacency List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Graph/images/Dynamic Adjacency List.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/images/Inverse Adjacency List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Graph/images/Inverse Adjacency List.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/images/Weighted Adjacency Matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Graph/images/Weighted Adjacency Matrix.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Graph/images/simple_graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Graph/images/simple_graph.jpg -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Heap/Basic Operation of Binary Heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void siftUp(int i, vector& heap) { 7 | int temp = heap[i]; 8 | while (i > 1 && temp < heap[i / 2]) { 9 | heap[i] = heap[i / 2]; 10 | i = i / 2; 11 | } 12 | heap[i] = temp; 13 | } 14 | 15 | void siftDown(int i, vector& heap) { 16 | int temp = heap[i]; 17 | int size = heap.size(); 18 | while (2 * i <= size) { 19 | int child = 2 * i; 20 | if (child < size && heap[child] > heap[child + 1]) { 21 | child++; 22 | } 23 | if (temp <= heap[child]) { 24 | break; 25 | } 26 | heap[i] = heap[child]; 27 | i = child; 28 | } 29 | heap[i] = temp; 30 | } 31 | 32 | void insert(int value, vector& heap) { 33 | heap.push_back(value); 34 | siftUp(heap.size() - 1, heap); 35 | } 36 | 37 | void deleteMin(vector& heap) { 38 | if (heap.size() > 1) { 39 | heap[1] = heap.back(); 40 | heap.pop_back(); 41 | siftDown(1, heap); 42 | } 43 | } 44 | 45 | void buildHeap(vector& heap) { 46 | int n = heap.size() - 1; 47 | for (int i = n / 2; i >= 1; --i) { 48 | siftDown(i, heap); 49 | } 50 | } 51 | 52 | int main() { 53 | // 创建一个空的二叉堆,第一个位置留空 54 | vector heap = {0}; 55 | 56 | insert(10, heap); 57 | insert(4, heap); 58 | insert(9, heap); 59 | insert(1, heap); 60 | insert(7, heap); 61 | 62 | cout << "堆中的元素(建堆后): "; 63 | for (int i = 1; i < heap.size(); i++) { 64 | cout << heap[i] << " "; 65 | } 66 | cout << endl; 67 | 68 | deleteMin(heap); 69 | 70 | cout << "删除最小元素后的堆: "; 71 | for (int i = 1; i < heap.size(); i++) { 72 | cout << heap[i] << " "; 73 | } 74 | cout << endl; 75 | 76 | system("pause"); 77 | return 0; 78 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Heap/images/Min-Max Heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Heap/images/Min-Max Heap.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Heap/images/Two-Ended Heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Heap/images/Two-Ended Heap.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Heap/堆.md: -------------------------------------------------------------------------------- 1 | # 堆(Heap) 2 | 3 | 4 | - [堆(Heap)](#堆heap) 5 | - [优先级队列(Priority Queue)](#优先级队列priority-queue) 6 | - [优先级队列的定义](#优先级队列的定义) 7 | - [优先级队列的ADT](#优先级队列的adt) 8 | - [优先级队列的实现](#优先级队列的实现) 9 | - [二叉堆(Binary Heap)](#二叉堆binary-heap) 10 | - [二叉堆的定义](#二叉堆的定义) 11 | - [二叉堆的特点](#二叉堆的特点) 12 | - [二叉堆的存储方式](#二叉堆的存储方式) 13 | - [二叉堆的基本操作及代码实现](#二叉堆的基本操作及代码实现) 14 | - [优先级队列的应用](#优先级队列的应用) 15 | - [优先级队列的应用I:哈夫曼树的构建](#优先级队列的应用i哈夫曼树的构建) 16 | - [优先级队列的应用II:堆排序](#优先级队列的应用ii堆排序) 17 | - [优先级队列的应用III:多路归并](#优先级队列的应用iii多路归并) 18 | - [\*可并堆(Meldable Heap)](#可并堆meldable-heap) 19 | - [可并堆的定义](#可并堆的定义) 20 | - [可并堆的主要特点](#可并堆的主要特点) 21 | - [常见类型的可并堆](#常见类型的可并堆) 22 | - [合并操作的实现](#合并操作的实现) 23 | - [可并堆的使用场景](#可并堆的使用场景) 24 | - [最大最小堆(Min-Max Heap)\& 最小最大堆(Max-Min Heap)](#最大最小堆min-max-heap-最小最大堆max-min-heap) 25 | - [两者的基本概念](#两者的基本概念) 26 | - [核心特性](#核心特性) 27 | - [两者的基本操作](#两者的基本操作) 28 | - [两者的时间复杂度](#两者的时间复杂度) 29 | - [两者的应用场景](#两者的应用场景) 30 | - [对顶堆(Two-Ended Heap)](#对顶堆two-ended-heap) 31 | - [对顶堆的基本概念](#对顶堆的基本概念) 32 | - [对顶堆的核心特性](#对顶堆的核心特性) 33 | - [对顶堆的基本操作](#对顶堆的基本操作) 34 | - [对顶堆的应用场景](#对顶堆的应用场景) 35 | 36 | ## 优先级队列(Priority Queue) 37 | 38 | ### 优先级队列的定义 39 | 40 | 优先级队列(Priority Queue)是一种特殊的队列,它的主要特点是元素的出队顺序是按照元素的优先级来决定的,而不是元素进入队列的先后顺序。在优先级队列中,每个元素都有一个优先级,优先级最高的元素最先出队。 41 | 42 | ### 优先级队列的ADT 43 | 44 | 优先级队列的抽象数据类型(ADT)定义了优先级队列的数据对象、数据关系和基本操作。 45 | 46 | 1. **数据对象**:元素取自全集 \( U \) 的可重集合 \( E \),表示优先级队列中包含的元素。 47 | 48 | 2. **数据关系**:全集 \( U \) 中的元素须满足严格弱序,即元素间可以比较优先级。 49 | 50 | 3. **基本操作**: 51 | - `Insert(pq, x)`:在优先级队列 \( pq \) 中插入元素 \( x \)。 52 | - `ExtractMin(pq)`:从优先级队列 \( pq \) 中删除优先级最高(也就是值最小)的元素,并返回该元素。 53 | - `ExtractMax(pq)`:从优先级队列 \( pq \) 中删除优先级最高(也就是值最大)的元素,并返回该元素。 54 | - `PeekMin(pq)`:返回优先级队列 \( pq \) 中优先级最高的元素(元素仍然保留在优先级队列中)。 55 | - `PeekMax(pq)`:返回优先级队列 \( pq \) 中优先级最高的元素(元素仍然保留在优先级队列中)。 56 | 57 | ### 优先级队列的实现 58 | 59 | 在实现优先级队列时,虽然可以使用线性结构如链表或数组,但这种实现方式在出队操作时需要遍历所有元素以找到优先级最高的元素,其时间复杂度为 \( O(n) \),效率较低。因此,更常见的做法是使用二叉堆(Binary Heap)等更高效的数据结构来实现优先级队列,这样可以将出队操作的时间复杂度降低到 \( O(\log n) \)。 60 | 61 | ## 二叉堆(Binary Heap) 62 | 63 | ### 二叉堆的定义 64 | 65 | 二叉堆(Binary Heap)是一种特殊的完全二叉树,主要用于实现优先级队列。它由 J. W. J. Williams 于 1964 年提出,最初是为了支持堆排序算法。二叉堆可以分为两种类型:最小堆(Min Heap)和最大堆(Max Heap),它们的特性如下: 66 | 67 | 1. **最小堆(Min Heap)**: 68 | - 在最小堆中,任何一个父节点的值都不大于其子节点的值。 69 | - 这意味着堆的根节点(即堆顶)是所有节点中的最小值。 70 | 71 | 2. **最大堆(Max Heap)**: 72 | - 在最大堆中,任何一个父节点的值都不小于其子节点的值。 73 | - 这意味着堆的根节点是所有节点中的最大值。 74 | 75 | ### 二叉堆的特点 76 | 77 | - **完全二叉树结构**:二叉堆是一种完全二叉树,这意味着除了最后一层外,每一层都是完全填满的,且最后一层的节点尽可能地集中在左侧。 78 | - **父子节点的关系**: 79 | - 结点 \( i \) 的左子节点的下标是 \( 2i \)(如果存在)。 80 | - 结点 \( i \) 的右子节点的下标是 \( 2i + 1 \)(如果存在)。 81 | - 结点 \( i \) 的父节点的下标是 \( i/2 \)(如果存在)。 82 | 83 | ### 二叉堆的存储方式 84 | 85 | - 由于二叉堆是完全二叉树,它可以有效地在数组中存储,无需使用指针。根节点存储在数组的第一个位置(有时为了计算方便,也会将根节点存储在数组的第二个位置,即下标为 1 的位置)。 86 | 87 | ### 二叉堆的基本操作及代码实现 88 | 89 | - 上调(Sift Up)操作 90 | 1. 比较当前结点 \( i \) 与其父结点 \( p \) 的值。如果当前结点的值小于父结点的值(对于最小堆),则需要调整。 91 | 2. 将当前结点的值向上移动,即将父结点的值下移,而不是直接交换两个结点的值。 92 | 3. 重复以上步骤,直到当前结点移动到根结点或者满足堆的性质(即当前结点的值不小于父结点的值)。 93 | 94 | - 下调(Sift Down)操作 95 | 1. 比较当前结点 \( i \) 与其子结点的值。如果当前结点的值大于其子结点的值(对于最小堆),则需要调整。 96 | 2. 如果有两个子结点,选择两者中较小的一个与当前结点进行比较。 97 | 3. 将当前结点的值向下移动,将较小的子结点的值上移。 98 | 4. 重复以上步骤,直到当前结点移动到叶子结点或满足堆的性质。 99 | 100 | - 插入操作 101 | 1. 将新元素添加到堆的末尾。 102 | 2. 使用上调操作将新元素移动到合适的位置。 103 | 104 | - 删除操作 105 | 1. 删除堆顶元素(对于最小堆,堆顶是最小值)。 106 | 2. 将堆的最后一个元素移动到堆顶。 107 | 3. 使用下调操作将新的堆顶元素移动到合适的位置。 108 | 109 | - 快速建堆操作 110 | 1. 从最后一个非叶子结点开始,对每个结点应用下调操作。 111 | 2. 逐步上移至根结点。 112 | 113 | - 朴素建堆操作 114 | 1. 从数组的第二个元素开始。因为在二叉堆的数组表示中,索引为 1 的位置是根节点,它没有父节点,因此不需要上调。 115 | 2. 依次遍历数组中的每个元素,对每个元素执行上调操作。 116 | 3. 重复这个过程,直到数组的最后一个元素。 117 | 118 | ***代码实现见`Basic Operation of Binary Heap.cpp`文件。*** 119 | 120 | ## 优先级队列的应用 121 | 122 | ### 优先级队列的应用I:哈夫曼树的构建 123 | 124 | 在“树-哈夫曼树的构建”已详细说明。 125 | 126 | ### 优先级队列的应用II:堆排序 127 | 128 | 在“排序-选择排序-堆排序”已详细说明。 129 | 130 | ### 优先级队列的应用III:多路归并 131 | 132 | 在“排序-归并排序”已详细说明。 133 | 134 | ## *可并堆(Meldable Heap) 135 | 136 | ### 可并堆的定义 137 | 138 | 一种特殊类型的堆,设计用于有效地支持堆的合并操作。这在某些算法中非常重要,尤其是当需要频繁地合并两个堆时。相比于传统的二叉堆,可并堆在合并两个堆时更加高效。 139 | 140 | ### 可并堆的主要特点 141 | 142 | 1. **高效的合并操作**:可并堆的主要特点是能够高效地合并两个堆,这通常是其最基本的操作之一。 143 | 144 | 2. **不规则的形状**:与二叉堆的规则完全二叉树形状不同,可并堆通常具有不规则的形状。 145 | 146 | 3. **指针表示法**:因为其形状的不规则性,可并堆在实现时通常需要使用指针来表示节点之间的连接关系。 147 | 148 | 4. **基本操作**: 149 | - **合并(Meld)**:合并是可并堆的核心操作,用于将两个堆合并成一个。 150 | - **插入**:通过将新元素创建为单节点堆,然后将其与现有堆合并来实现。 151 | - **删除**:删除操作通常涉及到从堆中移除节点后,将产生的子树合并回堆中。 152 | 153 | ### 常见类型的可并堆 154 | 155 | - **左堆(Leftist Heap)**:左堆通过维护外节点路径长度的方法来优化合并操作。左堆的合并操作时间复杂度是 \( O(\log n) \)。 156 | 157 | - **斜堆(Skew Heap)**:斜堆是左堆的一个变种,它减少了维护信息的需要。斜堆的合并操作同样是 \( O(\log n) \)。 158 | 159 | - **二项堆(Binomial Heap)**:二项堆由一系列满足特定性质的二项树组成。合并操作是通过合并这些二项树来实现的,时间复杂度也是 \( O(\log n) \)。 160 | 161 | ### 合并操作的实现 162 | 163 | 合并操作是可并堆的核心,其实现通常依赖于特定类型的堆的结构。例如,在左堆或斜堆中,合并操作通常涉及到比较根节点的值,然后递归地合并子堆。在二项堆中,合并则是通过合并相同大小的二项树来实现的。 164 | 165 | ### 可并堆的使用场景 166 | 167 | 可并堆在需要频繁合并堆的场景中非常有用,如图算法、优先队列的合并等。它们提供了一种比传统二叉堆更高效的合并机制,尤其是在处理大量元素时。 168 | 169 | ## 最大最小堆(Min-Max Heap)& 最小最大堆(Max-Min Heap) 170 | 171 | ### 两者的基本概念 172 | 173 | 最小最大堆(Min-Max Heap)和最大最小堆(Max-Min Heap)是两种特殊的堆结构,它们结合了最小堆和最大堆的特性,能够同时高效地获取堆中的最小值和最大值。 174 | 175 | ### 核心特性 176 | 177 | 1. **完全二叉树**:都是完全二叉树结构。 178 | 2. **交替层次最小/最大属性**: 179 | - 最小最大堆:偶数层(包括根层,第0层)的节点小于其所有后代,奇数层的节点大于其所有后代。 180 | - 最大最小堆:与最小最大堆相反,偶数层的节点大于其所有后代,奇数层的节点小于其所有后代。 181 | 182 | ![Min-Max Heap](images/Min-Max%20Heap.png) 183 | 184 | ### 两者的基本操作 185 | 186 | 1. **插入(Insert)**:插入到末尾,然后上调,可能涉及跨层比较。 187 | 2. **查询最小/最大元素(PeekMin/PeekMax)**: 188 | - 最小最大堆:最小元素在根,最大元素在根的子节点之一。 189 | - 最大最小堆:最大元素在根,最小元素在根的子节点之一。 190 | 3. **删除最小/最大元素(ExtractMin/ExtractMax)**:将末尾元素移至相应位置,然后下调。 191 | 192 | ### 两者的时间复杂度 193 | 194 | - **插入和删除操作**:均为 \( O(\log n) \)。 195 | 196 | ### 两者的应用场景 197 | 198 | 适用于需要同时快速访问和删除最小值和最大值的情况,如某些优先队列应用。这两种堆结构提供了在同一数据结构中处理最小值和最大值操作的灵活性。 199 | 200 | ## 对顶堆(Two-Ended Heap) 201 | 202 | ### 对顶堆的基本概念 203 | 204 | 对顶堆(Two-Ended Heap)是一种特殊的数据结构,由一个最大堆和一个最小堆组成,主要用于高效地解决第 \( k \) 大或第 \( k \) 小的问题。 205 | 206 | ### 对顶堆的核心特性 207 | 208 | 1. **两个堆的结构**:由一个最大堆和一个最小堆组成,最大堆维护最小的 \( k \) 个元素,最小堆维护剩下的元素。 209 | 2. **形象比喻**:可以想象为两个三角形的顶点对顶点扣在一起。 210 | 211 | ![Two-Ended Heap](images/Two-Ended%20Heap.png) 212 | 213 | ### 对顶堆的基本操作 214 | 215 | 1. **获取第 \( k \) 小的元素**:最大堆的堆顶元素即是第 \( k \) 小的元素。 216 | 2. **插入元素**: 217 | - 如果元素小于最大堆的堆顶元素,插入到最大堆中。 218 | - 如果元素大于最大堆的堆顶元素,插入到最小堆中。 219 | - 保持两个堆的大小平衡(可能需要移动堆顶元素)。 220 | 3. **删除元素**: 221 | - 如果元素在最大堆中,从最大堆删除。 222 | - 如果元素在最小堆中,从最小堆删除。 223 | - 保持两个堆的大小平衡。 224 | 225 | ### 对顶堆的应用场景 226 | 227 | 对顶堆适用于需要同时处理最小值和最大值的情况,尤其是对动态数据集进行第 \( k \) 大或第 \( k \) 小元素查询时非常有效。例如,在数据流中寻找中位数或其他顺序统计量时,对顶堆提供了一个既高效又灵活的解决方案。 228 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Linear-Structure/Double Linked List Implementation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | struct ListNode { 6 | int data; 7 | ListNode* prev; 8 | ListNode* next; 9 | 10 | ListNode(int x) : data(x), prev(nullptr), next(nullptr) {} 11 | }; 12 | 13 | // 插入新节点 14 | void InsertNode(ListNode*& head, ListNode*& tail, ListNode* position, int value) { 15 | ListNode* newNode = new ListNode(value); 16 | 17 | if (head == nullptr) { 18 | head = newNode; 19 | tail = newNode; 20 | // 如果链表为空,新节点成为头节点和尾节点 21 | } else if (position == nullptr) { 22 | newNode->next = head; 23 | head->prev = newNode; 24 | head = newNode; 25 | // 如果指定位置为空,将新节点插入到链表头部 26 | } else { 27 | newNode->next = position->next; 28 | newNode->prev = position; 29 | // 在指定位置之后插入新节点 30 | if (position->next != nullptr) { 31 | position->next->prev = newNode; 32 | } 33 | position->next = newNode; 34 | 35 | // 如果在尾部插入,更新尾节点 36 | if (position == tail) 37 | { 38 | tail = newNode; 39 | } 40 | } 41 | 42 | } 43 | 44 | // 删除旧节点 45 | void DeleteNode(ListNode*& head, ListNode*& tail, ListNode* node) { 46 | if (node == nullptr) return; 47 | 48 | if (node->prev != nullptr) { 49 | node->prev->next = node->next; 50 | } else { 51 | head = node->next; 52 | } 53 | 54 | if (node->next != nullptr) { 55 | node->next->prev = node->prev; 56 | } else { 57 | tail = node->prev; 58 | } 59 | 60 | delete node; 61 | } 62 | 63 | void PrintList(ListNode* head) { 64 | ListNode* current = head; 65 | while (current != nullptr) { 66 | cout << current->data << " "; 67 | current = current->next; 68 | } 69 | cout << endl; 70 | } 71 | 72 | int main(){ 73 | cout << "请输入双向链表元素,输入-1结束: "; 74 | int value; 75 | ListNode* head = nullptr; 76 | ListNode* tail = nullptr; 77 | 78 | while (cin >> value) 79 | { 80 | if (value == -1){ 81 | break; 82 | } 83 | if (head == nullptr){ 84 | head = new ListNode(value); 85 | tail = head; 86 | } else { 87 | InsertNode(head, tail, tail, value); 88 | } 89 | } 90 | 91 | cout << "当前双向链表:"; 92 | PrintList(head); 93 | 94 | InsertNode(head, tail, head->next, 9); 95 | cout << "当前双向链表:"; 96 | PrintList(head); 97 | 98 | DeleteNode(head, tail, tail->prev); 99 | cout << "当前双向链表:"; 100 | PrintList(head); 101 | 102 | system("pause"); 103 | return 0; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Linear-Structure/Find Kth Node From Bottom (Double Pointers Method).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct ListNode{ 5 | int data; 6 | ListNode* next; 7 | 8 | ListNode(int x) : data(x), next(nullptr) {} 9 | }; 10 | 11 | ListNode* FindKthNodeFromBottom(ListNode* head, int k){ 12 | if (head == nullptr || k <= 0){ 13 | return nullptr; 14 | } 15 | 16 | ListNode* fast = head; 17 | ListNode* slow = head; 18 | 19 | // 移动fast指针,使其与slow指针之间相隔k个节点 20 | for (int i = 0; i < k; ++i){ 21 | if (fast == nullptr){ 22 | return nullptr; // 预防k超出链表长度这一情况 23 | } 24 | fast = fast->next; 25 | } 26 | 27 | // 同时移动fast和slow,直到fast到达链表末尾 28 | while (fast != nullptr){ 29 | fast = fast->next; 30 | slow = slow->next; 31 | } 32 | 33 | return slow; // slow即为所求 34 | } 35 | 36 | void PrintList(ListNode* head){ 37 | ListNode* current = head; 38 | while (current != nullptr){ 39 | cout << current->data << " "; 40 | current = current->next; 41 | } 42 | cout << endl; 43 | } 44 | 45 | int main(){ 46 | cout << "请输入链表元素,输入-1结束: "; 47 | int value; 48 | ListNode* head = nullptr; 49 | ListNode* bottom = nullptr; 50 | 51 | while (cin >> value) { 52 | if (value == -1){ 53 | break; 54 | } 55 | 56 | ListNode* newNode = new ListNode(value); 57 | if (head == nullptr){ 58 | head = newNode; 59 | bottom = newNode; 60 | } 61 | else{ 62 | bottom->next = newNode; 63 | bottom = newNode; 64 | } 65 | } 66 | 67 | // 显示当前链表 68 | cout << "当前链表情况: "; 69 | PrintList(head); 70 | 71 | // 接受用户输入k值 72 | int k; 73 | cout << "你想要查找倒数第几个元素?"; 74 | cin >> k; 75 | 76 | // 查找倒数第K个节点 77 | ListNode* result = FindKthNodeFromBottom(head, k); 78 | if (result != nullptr){ 79 | cout << "你想查到的元素的值为:" << result->data << endl; 80 | }else { 81 | cout << "对不起,你想查找的元素不存在哦~" << endl; 82 | } 83 | 84 | // 收尾工作,清理链表内存 85 | while (head != nullptr){ 86 | ListNode* temp = head; 87 | head = head->next; 88 | delete temp; 89 | } 90 | 91 | system("pause"); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Linear-Structure/Find Kth Node From Bottom (Single Pointer Method).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct ListNode { 5 | int data; 6 | ListNode* next; 7 | 8 | ListNode(int x) : data(x), next(nullptr) {} 9 | }; 10 | 11 | // 查找单链表中倒数第k个节点的函数 12 | ListNode* FindKthNodeFromBottom(ListNode* head, int k){ 13 | int count = 0; 14 | ListNode* current = head; 15 | 16 | // 第一次遍历计算链表长度 17 | while (current != nullptr){ 18 | count++; 19 | current = current->next; 20 | } 21 | 22 | // 检查k的有效性 23 | if (k > count || k <= 0){ 24 | return nullptr; 25 | } 26 | 27 | // 第二次遍历 28 | current = head; 29 | for (int i = 0; i < count - k; ++i){ 30 | current = current->next; 31 | } 32 | 33 | return current; 34 | } 35 | 36 | // 写一个显示链表的函数 37 | void PrintList(ListNode* head){ 38 | ListNode* current = head; 39 | while (current != nullptr){ 40 | cout << current->data << " "; 41 | current = current->next; 42 | } 43 | cout << endl; 44 | } 45 | 46 | int main(){ 47 | cout << "请输入链表元素,输入-1结束: "; 48 | int value; 49 | ListNode* head = nullptr; 50 | ListNode* bottom = nullptr; 51 | 52 | while (cin >> value) { 53 | if (value == -1){ 54 | break; 55 | } 56 | 57 | ListNode* newNode = new ListNode(value); 58 | if (head == nullptr){ 59 | head = newNode; 60 | bottom = newNode; 61 | } 62 | else{ 63 | bottom->next = newNode; 64 | bottom = newNode; 65 | } 66 | } 67 | 68 | // 显示当前链表 69 | cout << "当前链表情况: "; 70 | PrintList(head); 71 | 72 | // 接受用户输入k值 73 | int k; 74 | cout << "你想要查找倒数第几个元素?"; 75 | cin >> k; 76 | 77 | // 查找倒数第K个节点 78 | ListNode* result = FindKthNodeFromBottom(head, k); 79 | if (result != nullptr){ 80 | cout << "你想查到的元素的值为:" << result->data << endl; 81 | }else { 82 | cout << "对不起,你想查找的元素不存在哦~" << endl; 83 | } 84 | 85 | // 收尾工作,清理链表内存 86 | while (head != nullptr){ 87 | ListNode* temp = head; 88 | head = head->next; 89 | delete temp; 90 | } 91 | 92 | system("pause"); 93 | return 0; 94 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Linear-Structure/Linked List Implemented with Pointers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 定义元素类型,这里假设元素类型为int 5 | typedef int ElemType; 6 | 7 | // 定义链表的节点 8 | struct ListNode { 9 | ElemType data; // 数据域 10 | ListNode* next; // 指针域,指向下一个节点 11 | }; 12 | 13 | // 定义链表 14 | struct LinkList { 15 | ListNode* head; // 指向链表的头节点 16 | int length; // 链表的长度 17 | 18 | // 构造函数 19 | LinkList() : head(nullptr), length(0) {} 20 | 21 | // 初始化链表 22 | void InitList() { 23 | head = new ListNode(); // 创建头节点 24 | head->next = nullptr; // 初始化为空链表 25 | length = 0; 26 | } 27 | 28 | // 销毁链表 29 | void DestroyList() { 30 | ListNode* current = head; 31 | while (current != nullptr) { 32 | ListNode* temp = current; 33 | current = current->next; 34 | delete temp; 35 | } 36 | head = nullptr; 37 | length = 0; 38 | } 39 | 40 | // 清空链表 41 | void Clear() { 42 | DestroyList(); 43 | InitList(); 44 | } 45 | 46 | // 判断链表是否为空 47 | bool IsEmpty() const { 48 | return length == 0; 49 | } 50 | 51 | // 获取链表的长度 52 | int Length() const { 53 | return length; 54 | } 55 | 56 | // 获取链表第i个位置的元素 57 | bool Get(int i, ElemType& e) { 58 | if (i < 1 || i > length) return false; // 检查索引有效性 59 | ListNode* current = head->next; // 从第1个元素开始 60 | for (int k = 1; k < i; ++k) { // 移动到第i个元素 61 | current = current->next; 62 | } 63 | e = current->data; // 获取数据 64 | return true; 65 | } 66 | 67 | // 在链表第i个位置插入新元素 68 | bool Insert(int i, ElemType e) { 69 | if (i < 1 || i > length + 1) return false; // 检查索引有效性 70 | ListNode* current = head; 71 | for (int k = 1; k < i; ++k) { // 移动到第i个元素的前驱 72 | current = current->next; 73 | } 74 | ListNode* newNode = new ListNode(); // 创建新节点 75 | newNode->data = e; 76 | newNode->next = current->next; 77 | current->next = newNode; 78 | length++; 79 | return true; 80 | } 81 | 82 | // 删除链表第i个位置的元素 83 | bool Remove(int i) { 84 | if (i < 1 || i > length) return false; // 检查索引有效性 85 | ListNode* current = head; 86 | for (int k = 1; k < i; ++k) { // 移动到第i个元素的前驱 87 | current = current->next; 88 | } 89 | ListNode* toDelete = current->next; // 找到要删除的节点 90 | current->next = toDelete->next; 91 | delete toDelete; 92 | length--; 93 | return true; 94 | } 95 | }; 96 | 97 | int main() { 98 | LinkList list; // 创建链表对象 99 | list.InitList(); // 初始化链表 100 | 101 | // 插入元素 102 | list.Insert(1, 10); 103 | list.Insert(2, 20); 104 | 105 | int element; 106 | if(list.Get(2, element)) { 107 | cout << "Element at position 2 is: " << element << endl; 108 | } 109 | 110 | list.DestroyList(); // 销毁链表 111 | 112 | system("pause"); 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Linear-Structure/Reverse the Linked List (Rearrange Pointers).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | struct ListNode 6 | { 7 | int data; 8 | ListNode* next; 9 | 10 | ListNode(int x) : data(x), next(nullptr) {} 11 | }; 12 | 13 | ListNode* ReverseList(ListNode* head){ 14 | ListNode* prev = nullptr; 15 | ListNode* current = head; 16 | ListNode* next = nullptr; 17 | 18 | while (current != nullptr){ 19 | next = current->next; // 保存当前节点的下一个节点 20 | 21 | current->next = prev; // 将当前节点的next指向前一个节点 22 | 23 | prev = current; // 移动prev到当前节点 24 | current = next; // 移动current到下一节点 25 | } 26 | 27 | head = prev; // 更新头指针指向新的头节点 28 | return head; 29 | } 30 | 31 | void PrintList(ListNode* head){ 32 | ListNode* current = head; 33 | while (current != nullptr){ 34 | cout << current->data << " "; 35 | current = current->next; 36 | } 37 | cout << endl; 38 | } 39 | 40 | int main() 41 | { 42 | cout << "请输入链表元素,输入-1结束: "; 43 | int value; 44 | ListNode* head = nullptr; 45 | ListNode* tail = nullptr; 46 | ListNode* newHead = nullptr; 47 | 48 | while (cin >> value){ 49 | if (value == -1){ 50 | break; 51 | } 52 | 53 | ListNode* newNode = new ListNode(value); 54 | if (head == nullptr){ 55 | head = newNode; 56 | tail = newNode; 57 | } 58 | else{ 59 | tail->next = newNode; 60 | tail = newNode; 61 | } 62 | } 63 | 64 | cout << "显示当前链表" << endl; 65 | PrintList(head); 66 | 67 | newHead = ReverseList(head); 68 | cout << "显示翻转后的链表" << endl; 69 | PrintList(newHead); 70 | 71 | system("pause"); 72 | return 0; 73 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Linear-Structure/Reverse the Linked List (delete&insert).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct ListNode{ 5 | int data; 6 | ListNode* next; 7 | 8 | ListNode(int x) : data(x), next(nullptr) {} 9 | }; 10 | 11 | ListNode* ReverseList(ListNode* head){ 12 | ListNode* newHead = nullptr; 13 | ListNode* temp; 14 | 15 | while (head != nullptr) 16 | { 17 | temp = head; // 从原链表中删除头节点 18 | head = head->next; // 更新原链表中的头指针 19 | 20 | // 将temp节点插入到新链表的头部 21 | temp->next = newHead; 22 | newHead = temp; 23 | } 24 | 25 | return newHead; 26 | } 27 | 28 | void PrintList (ListNode* head){ 29 | ListNode* current = head; 30 | while (current != nullptr) 31 | { 32 | cout << current->data << " "; 33 | current = current->next; 34 | } 35 | cout << endl; 36 | 37 | } 38 | 39 | int main(){ 40 | cout << "请输入链表元素,输入-1结束: "; 41 | int value; 42 | ListNode* head = nullptr; 43 | ListNode* bottom = nullptr; 44 | ListNode* newHead = nullptr; 45 | 46 | while (cin >> value){ 47 | if (value == -1) 48 | { 49 | break; 50 | } 51 | 52 | ListNode* newNode = new ListNode(value); 53 | if (head == nullptr){ 54 | head = newNode; 55 | bottom = newNode; 56 | } 57 | else{ 58 | bottom->next = newNode; 59 | bottom = newNode; 60 | } 61 | } 62 | 63 | cout << "显示当前链表" << endl; 64 | PrintList(head); 65 | 66 | newHead = ReverseList(head); 67 | cout << "显示翻转后的链表" << endl; 68 | PrintList(newHead); 69 | 70 | system("pause"); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Linear-Structure/Sequential List Implemented with Arrays.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 定义最大容量 5 | const int MAX_SIZE = 100; 6 | 7 | // 定义顺序表的结构体 8 | template 9 | struct SeqList { 10 | ElemType data[MAX_SIZE]; // 静态数组存储元素 11 | int length; // 当前顺序表的长度 12 | 13 | // 构造函数 14 | SeqList() : length(0) {} 15 | 16 | // 初始化顺序表 17 | void InitList() { 18 | length = 0; 19 | } 20 | 21 | // 插入元素,位置i,元素值e 22 | bool Insert(int i, ElemType e) { 23 | if (length >= MAX_SIZE || i < 1 || i > length + 1) { 24 | return false; 25 | } 26 | for (int j = length; j >= i; j--) { 27 | data[j] = data[j - 1]; 28 | }// 从最后一个元素开始,依次向后移动一个位置 29 | data[i - 1] = e; 30 | length++; 31 | return true; 32 | } 33 | 34 | // 删除元素,位置i 35 | bool Remove(int i) { 36 | if (i < 1 || i > length) { 37 | return false; 38 | } 39 | for (int j = i; j < length; j++) { 40 | data[j - 1] = data[j]; 41 | }// 从位置i开始,依次向前移动一个位置 42 | length--; 43 | return true; 44 | } 45 | 46 | // 获取元素,位置i 47 | bool Get(int i, ElemType e) { 48 | if (i < 1 || i > length) { 49 | return false; 50 | } 51 | e = data[i - 1]; 52 | return true; 53 | } 54 | 55 | // 获取元素e的位置 56 | int Locate(ElemType e) { 57 | for (int i = 0; i < length; i++) { 58 | if (data[i] == e) { 59 | return i + 1; 60 | } 61 | } 62 | return 0; 63 | } 64 | 65 | // 翻转顺序表 66 | void Reverse() { 67 | for (int i = 0; i < length / 2; i++) { 68 | ElemType temp = data[i]; 69 | data[i] = data[length - i - 1]; 70 | data[length - i - 1] = temp; 71 | } 72 | } 73 | 74 | // 打印顺序表所有元素 75 | void PrintList() { 76 | for (int i = 0; i < length; i++) { 77 | cout << data[i] << " "; 78 | } 79 | cout << endl; 80 | } 81 | }; 82 | 83 | int main() { 84 | SeqList list; // 创建顺序表实例 85 | list.InitList(); // 初始化顺序表 86 | 87 | // 测试插入 88 | list.Insert(1, 10); 89 | list.Insert(2, 20); 90 | list.Insert(3, 30); 91 | list.Insert(4, 40); 92 | list.PrintList(); 93 | 94 | // 测试删除 95 | list.Remove(1); 96 | list.PrintList(); 97 | list.Remove(3); 98 | list.PrintList(); 99 | 100 | // 测试翻转 101 | list.Reverse(); 102 | list.PrintList(); 103 | 104 | // 测试获取 105 | int elem; 106 | if (list.Get(1, elem)) { 107 | cout << "Element at position 1 is: " << elem << endl; 108 | } else { 109 | cout << "Get operation failed!" << endl; 110 | } 111 | 112 | // 测试定位 113 | int pos = list.Locate(30); 114 | if (pos != 0){ 115 | cout << "Element 30 is located at " << pos << endl; 116 | } 117 | else { 118 | cout << "Element 30 is not found!" << endl; 119 | } 120 | 121 | system("pause"); 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Queue/Linked Queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template 6 | class LinkedQueue { 7 | private: 8 | struct Node { 9 | T data; 10 | Node* next; 11 | 12 | Node(T data, Node* next = nullptr) : data(data), next(next) {} 13 | }; 14 | 15 | Node* front; 16 | Node* rear; 17 | 18 | public: 19 | LinkedQueue() : front(nullptr), rear(nullptr) {} 20 | 21 | ~LinkedQueue() { 22 | while (front != nullptr) { 23 | Dequeue(); 24 | } 25 | } 26 | 27 | void Enqueue(const T& item) { 28 | Node* node = new Node(item); 29 | if (IsEmpty()) { 30 | front = rear = node; 31 | } else { 32 | rear->next = node; 33 | rear = node; 34 | } 35 | } 36 | 37 | void Dequeue() { 38 | if (IsEmpty()) { 39 | cout << "Queue is empty" << endl; 40 | } 41 | Node* temp = front; 42 | front = front->next; 43 | if (front == nullptr) { 44 | rear = nullptr; 45 | } 46 | delete temp; 47 | } 48 | 49 | T Front() const { 50 | if (IsEmpty()) { 51 | cout << "Queue is empty" << endl; 52 | } 53 | return front->data; 54 | } 55 | 56 | bool IsEmpty() const { 57 | return front == nullptr; 58 | } 59 | }; 60 | 61 | int main() { 62 | LinkedQueue queue; 63 | 64 | queue.Enqueue(1); 65 | queue.Enqueue(2); 66 | queue.Enqueue(3); 67 | 68 | cout << "Front element: " << queue.Front() << endl; 69 | 70 | queue.Dequeue(); 71 | cout << "Front element after dequeue: " << queue.Front() << endl; 72 | 73 | system("pause"); 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Queue/Sequential Queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template 6 | class SequentialQueue { 7 | private: 8 | T data[MAX_SIZE]; 9 | int front; 10 | int rear; 11 | 12 | public: 13 | SequentialQueue() : front(0), rear(0) {} 14 | 15 | void Enqueue(const T& item) { 16 | if ((rear + 1) % MAX_SIZE == front) { 17 | cout << "Queue is full" << endl; 18 | } 19 | data[rear] = item; 20 | rear = (rear + 1) % MAX_SIZE; 21 | } 22 | 23 | void Dequeue() { 24 | if (IsEmpty()) { 25 | cout << "Queue is empty" << endl; 26 | } 27 | front = (front + 1) % MAX_SIZE; 28 | } 29 | 30 | T Front() const { 31 | if (IsEmpty()) { 32 | cout << "Queue is empty" << endl; 33 | } 34 | return data[front]; 35 | } 36 | 37 | bool IsEmpty() const { 38 | return front == rear; 39 | } 40 | 41 | bool IsFull() const { 42 | return (rear + 1) % MAX_SIZE == front; 43 | } 44 | }; 45 | 46 | int main() { 47 | SequentialQueue queue; 48 | 49 | queue.Enqueue(1); 50 | queue.Enqueue(2); 51 | queue.Enqueue(3); 52 | 53 | cout << "Front element: " << queue.Front() << endl; 54 | 55 | queue.Dequeue(); 56 | cout << "Front element after dequeue: " << queue.Front() << endl; 57 | 58 | system("pause"); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Queue/The ADT of Queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template 6 | class Queue { 7 | private: 8 | T data[MAX_SIZE]; 9 | int front; 10 | int rear; 11 | int count; 12 | 13 | public: 14 | // 初始化一个空的队列 15 | Queue() : front(0), rear(0), count(0) {} 16 | 17 | // 销毁队列 18 | ~Queue() {} 19 | 20 | // 清空队列 21 | void Clear() { 22 | front = rear = count = 0; 23 | } 24 | 25 | // 检查队列是否为空 26 | bool IsEmpty() const { 27 | return count == 0; 28 | } 29 | 30 | // 检查队列是否已满 31 | bool IsFull() const { 32 | return count == MAX_SIZE; 33 | } 34 | 35 | // 返回队首元素 36 | T GetFront() const { 37 | if (IsEmpty()) { 38 | cout << "Queue is empty" << endl; 39 | } 40 | return data[front]; 41 | } 42 | 43 | // 入队操作 44 | void EnQueue(const T& item) { 45 | if (IsFull()) { 46 | cout << "Queue is full" << endl; 47 | } 48 | data[rear] = item; 49 | rear = (rear + 1) % MAX_SIZE; 50 | count++; 51 | } 52 | 53 | // 出队操作 54 | void DeQueue() { 55 | if (IsEmpty()) { 56 | cout << "Queue is empty" << endl; 57 | } 58 | front = (front + 1) % MAX_SIZE; 59 | count--; 60 | } 61 | }; 62 | 63 | int main() { 64 | Queue queue; 65 | 66 | queue.EnQueue(1); 67 | queue.EnQueue(2); 68 | queue.EnQueue(3); 69 | 70 | cout << "Front element: " << queue.GetFront() << endl; 71 | 72 | queue.DeQueue(); 73 | cout << "Front element after dequeue: " << queue.GetFront() << endl; 74 | 75 | system("pause"); 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Queue/队列.md: -------------------------------------------------------------------------------- 1 | # 队列(Queue) 2 | 3 | 4 | - [队列(Queue)](#队列queue) 5 | - [初步了解队列](#初步了解队列) 6 | - [队列的定义](#队列的定义) 7 | - [队列的主要元素](#队列的主要元素) 8 | - [队列的溢出](#队列的溢出) 9 | - [队列的主要应用](#队列的主要应用) 10 | - [队列的抽象数据类型](#队列的抽象数据类型) 11 | - [队列的实现方式](#队列的实现方式) 12 | - [顺序队列(Sequential Queue)](#顺序队列sequential-queue) 13 | - [顺序队列的特点](#顺序队列的特点) 14 | - [循环队列的实现方法](#循环队列的实现方法) 15 | - [顺序队列的代码实现](#顺序队列的代码实现) 16 | - [链式队列(Linked Queue)](#链式队列linked-queue) 17 | - [链式队列的特点](#链式队列的特点) 18 | - [链式队列的代码实现](#链式队列的代码实现) 19 | - [顺序队列与链式队列的比较](#顺序队列与链式队列的比较) 20 | - [双端队列(Deque)](#双端队列deque) 21 | - [双端队列的特点](#双端队列的特点) 22 | - [双端队列的特化](#双端队列的特化) 23 | - [队列的应用](#队列的应用) 24 | - [车厢重排问题](#车厢重排问题) 25 | 26 | ## 初步了解队列 27 | 28 | ### 队列的定义 29 | 30 | 队列是一种允许在一端(队尾,rear)进行插入操作,在另一端(队首,front)进行删除操作的线性数据结构。队列的这种操作特性使其成为一种FIFO(先进先出)的数据结构。 31 | 32 | ### 队列的主要元素 33 | 34 | 1. **队首(Front)**:队列的这一端用于移除元素。当队列非空时,可以从队首取出元素。 35 | 2. **队尾(Rear)**:队列的另一端,用于插入元素。新加入的元素总是被放置在队尾。 36 | 37 | ### 队列的溢出 38 | 39 | - 上溢(Overflow) 40 | 尝试向一个已满的队列中添加元素时,在固定大小的队列中尤为常见。 41 | 42 | - 下溢(Underflow) 43 | 尝试从一个空队列中移除元素时。 44 | 45 | - 假溢出(False Overflow) 46 | 顺序队列特有的一个现象,发生在使用数组实现的队列中。当队列前端的空间被清空(即前面的元素已经出队),而后端由于达到数组的物理边界而无法再进行入队操作时,即使数组中还有未使用的空间,也会发生溢出情况。 47 | 48 | ### 队列的主要应用 49 | 50 | - **调度和缓冲**:在操作系统中执行各种调度任务,如CPU调度、打印作业排队等。在网络通信中,作为数据包的缓冲区,帮助控制数据流量和处理网络拥塞。 51 | - **消息队列**:存储待处理的消息,确保按照接收顺序进行处理。 52 | - **邮件队列**:管理待发送或接收的邮件,以维持邮件的处理顺序。 53 | - **数据流管理**:在流媒体、实时数据传输等场景中管理数据包。 54 | - **硬件设备通信**:管理设备间的通信,例如打印机任务队列、硬盘I/O请求队列等。 55 | - **资源管理**:操作系统使用队列进行资源分配和管理,如内存管理、进程管理等。 56 | - **广度优先搜索(BFS)**:在图和树结构的搜索中实现广度优先搜索。 57 | 58 | ## 队列的抽象数据类型 59 | 60 | 1. 数据对象 61 | - 集合 \(\{ a_i | a_i \in \text{ElemSet}, i = 1, 2, \ldots, n, n > 0 \}\) 或空集 \(\Phi\),其中 \(\text{ElemSet}\) 是元素的集合。 62 | 63 | 2. 数据关系 64 | - 队列中的元素之间存在顺序关系 \(\{ | a_i, a_{i+1} \in \text{ElemSet}, i = 0, 1, \ldots, n-2 \}\),表示每个元素 \(a_i\) 都在 \(a_{i+1}\) 之前。 65 | 66 | 3. 基本操作 67 | - `InitQueue(queue)`:初始化一个空的队列 `queue`。 68 | - `DestroyQueue(queue)`:销毁队列 `queue`,释放其占用的所有空间。 69 | - `Clear(queue)`:清空队列 `queue`。 70 | - `IsEmpty(queue)`:如果队列 `queue` 为空,则返回真(true);否则返回假(false)。 71 | - `IsFull(queue)`:如果队列 `queue` 已满,则返回真(true);否则返回假(false)。 72 | - `GetFront(queue)`:返回队列 `queue` 的队首元素,但不改变队首元素。 73 | - `EnQueue(queue, x)`:将元素 `x` 插入队列 `queue`,成为新的队尾。 74 | - `DeQueue(queue)`:将队首元素从队列 `queue` 中删除。 75 | 76 | 4. 代码实现 77 | 78 | 见`The ADT of Queue.cpp`文件。 79 | 80 | ## 队列的实现方式 81 | 82 | ### 顺序队列(Sequential Queue) 83 | 84 | 队列的元素按顺序存储在一块连续的内存空间(通常是数组)中。这种实现方式与顺序栈类似,但遵循的是先进先出(FIFO, First In First Out)的原则。 85 | 86 | #### 顺序队列的特点 87 | 88 | 1. **固定大小**:顺序队列通常有固定的容量,这个容量在队列初始化时确定。 89 | 2. **连续存储**:队列中的元素在内存中连续存放。 90 | 3. **队首和队尾指针**:使用两个指针或索引来标识队列的队首(front)和队尾(rear)。 91 | 4. **循环使用空间**:为了有效利用空间,顺序队列通常作为**循环队列**实现,当达到数组的末尾时,如果前面有空闲空间,则从数组的开始处继续使用空间。 92 | 93 | #### 循环队列的实现方法 94 | 95 | | 方法 | 队空判定 | 队满判定 | 特点 | 96 | | ------------------ | ------------------ | ---------------------------------- | ------------------------------------------------------------ | 97 | | 虚指针法 | `front == rear` | `(rear + 1) % M == front` | 使用一个位置来区分队满和队空,牺牲了一个存储空间。 | 98 | | 实指针法 | `front == rear` | `(rear + 2) % M == front` | 保留一个空位作为队满的标志,更充分地利用空间。 | 99 | | 额外标记法 | `front == rear` 且 `count == 0` | `front == rear` 且 `count == MAX_SIZE` | 使用额外标记(如计数器)区分队满和队空,完全利用所有空间,逻辑稍复杂。 | 100 | 101 | #### 顺序队列的代码实现 102 | 103 | 使用虚指针法,见`Sequential Queue.cpp`文件。 104 | 105 | ### 链式队列(Linked Queue) 106 | 107 | 队列的元素不是连续存储的,而是每个元素通过指针链接在一起。这种实现方式相比于顺序队列(使用数组实现的队列),具有更好的扩展性和灵活性。 108 | 109 | #### 链式队列的特点 110 | 111 | 1. **动态大小**:链式队列的大小不是固定的,可以根据需要动态增长或减少。 112 | 2. **非连续存储**:队列中的元素通过指针链接,每个元素(节点)包含数据和指向下一个节点的指针。 113 | 3. **队首和队尾指针**:使用两个指针分别指向队列的队首(front)和队尾(rear)。 114 | 4. **空间利用**:链式队列按需分配空间,不会预先分配未使用的空间,因此具有高效的空间利用率。 115 | 5. **操作复杂度**:入队(Enqueue)和出队(Dequeue)操作的时间复杂度都是 \(O(1)\)。 116 | 117 | #### 链式队列的代码实现 118 | 119 | 见`Linked Queue.cpp`文件。 120 | 121 | ### 顺序队列与链式队列的比较 122 | 123 | | 特性 | 顺序队列 | 链式队列 | 124 | | -------------- | ------------------------------------------------------ | ------------------------------------------------------ | 125 | | **内存分配** | 静态分配:通常需要预先分配固定大小的数组 | 动态分配:根据需要分配节点,每个元素独立分配 | 126 | | **容量限制** | 有固定的容量,超出容量时需处理溢出问题 | 无固定容量,理论上受限于系统内存 | 127 | | **存储方式** | 连续存储:所有元素在内存中连续存放 | 非连续存储:元素通过指针链接,分散存储 | 128 | | **空间效率** | 可能有空间浪费(预分配但未使用的空间),或面临扩展问题 | 高空间利用率,按需分配,无空间浪费 | 129 | | **时间效率** | 入队和出队操作通常较快(直接索引) | 入队操作快(尾部插入),出队操作也快(头部删除) | 130 | | **实现复杂度** | 相对简单,特别是不涉及循环逻辑时 | 略高,需要处理节点的动态分配和链接 | 131 | | **适用场景** | 当队列大小可预知且变动不大时 | 当需要频繁的动态调整队列大小时 | 132 | 133 | ### 双端队列(Deque) 134 | 135 | 双端队列(Double-Ended Queue,简称 Deque)是一种特殊的队列,它允许在队列的两端(前端和后端)进行插入(入队)和删除(出队)操作。双端队列结合了栈和队列的特性,使得元素可以在两端被加入或移除。 136 | 137 | #### 双端队列的特点 138 | 139 | 1. **两端操作**:支持在队列的前端和后端进行元素的插入和删除。 140 | 2. **灵活性**:由于支持两端操作,双端队列可以作为普通队列或栈使用。 141 | 3. **实现方式**:可以通过数组或链表实现,循环数组实现的双端队列特别常见。 142 | 143 | #### 双端队列的特化 144 | 145 | - 超队列(Super Queue) 146 | 删除受限:在超队列中,删除操作仅限于一端进行。这意味着,尽管可以从队列的任一端插入元素,但删除元素只能从固定的一端执行。 147 | 148 | - 超栈(Super Stack) 149 | 插入受限:在超栈中,插入操作仅限于一端进行。尽管可以从两端删除元素,但插入元素只能在固定的一端执行。 150 | 151 | ## 队列的应用 152 | 153 | ### 车厢重排问题 154 | 155 | 见`Lab 1_5 车厢重排问题.cpp`文件。 156 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Stack/Linked Stack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template 6 | class LinkedStack { 7 | private: 8 | struct Node { 9 | T data; 10 | Node* next; 11 | 12 | Node(T data, Node* next = nullptr) : data(data), next(next) {} 13 | }; 14 | 15 | Node* top; // 栈顶指针 16 | 17 | public: 18 | LinkedStack() : top(nullptr) {} 19 | 20 | ~LinkedStack() { 21 | while (!IsEmpty()) { 22 | Pop(); 23 | } 24 | } 25 | 26 | void Push(const T& item) { 27 | top = new Node(item, top); 28 | } 29 | 30 | void Pop() { 31 | if (IsEmpty()) { 32 | cout << "Stack Underflow" << endl; 33 | return; 34 | } 35 | Node* nodeToDelete = top; 36 | top = top->next; 37 | delete nodeToDelete; 38 | } 39 | 40 | T Top() const { 41 | if (IsEmpty()) { 42 | cout << "Stack is Empty" << endl; 43 | } 44 | return top->data; 45 | } 46 | 47 | bool IsEmpty() const { 48 | return top == nullptr; 49 | } 50 | }; 51 | 52 | int main() { 53 | LinkedStack stack; 54 | 55 | stack.Push(1); 56 | stack.Push(2); 57 | stack.Push(3); 58 | 59 | cout << "Top element: " << stack.Top() << endl; 60 | 61 | stack.Pop(); 62 | cout << "Top element after pop: " << stack.Top() << endl; 63 | 64 | system("pause"); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Stack/Sequential Stack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template 6 | class SequentialStack { 7 | private: 8 | T data[MAX_SIZE]; // 存储栈元素的数组 9 | int top; // 栈顶索引 10 | 11 | public: 12 | // 构造函数,初始化空栈 13 | SequentialStack() : top(-1) {} 14 | 15 | // 压栈操作 16 | void Push(const T& item) { 17 | if (IsFull()) { 18 | cout << "Stack Overflow" << endl; 19 | return; 20 | } 21 | data[++top] = item; 22 | } 23 | 24 | // 出栈操作 25 | void Pop() { 26 | if (IsEmpty()) { 27 | cout << "Stack Underflow" << endl; 28 | return; 29 | } 30 | top--; 31 | } 32 | 33 | // 读取栈顶元素 34 | T Top() const { 35 | if (IsEmpty()) { 36 | throw out_of_range("Stack is Empty"); 37 | } 38 | return data[top]; 39 | } 40 | 41 | // 检查栈是否为空 42 | bool IsEmpty() const { 43 | return top == -1; 44 | } 45 | 46 | // 检查栈是否已满 47 | bool IsFull() const { 48 | return top == MAX_SIZE - 1; 49 | } 50 | }; 51 | 52 | int main() { 53 | SequentialStack stack; 54 | 55 | // 压栈操作 56 | stack.Push(1); 57 | stack.Push(2); 58 | stack.Push(3); 59 | 60 | // 读取栈顶元素 61 | cout << "Top element: " << stack.Top() << endl; 62 | 63 | // 出栈操作 64 | stack.Pop(); 65 | cout << "Top element after pop: " << stack.Top() << endl; 66 | 67 | // 尝试导致栈溢出 68 | for (int i = 0; i < 10; i++) { 69 | stack.Push(i); 70 | } 71 | 72 | system("pause"); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Stack/The ADT of Stack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | template 7 | class Stack { 8 | private: 9 | vector elements; 10 | 11 | public: 12 | // 初始化一个空的栈 13 | Stack() {} 14 | 15 | // 销毁栈 16 | ~Stack() {} 17 | 18 | // 清空栈 19 | void Clear() { 20 | elements.clear(); 21 | } 22 | 23 | // 检查栈是否为空 24 | bool IsEmpty() const { 25 | return elements.empty(); 26 | } 27 | 28 | // 检查栈是否已满(对于基于动态数组的实现,这个函数其实是不必要的) 29 | bool IsFull() const { 30 | return elements.size() == elements.max_size(); 31 | } 32 | 33 | // 返回栈顶元素 34 | T Top() const { 35 | if (!IsEmpty()) { 36 | return elements.back(); 37 | } else { 38 | cout << "Stack is empty" << endl; 39 | } 40 | } 41 | 42 | // 入栈操作 43 | void Push(const T& item) { 44 | elements.push_back(item); 45 | } 46 | 47 | // 出栈操作 48 | void Pop() { 49 | if (!IsEmpty()) { 50 | elements.pop_back(); 51 | } else { 52 | cout << "Stack is empty" << endl; 53 | } 54 | } 55 | }; 56 | 57 | int main() { 58 | Stack intStack; 59 | 60 | intStack.Push(10); 61 | intStack.Push(20); 62 | intStack.Push(30); 63 | 64 | cout << "The top element is: " << intStack.Top() << endl; 65 | 66 | intStack.Pop(); 67 | cout << "After popping, the top element is: " << intStack.Top() << endl; 68 | 69 | system("pause"); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/Stack/栈.md: -------------------------------------------------------------------------------- 1 | # 栈(Stack) 2 | 3 | 4 | - [栈(Stack)](#栈stack) 5 | - [初步了解栈](#初步了解栈) 6 | - [栈的定义](#栈的定义) 7 | - [栈的主要元素](#栈的主要元素) 8 | - [栈的主要应用](#栈的主要应用) 9 | - [栈的抽象数据类型](#栈的抽象数据类型) 10 | - [栈的实现方式](#栈的实现方式) 11 | - [顺序栈(Sequential Stack)](#顺序栈sequential-stack) 12 | - [顺序栈的定义](#顺序栈的定义) 13 | - [顺序栈的特点](#顺序栈的特点) 14 | - [顺序栈栈顶的确定](#顺序栈栈顶的确定) 15 | - [顺序栈的上溢和下溢问题](#顺序栈的上溢和下溢问题) 16 | - [顺序栈的变种](#顺序栈的变种) 17 | - [顺序栈的代码实现](#顺序栈的代码实现) 18 | - [链式栈(Linked Stack)](#链式栈linked-stack) 19 | - [链式栈的定义](#链式栈的定义) 20 | - [链式栈的特点](#链式栈的特点) 21 | - [链式栈的代码实现](#链式栈的代码实现) 22 | - [顺序栈与链式栈的比较](#顺序栈与链式栈的比较) 23 | - [栈的应用](#栈的应用) 24 | - [括号语句的判定](#括号语句的判定) 25 | - [后缀表达式求值](#后缀表达式求值) 26 | 27 | ## 初步了解栈 28 | 29 | ### 栈的定义 30 | 31 | 栈(Stack)是一种特殊的线性数据结构,它遵循**后进先出**(LIFO, Last In First Out)的原则。这意味着最后添加进栈的元素将是第一个被移除的。栈限制了数据的访问方式,只能在**一个端口**(栈顶)进行数据的插入和删除操作。 32 | 33 | ### 栈的主要元素 34 | 35 | 1. **栈顶(Top)**:栈的操作都在栈顶进行。新元素添加到栈顶,被称为“入栈”或“压栈”(push)。当从栈中移除元素时,也是从栈顶移除,这个操作称为“出栈”或“弹出”(pop)。 36 | 37 | 2. **栈底(Bottom)**:栈的另一端称为栈底,它是最先加入栈的元素所在的位置。在栈底的元素会最后被移除。 38 | 39 | 3. **空栈(Empty Stack)**:没有任何元素的栈称为空栈。 40 | 41 | ### 栈的主要应用 42 | 43 | - **进制转换**:利用栈来存储和逆转数字序列。 44 | - **括号匹配**:检查程序中括号是否正确配对。 45 | - **表达式求值**:计算如后缀表达式的值。 46 | - **函数调用**:计算机内部使用栈来处理函数调用,特别是递归函数。 47 | - **深度优先搜索(DFS)**:在图和树的搜索中使用栈来追踪访问路径。 48 | 49 | ## 栈的抽象数据类型 50 | 51 | 1. **数据对象**: 52 | - 集合 \(\{ a_i | a_i \in \text{ElemSet}, i = 1, 2, \ldots, n, n > 0 \}\) 或空集 \(\Phi\)。这里,\(\text{ElemSet}\) 是元素的集合,可以包含任意类型的数据。 53 | 54 | 2. **数据关系**: 55 | - 栈中的元素之间存在有序的线性关系 \(\{ | a_i, a_{i+1} \in \text{ElemSet}, i = 0, 1, \ldots, n-2 \}\)。在这个关系中,每个元素 \(a_i\) 都与其下一个元素 \(a_{i+1}\) 相关联。 56 | 57 | 3. **基本操作**: 58 | - `InitStack(stack)`:初始化一个空栈 `stack`。 59 | - `DestroyStack(stack)`:销毁栈 `stack`,释放其占用的所有空间。 60 | - `Clear(stack)`:清空栈 `stack`。 61 | - `IsEmpty(stack)`:如果栈 `stack` 为空,则返回真(true);否则返回假(false)。 62 | - `IsFull(stack)`:如果栈 `stack` 已满,则返回真(true);否则返回假(false)。 63 | - `Top(stack)`:返回栈 `stack` 的栈顶元素,但不改变栈顶元素。 64 | - `Push(stack, x)`:将元素 `x` 压入栈 `stack`,成为新的栈顶。 65 | - `Pop(stack)`:将栈顶元素从栈 `stack` 中弹出。 66 | 67 | 4. **ADT的C++实现**: 68 | 见`The ADT of Stack.cpp`文件。 69 | 70 | ## 栈的实现方式 71 | 72 | ### 顺序栈(Sequential Stack) 73 | 74 | #### 顺序栈的定义 75 | 76 | 顺序栈是栈的一种实现方式,它使用一段连续的内存空间来存储栈中的元素。这种实现方式通常使用**数组**来完成。在顺序栈中,元素的入栈(push)和出栈(pop)操作都在栈的一端进行,这一端称为“栈顶”。 77 | 78 | #### 顺序栈的特点 79 | 80 | - **固定容量**:顺序栈的大小在初始化时就**固定**了,它由数组的大小决定。 81 | - **连续的内存空间**:所有元素都存储在一块**连续**的内存区域内。 82 | - **高效的访问和操作**:入栈和出栈操作的时间复杂度都是 \(O(1)\),因为只涉及到对数组索引的操作。 83 | - **空间利用率**:由于容量固定,可能存在空间浪费的情况,或者在元素数量超过容量时无法继续入栈。 84 | 85 | #### 顺序栈栈顶的确定 86 | 87 | - **栈顶在数组末尾**:这是最常见的实现方式。栈顶对应于数组的最后一个元素,每次入栈和出栈都在数组的末端进行。 88 | 89 | - **栈顶在数组头处**:这种方式较少见。栈顶对应于数组的第一个元素,这种方式每次入栈和出栈都需要移动栈中的所有元素,效率较低。 90 | 91 | #### 顺序栈的上溢和下溢问题 92 | 93 | - **上溢(Stack Overflow)**:当尝试向一个已经满了的栈中添加元素时,会发生上溢。在顺序栈中,由于容量是固定的,一旦入栈的元素超过这个容量,就会发生上溢。 94 | - **下溢(Stack Underflow)**:当尝试从一个空栈中取出元素时,会发生下溢。由于栈中没有元素可以出栈,这种操作是非法的。 95 | 96 | #### 顺序栈的变种 97 | 98 | 两个栈共用一个数组空间,但是它们在这个空间中的增长方向是相反的。其又分为迎面增长型与底部相连型。 99 | 100 | 1. **迎面增长(Head-To-Head)**:两个栈从数组的两端开始增长,一个栈从数组的起始位置增长,另一个栈从数组的末尾开始增长。 101 | - **优点**:最大限度地利用了数组的空间,它减少了空间的浪费。 102 | - **缺点**:两个栈的总容量是固定的,如果一个栈增长过快,可能会在空间还未充分使用的情况下导致其中一个栈溢出。 103 | - **适应的场景**:适用于预先知道两个栈总容量限制的场景,但不确定各自栈的具体容量需求。 104 | 105 | 2. **底部相连(Back-To-Back)**:这种情况下,两个栈的底部是相连的,它们从中间向两端增长。 106 | - **特点**:两个栈的增长更加灵活,可以更好地应对不确定的栈大小需求。 107 | - **适应的场景**:适用于两个栈的大小变化不确定,需要更灵活分配空间的情况。 108 | 109 | 相比于传统的独立栈结构,这些变种的优势在于**空间利用的效率和灵活性**。在**资源有限**的环境下(如嵌入式系统),这种结构可以更好地利用可用空间。然而,管理这种共享结构也比单个独立栈更复杂,需要更仔细地考虑**栈溢出**和**空间分配**的问题。 110 | 111 | #### 顺序栈的代码实现 112 | 113 | 见`Sequential Stack.cpp`文件。 114 | 115 | ### 链式栈(Linked Stack) 116 | 117 | #### 链式栈的定义 118 | 119 | 链式栈是栈的另一种实现方式,它使用节点(Node)通过指针相连来存储数据。每个节点包含两部分:一部分存储数据元素,另一部分存储指向下一个节点的指针。在链式栈中,栈顶的位置是变化的,而栈底指向一个固定的哨兵节点或为空。 120 | 121 | ![Linked Stack](../images/Linked%20Stack.jpg) 122 | 123 | #### 链式栈的特点 124 | 125 | - **动态大小**:链式栈的大小不是固定的,可以根据需要**动态增长或减少**。 126 | - **非连续存储**:栈中的元素不是连续存储的,而是通过**指针链接**的。 127 | - **高效的操作**:入栈和出栈操作通常都是 \(O(1)\) 的时间复杂度,因为只涉及指针的改变。 128 | - **额外的内存开销**:由于每个元素都需要**额外的空间来存储指针**,因此相对于顺序栈,链式栈的内存开销更大。 129 | 130 | #### 链式栈的代码实现 131 | 132 | 见`Linked Stack.cpp`文件。 133 | 134 | ### 顺序栈与链式栈的比较 135 | 136 | | 特性 | 顺序栈 | 链式栈 | 137 | | -------------- | ---------------------------- | ---------------------------- | 138 | | **内存分配** | 静态分配:固定大小的数组 | 动态分配:根据需要分配节点 | 139 | | **容量限制** | 容量固定 | 容量可变,受系统内存限制 | 140 | | **存储方式** | 连续存储 | 非连续存储 | 141 | | **空间效率** | 可能浪费空间或遇到栈溢出问题 | 更高的空间利用率,但每个元素需要额外存储指针 | 142 | | **时间效率** | 入栈、出栈操作通常较快 | 入栈、出栈操作通常较快 | 143 | | **实现复杂度** | 简单 | 相对复杂 | 144 | | **扩展性** | 受限于初始容量设定 | 根据需要动态扩展 | 145 | | **适用场景** | 当栈的最大元素数量可预知时 | 当栈的大小不确定或频繁变动时 | 146 | 147 | ## 栈的应用 148 | 149 | ### 括号语句的判定 150 | 151 | 见`Hw 4_1 字符串匹配问题.cpp`文件。 152 | 见`Lab 1_2 括号匹配检验.cpp`文件。 153 | 154 | ### 后缀表达式求值 155 | 156 | 见`Hw 4_2 后缀表达式求值.cpp`文件。 157 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/images/Linked Stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Stack&Queue/images/Linked Stack.jpg -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/Create Huffman Tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct HuffmanNode { 8 | int weight; 9 | HuffmanNode *left, *right; 10 | 11 | HuffmanNode(int w) : weight(w), left(nullptr), right(nullptr) {} 12 | 13 | // 重载比较运算符,优先队列需要 14 | bool operator>(const HuffmanNode& other) const { 15 | return weight > other.weight; 16 | } 17 | }; 18 | 19 | HuffmanNode* createHuffmanTree(vector& weights) { 20 | priority_queue, greater<>> pq; 21 | 22 | for (int w : weights) { 23 | pq.push(new HuffmanNode(w)); 24 | } 25 | 26 | while (pq.size() > 1) { 27 | HuffmanNode* left = pq.top(); pq.pop(); 28 | HuffmanNode* right = pq.top(); pq.pop(); 29 | 30 | HuffmanNode* parent = new HuffmanNode(left->weight + right->weight); 31 | parent->left = left; 32 | parent->right = right; 33 | 34 | pq.push(parent); 35 | } 36 | 37 | return pq.top(); 38 | } 39 | 40 | void preOrderPrintHuffmanTree(HuffmanNode* root) { 41 | if (root == nullptr) { 42 | return; 43 | } 44 | 45 | cout << root->weight << " "; 46 | preOrderPrintHuffmanTree(root->left); 47 | preOrderPrintHuffmanTree(root->right); 48 | } 49 | 50 | int main() { 51 | int n; 52 | cin >> n; 53 | vector weights(n); 54 | 55 | for(int i = 0; i < n; ++i) { 56 | cin >> weights[i]; 57 | } 58 | 59 | HuffmanNode* root = createHuffmanTree(weights); 60 | 61 | preOrderPrintHuffmanTree(root); 62 | cout << endl; 63 | 64 | system("pause"); 65 | return 0; 66 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/Odd-Even Tree inOrder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | struct TreeNode 7 | { 8 | int val; 9 | TreeNode *left, *right; 10 | TreeNode(int value, TreeNode* leftTree = nullptr, TreeNode* rightTree = nullptr) : 11 | val(value), left(leftTree), right(rightTree) {} 12 | }; 13 | 14 | bool isOddEvenTree(TreeNode* root) { 15 | if (!root) return true; 16 | queue nodes; 17 | queue levels; 18 | nodes.push(root); 19 | levels.push(1); 20 | 21 | while (!nodes.empty()) { 22 | TreeNode* node = nodes.front(); 23 | int level = levels.front(); 24 | nodes.pop(); 25 | levels.pop(); 26 | 27 | if ((node->val % 2) != (level % 2)) return false; 28 | 29 | if (node->left) { 30 | nodes.push(node->left); 31 | levels.push(level + 1); 32 | } 33 | if (node->right) { 34 | nodes.push(node->right); 35 | levels.push(level + 1); 36 | } 37 | } 38 | return true; 39 | } 40 | 41 | 42 | int main() { 43 | // 构建树 44 | TreeNode *root = new TreeNode(1); 45 | root->left = new TreeNode(2); 46 | root->right = new TreeNode(4); 47 | 48 | root->left->left = new TreeNode(3); 49 | root->left->right = new TreeNode(5); 50 | root->right->left = new TreeNode(7); 51 | root->right->right = new TreeNode(9); 52 | 53 | // 验证是否是奇偶树 54 | bool result = isOddEvenTree(root); 55 | if (result) { 56 | cout << "这是一个奇偶树。" << endl; 57 | } else { 58 | cout << "这不是一个奇偶树。" << endl; 59 | } 60 | 61 | system("pause"); 62 | return 0; 63 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/Odd-Even Tree preOrder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | struct TreeNode 6 | { 7 | int val; 8 | TreeNode* left, * right; 9 | TreeNode(int value, TreeNode* leftTree = nullptr, TreeNode* rightTree = nullptr) : 10 | val(value), left(leftTree), right(rightTree) {} 11 | }; 12 | 13 | bool isOddEvenTree(TreeNode* node, int level) { 14 | if (!node) return true; 15 | if ((node->val % 2) != (level % 2)) return false; 16 | return isOddEvenTree(node->left, level + 1) && isOddEvenTree(node->right, level + 1); 17 | } 18 | 19 | int main() { 20 | // 构建树 21 | TreeNode *root = new TreeNode(1); 22 | root->left = new TreeNode(2); 23 | root->right = new TreeNode(4); 24 | 25 | root->left->left = new TreeNode(3); 26 | root->left->right = new TreeNode(5); 27 | root->right->left = new TreeNode(7); 28 | root->right->right = new TreeNode(9); 29 | 30 | // 验证是否是奇偶树 31 | bool result = isOddEvenTree(root, 1); 32 | if (result) { 33 | cout << "这是一个奇偶树。" << endl; 34 | } else { 35 | cout << "这不是一个奇偶树。" << endl; 36 | } 37 | 38 | system("pause"); 39 | return 0; 40 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/Print Infix Expression.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct TreeNode 5 | { 6 | char data; 7 | TreeNode* left; 8 | TreeNode* right; 9 | 10 | TreeNode(char val) : data(val), left(nullptr), right(nullptr) {} 11 | }; 12 | 13 | void printInfixExpression(TreeNode* tree) { 14 | if (tree == nullptr) return; 15 | 16 | if (tree->left != nullptr) { 17 | cout << "("; 18 | printInfixExpression(tree->left); 19 | cout << ")"; 20 | } 21 | 22 | cout << tree->data; 23 | 24 | if (tree->right != nullptr) { 25 | cout << "("; 26 | printInfixExpression(tree->right); 27 | cout << ")"; 28 | } 29 | } 30 | 31 | void deleteTree(TreeNode* tree) { 32 | if (tree == nullptr) return; 33 | deleteTree(tree->left); 34 | deleteTree(tree->right); 35 | delete tree; 36 | } 37 | 38 | int main() { 39 | // 构建表达式树 40 | TreeNode* root = new TreeNode('+'); 41 | root->left = new TreeNode('9'); 42 | 43 | // 构建右子树 44 | TreeNode* right = new TreeNode('/'); 45 | root->right = right; 46 | 47 | // 构建右子树的左部分 (6 + 3 * 2) 48 | TreeNode* rightLeft = new TreeNode('+'); 49 | right->left = rightLeft; 50 | rightLeft->left = new TreeNode('6'); 51 | TreeNode* rightLeftRight = new TreeNode('*'); 52 | rightLeftRight->left = new TreeNode('3'); 53 | rightLeftRight->right = new TreeNode('2'); 54 | rightLeft->right = rightLeftRight; 55 | 56 | // 构建右子树的右部分 (8 / (5 - 3)) 57 | TreeNode* rightRight = new TreeNode('/'); 58 | right->right = rightRight; 59 | rightRight->left = new TreeNode('8'); 60 | TreeNode* rightRightRight = new TreeNode('-'); 61 | rightRightRight->left = new TreeNode('5'); 62 | rightRightRight->right = new TreeNode('3'); 63 | rightRight->right = rightRightRight; 64 | 65 | printInfixExpression(root); 66 | cout << endl; 67 | 68 | // The output will be: (9)+(((6)+((3)*(2)))/((8)/((5)-(3)))) 69 | 70 | deleteTree(root); 71 | 72 | system("pause"); 73 | return 0; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/Serialization & Deserialization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct TreeNode { 8 | int val; 9 | TreeNode* left, *right; 10 | TreeNode(int value) : val(value), left(nullptr), right(nullptr) {} 11 | }; 12 | 13 | string serialize(TreeNode* root) { 14 | if (root == nullptr) { 15 | return "#,"; 16 | } 17 | return to_string(root->val) + "," + serialize(root->left) + serialize(root->right); 18 | } 19 | 20 | TreeNode* deserialize(stringstream& ss) { 21 | string val; 22 | getline(ss, val, ','); 23 | if (val == "#") 24 | return nullptr; 25 | 26 | TreeNode* node = new TreeNode(stoi(val)); 27 | node->left = deserialize(ss); 28 | node->right = deserialize(ss); 29 | return node; 30 | } 31 | 32 | TreeNode* deserialize(string data) { 33 | stringstream ss(data); 34 | return deserialize(ss); 35 | } 36 | 37 | void printTree(TreeNode* root) { 38 | if (root == nullptr) { 39 | cout << "EMPTY TREE!" << endl; 40 | return; 41 | } 42 | 43 | queue q; 44 | q.push(root); 45 | while (!q.empty()) { 46 | TreeNode* current = q.front(); 47 | q.pop(); 48 | if (current == nullptr) { 49 | cout << "# "; 50 | } else { 51 | cout << current->val << " "; 52 | q.push(current->left); 53 | q.push(current->right); 54 | } 55 | } 56 | } 57 | 58 | int main() { 59 | // 构建二叉树 60 | TreeNode* root = new TreeNode(1); 61 | root->left = new TreeNode(2); 62 | root->right = new TreeNode(3); 63 | root->right->left = new TreeNode(4); 64 | root->right->right = new TreeNode(5); 65 | 66 | // 序列化 67 | string serialized = serialize(root); 68 | cout << "Serialized tree: " << serialized << endl; 69 | 70 | // 反序列化 71 | TreeNode* deserialized = deserialize(serialized); 72 | cout << "Deserialized tree: "; 73 | printTree(deserialized); 74 | cout << endl; 75 | 76 | system("pause"); 77 | return 0; 78 | 79 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/Special OE Tree inOrder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct TreeNode { 8 | int val; 9 | TreeNode *left, *right; 10 | TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 11 | }; 12 | 13 | bool isOddEvenTree(TreeNode* root) { 14 | if (!root) return true; 15 | queue nodes; 16 | nodes.push(root); 17 | int level = 1; 18 | 19 | while (!nodes.empty()) { 20 | int size = nodes.size(); 21 | int prev_value = INT_MIN; 22 | 23 | for (int i = 0; i < size; ++i) { 24 | TreeNode* node = nodes.front(); 25 | nodes.pop(); 26 | 27 | if ((node->val % 2) != (level % 2) || (node->val < prev_value)) return false; 28 | 29 | prev_value = node->val; 30 | 31 | if (node->left) nodes.push(node->left); 32 | if (node->right) nodes.push(node->right); 33 | } 34 | level++; 35 | } 36 | return true; 37 | } 38 | 39 | int main() { 40 | // 构建树 41 | TreeNode *root = new TreeNode(1); 42 | root->left = new TreeNode(2); 43 | root->right = new TreeNode(4); 44 | 45 | root->left->left = new TreeNode(3); 46 | root->left->right = new TreeNode(5); 47 | root->right->left = new TreeNode(7); 48 | root->right->right = new TreeNode(9); 49 | 50 | // 验证是否是奇偶树 51 | bool result = isOddEvenTree(root); 52 | if (result) { 53 | cout << "这是一个特殊奇偶树。" << endl; 54 | } else { 55 | cout << "这不是一个特殊奇偶树。" << endl; 56 | } 57 | 58 | system("pause"); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/The Implementation of Binary Tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct TreeNode { 6 | int value; 7 | TreeNode* left; 8 | TreeNode* right; 9 | 10 | TreeNode(int val, TreeNode* leftTree = nullptr, TreeNode* rightTree = nullptr) 11 | : value(val), left(leftTree), right(rightTree) {} 12 | }; 13 | 14 | TreeNode* createBinaryTree(int value, TreeNode* leftTree = nullptr, TreeNode* rightTree = nullptr) { 15 | return new TreeNode(value, leftTree, rightTree); 16 | } 17 | 18 | bool isLeaf(TreeNode* node) { 19 | return node != nullptr && node->left == nullptr && node->right == nullptr; 20 | } 21 | 22 | int countLeaves(TreeNode* node) { 23 | if (node == nullptr) { 24 | return 0; 25 | } 26 | if (isLeaf(node)) { 27 | return 1; 28 | } 29 | return countLeaves(node->left) + countLeaves(node->right); 30 | } 31 | 32 | int height(TreeNode* node) { 33 | if (node == nullptr) { 34 | return 0; 35 | } 36 | return 1 + max(height(node->left), height(node->right)); 37 | } 38 | 39 | void preOrder(TreeNode* node) { 40 | if (node != nullptr) { 41 | cout << node->value << " "; 42 | preOrder(node->left); 43 | preOrder(node->right); 44 | } 45 | } 46 | 47 | void inOrder(TreeNode* node) { 48 | if (node != nullptr) { 49 | inOrder(node->left); 50 | cout << node->value << " "; 51 | inOrder(node->right); 52 | } 53 | } 54 | 55 | void postOrder(TreeNode* node) { 56 | if (node != nullptr) { 57 | postOrder(node->left); 58 | postOrder(node->right); 59 | cout << node->value << " "; 60 | } 61 | } 62 | 63 | void levelOrder(TreeNode* root) { 64 | if (root == nullptr) return; 65 | queue q; 66 | q.push(root); 67 | 68 | while (!q.empty()) { 69 | TreeNode* node = q.front(); 70 | q.pop(); 71 | cout << node->value << " "; 72 | if (node->left != nullptr) { 73 | q.push(node->left); 74 | } 75 | if (node->right != nullptr) { 76 | q.push(node->right); 77 | } 78 | } 79 | } 80 | 81 | int main() { 82 | // 创建一些节点 83 | TreeNode* leftChild = createBinaryTree(2); 84 | TreeNode* rightChild = createBinaryTree(3); 85 | TreeNode* root = createBinaryTree(1, leftChild, rightChild); 86 | 87 | // 检查是否为叶节点 88 | cout << "Is leaf: " << boolalpha << isLeaf(leftChild) << endl; 89 | 90 | // 计算叶子的个数 91 | cout << "Number of leaves: " << countLeaves(root) << endl; 92 | 93 | // 计算树的高度 94 | cout << "Height of tree: " << height(root) << endl; 95 | 96 | // 执行遍历 97 | cout << "PreOrder: "; 98 | preOrder(root); 99 | cout << endl; 100 | 101 | cout << "InOrder: "; 102 | inOrder(root); 103 | cout << endl; 104 | 105 | cout << "PostOrder: "; 106 | postOrder(root); 107 | cout << endl; 108 | 109 | cout << "LevelOrder: "; 110 | levelOrder(root); 111 | cout << endl; 112 | 113 | system("pause"); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/Traverse Binary Tree with Non Recrusion.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | struct TreeNode 7 | { 8 | int value; 9 | TreeNode* left, * right; 10 | TreeNode(int val, TreeNode* leftTree = nullptr, TreeNode* rightTree = nullptr) : value(val), left(leftTree), right(rightTree) {} 11 | }; 12 | 13 | TreeNode* createBinaryTree(int value, TreeNode* left = nullptr, TreeNode* right = nullptr) { 14 | return new TreeNode(value, left, right); 15 | } 16 | 17 | void preOrderNonRecrusive(TreeNode* root) { 18 | if (!root) return; 19 | stack s; 20 | s.push(root); 21 | while (!s.empty()) { 22 | TreeNode* node = s.top(); 23 | s.pop(); 24 | cout << node->value << " "; 25 | if (node->right) s.push(node->right); 26 | if (node->left) s.push(node->left); 27 | } 28 | } 29 | 30 | void inOrderNonRecursive(TreeNode* root) { 31 | stack s; 32 | TreeNode* current = root; 33 | while (current != nullptr || !s.empty()) { 34 | while (current != nullptr) { 35 | s.push(current); 36 | current = current->left; 37 | } 38 | current = s.top(); 39 | s.pop(); 40 | cout << current->value << " "; 41 | current = current->right; 42 | } 43 | } 44 | 45 | void postOrderNonRecursive(TreeNode* root) { 46 | if (!root) return; 47 | stack s1, s2; 48 | s1.push(root); 49 | while (!s1.empty()) { 50 | TreeNode* node = s1.top(); 51 | s1.pop(); 52 | s2.push(node); 53 | if (node->left) s1.push(node->left); 54 | if (node->right) s1.push(node->right); 55 | } 56 | while (!s2.empty()) { 57 | cout << s2.top()->value << " "; 58 | s2.pop(); 59 | } 60 | } 61 | 62 | int main() { 63 | // 创建一些节点 64 | TreeNode* left = createBinaryTree(2); 65 | TreeNode* right = createBinaryTree(3); 66 | TreeNode* root = createBinaryTree(1, left, right); 67 | 68 | // 执行遍历 69 | cout << "PreOrder: "; 70 | preOrderNonRecrusive(root); 71 | cout << endl; 72 | 73 | cout << "InOrder: "; 74 | inOrderNonRecursive(root); 75 | cout << endl; 76 | 77 | cout << "PostOrder: "; 78 | postOrderNonRecursive(root); 79 | cout << endl; 80 | 81 | system("pause"); 82 | return 0; 83 | } -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Binary Linked List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Binary Linked List.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Children Representation 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Children Representation 1.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Children Representation 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Children Representation 2.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Children-Sibling Representation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Children-Sibling Representation.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Complete Binary Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Complete Binary Tree.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Exchange Binary Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Exchange Binary Tree.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Exchange Forest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Exchange Forest.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Full Binary Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Full Binary Tree.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Huffman Encoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Huffman Encoder.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Parent Representation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Parent Representation.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Perfect Binary Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Perfect Binary Tree.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Suffix Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Suffix Tree.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Complete Binary Tree 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Complete Binary Tree 1.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Complete Binary Tree 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Complete Binary Tree 2.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Non-Complete Binary Tree 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Non-Complete Binary Tree 1.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Non-Complete Binary Tree 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/The Squential Storage of Non-Complete Binary Tree 2.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Three-Pronged Linked List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Three-Pronged Linked List.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/Data-Structures/Tree/images/Trie Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/Data-Structures/Tree/images/Trie Tree.png -------------------------------------------------------------------------------- /Class-Contents-Only-by-C++/images/Commonly Used Complexity Functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Class-Contents-Only-by-C++/images/Commonly Used Complexity Functions.png -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-1/Hw 1_1 最大公约数和最小公倍数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int GCD(int a, int b) { 5 | if (b == 0) 6 | return a; 7 | else 8 | return GCD(b, a % b); 9 | } 10 | 11 | int LCM(int a,int b) { 12 | return a * b / GCD(a, b); 13 | } 14 | 15 | int main(){ 16 | int A, B; 17 | cin >> A >> B; 18 | 19 | int gcd_result = GCD(A, B); 20 | int lcm_result = LCM(A, B); 21 | 22 | cout << gcd_result << "," << lcm_result << endl; 23 | 24 | system("pause"); 25 | return 0; 26 | 27 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-1/Hw 1_2 最大值和最小值.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main(){ 5 | int N; 6 | cin >> N; 7 | int arr[N]; 8 | for(int i = 0; i < N; ++i) { 9 | cin >> arr[i]; 10 | } 11 | int max_temp, min_temp; 12 | max_temp = min_temp = arr[0]; 13 | 14 | for(int i = 1; i < N; ++i) { 15 | if(arr[i] > max_temp) { 16 | max_temp = arr[i]; 17 | } 18 | if(arr[i] < min_temp) { 19 | min_temp = arr[i]; 20 | } 21 | } 22 | 23 | cout << max_temp - min_temp << endl; 24 | 25 | system("pause"); 26 | return 0; 27 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-1/Hw 1_3 数雷.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int countMines(int x, int y, const vector>& grid) { 7 | int count = 0; 8 | int dx[] = {-1,-1,-1,0,0,1,1,1}; 9 | int dy[] = {-1,0,1,-1,1,-1,0,1}; 10 | 11 | for (int i = 0; i < 8; ++i) { 12 | int new_x = x + dx[i], new_y = y + dy[i]; 13 | if (new_x >= 0 && new_x < grid.size() && new_y >=0 && new_y < grid[0].size() && grid[new_x][new_y] == '*') { 14 | count ++; 15 | } 16 | } 17 | 18 | return count; 19 | } 20 | 21 | int main() { 22 | int T; 23 | cin >> T; 24 | vector> all_outputs; 25 | 26 | while (T--) { 27 | int x, y; 28 | cin >> x >> y; 29 | vector> grid(x, vector(y)); 30 | for (int i = 0; i < x; ++i) { 31 | for (int j = 0; j < y; ++j) { 32 | cin >> grid[i][j]; 33 | } 34 | } 35 | 36 | vector output; 37 | for (int i = 0; i < x; ++i) { 38 | string row; 39 | for (int j = 0; j < y; ++j) { 40 | if (grid[i][j] == '*') { 41 | row.push_back('*'); 42 | } else { 43 | row.push_back('0' + countMines(i, j, grid)); 44 | } 45 | } 46 | output.push_back(row); 47 | } 48 | all_outputs.push_back(output); 49 | } 50 | 51 | for (int i = 0; i < all_outputs.size(); ++i) { 52 | for (const string& row : all_outputs[i]) { 53 | cout << row << endl; 54 | } 55 | if (i < all_outputs.size() - 1) { 56 | cout << endl; 57 | } 58 | } 59 | 60 | system("pause"); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-1/Hw 1_4 全排列.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | void generate_permutations(vector& arr, int n, vector& curr_permutation) { 9 | if (curr_permutation.size() == n) { 10 | for (int i = 0; i < n; i++) { 11 | cout << curr_permutation[i]; 12 | if (i < n - 1) cout << " "; 13 | } 14 | cout << endl; 15 | return; 16 | } 17 | 18 | set seen; 19 | for (int i = 0; i < arr.size(); i++) { 20 | if (seen.find(arr[i]) == seen.end()) { 21 | seen.insert(arr[i]); 22 | curr_permutation.push_back(arr[i]); 23 | vector next_arr = arr; 24 | next_arr.erase(next_arr.begin() + i); 25 | generate_permutations(next_arr, n, curr_permutation); 26 | curr_permutation.pop_back(); 27 | } 28 | } 29 | } 30 | 31 | int main() { 32 | int N; 33 | cin >> N; 34 | vector arr(N); 35 | for (int i = 0; i < N; ++i) { 36 | cin >> arr[i]; 37 | } 38 | 39 | vector curr_permutation; 40 | generate_permutations(arr, N, curr_permutation); 41 | 42 | system("pause"); 43 | return 0; 44 | 45 | 46 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-10/Hw 10_1 求叶子结点个数.cpp: -------------------------------------------------------------------------------- 1 | void creat(BiTree &Tree) { 2 | char ch; 3 | scanf(" %c", &ch); // 读取字符,注意前面有个空格用来过滤掉空白符 4 | if (ch == '#') { 5 | Tree = NULL; // 如果当前字符为'#',则当前子树为空,即无左子或右子 6 | } else { 7 | Tree = (BiTree)malloc(len); // 分配内存 8 | Tree->data = ch; // 将读取的字符赋值给节点的数据域 9 | creat(Tree->lchild); // 递归构造左子树 10 | creat(Tree->rchild); // 递归构造右子树 11 | } 12 | } 13 | 14 | int countleaf(BiTree Tree) { 15 | if (!Tree) { 16 | return 0; // 如果是空树或者达到叶子节点的子节点,返回0 17 | } 18 | if (!Tree->lchild && !Tree->rchild) { 19 | return 1; // 如果左右孩子都为空,则为叶子节点,返回1 20 | } else { 21 | return countleaf(Tree->lchild) + countleaf(Tree->rchild); // 否则,递归统计左右子树的叶子节点数并返回总和 22 | } 23 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-10/Hw 10_2 求二叉树高度.cpp: -------------------------------------------------------------------------------- 1 | void creat(BiTree &Tree) { 2 | char ch; 3 | scanf(" %c", &ch); // 读取字符,注意前面有个空格用来过滤掉空白符 4 | if (ch == '#') { 5 | Tree = NULL; // 如果当前字符为'#',则当前子树为空,即无左子或右子 6 | } else { 7 | Tree = (BiTree)malloc(len); // 分配内存 8 | Tree->data = ch; // 将读取的字符赋值给节点的数据域 9 | creat(Tree->lchild); // 递归构造左子树 10 | creat(Tree->rchild); // 递归构造右子树 11 | } 12 | } 13 | 14 | int Depth(BiTree Tree) { 15 | if (Tree == NULL) { 16 | return 0; // 空树的高度为0 17 | } else { 18 | int leftDepth = Depth(Tree->lchild); // 计算左子树的高度 19 | int rightDepth = Depth(Tree->rchild); // 计算右子树的高度 20 | return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1; // 返回较大的高度加1 21 | } 22 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-11/Hw 11_1 根据后序序列和中序序列确定二叉树.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct TreeNode { 7 | int val; 8 | TreeNode *left, *right; 9 | TreeNode(int value) : val(value), left(nullptr), right(nullptr) {} 10 | }; 11 | 12 | TreeNode* buildTreeHelper(vector& postOrder, int pStart, int pEnd, vector& inOrder, int iStart, int iEnd, unordered_map& inMap) { 13 | if (pStart > pEnd || iStart > iEnd) return nullptr; 14 | TreeNode* root = new TreeNode(postOrder[pEnd]); 15 | int inRoot = inMap[root->val]; 16 | int numsLeft = inRoot - iStart; 17 | 18 | root->left = buildTreeHelper(postOrder, pStart, pStart + numsLeft - 1, inOrder, iStart, inRoot - 1, inMap); 19 | root->right = buildTreeHelper(postOrder, pStart + numsLeft, pEnd - 1, inOrder, inRoot + 1, iEnd, inMap); 20 | return root; 21 | } 22 | 23 | TreeNode* buildTree(vector& postOrder, vector& inOrder) { 24 | unordered_map inMap; 25 | for (int i = 0; i < inOrder.size(); ++i) { 26 | inMap[inOrder[i]] = i; 27 | } 28 | return buildTreeHelper(postOrder, 0, postOrder.size() - 1, inOrder, 0, inOrder.size() - 1, inMap); 29 | } 30 | 31 | void printTreePreOrder(TreeNode* root) { 32 | if (root == nullptr) return; 33 | cout << " " << root->val; 34 | printTreePreOrder(root->left); 35 | printTreePreOrder(root->right); 36 | } 37 | 38 | int height(TreeNode* root) { 39 | if (root == nullptr) return 0; 40 | else return 1 + max(height(root->left), height(root->right)); 41 | } 42 | 43 | int main() { 44 | int n; 45 | cin >> n; 46 | vector postOrder(n); 47 | vector inOrder(n); 48 | for (int i = 0; i < n; ++i) { 49 | cin >> postOrder[i]; 50 | } 51 | for (int j = 0; j < n; ++j) { 52 | cin >> inOrder[j]; 53 | } 54 | 55 | TreeNode* root = buildTree(postOrder, inOrder); 56 | int level = height(root); 57 | cout << level; 58 | printTreePreOrder(root); 59 | cout << endl; 60 | 61 | system("pause"); 62 | return 0; 63 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-11/Hw 11_2 哈夫曼树.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int calculateWPL(vector& weights) { 8 | priority_queue, greater> min_heap; 9 | 10 | for (int weight : weights) { 11 | min_heap.push(weight); 12 | } 13 | 14 | int wpl = 0; 15 | while (min_heap.size() > 1) { 16 | int x = min_heap.top(); 17 | min_heap.pop(); 18 | int y = min_heap.top(); 19 | min_heap.pop(); 20 | 21 | int z = x + y; 22 | min_heap.push(z); 23 | 24 | wpl += z; 25 | } 26 | 27 | return wpl; 28 | } 29 | 30 | int main() { 31 | int n; 32 | cin >> n; 33 | 34 | vector weights(n); 35 | for (int i = 0; i < n; ++i) { 36 | cin >> weights[i]; 37 | } 38 | 39 | int wpl = calculateWPL(weights); 40 | cout << wpl << endl; 41 | 42 | system("pause"); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-12/Hw 12_1 堆的操作.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void printHeap(vector& heap) { 8 | for (int i = 1; i < heap.size(); ++i) 9 | cout << heap[i] << (i < heap.size() - 1 ? " " : ""); 10 | cout << endl; 11 | } 12 | 13 | void siftUp(int i, vector& heap) { 14 | int temp = heap[i]; 15 | while (i > 1 && temp < heap[i / 2]) { 16 | heap[i] = heap[i / 2]; 17 | i = i / 2; 18 | } 19 | heap[i] = temp; 20 | } 21 | 22 | void siftDown(int i, vector& heap) { 23 | int temp = heap[i]; 24 | int size = heap.size(); 25 | while (2 * i < size) { 26 | int child = 2 * i; 27 | if (child + 1 < size && heap[child] > heap[child + 1]) { 28 | child++; 29 | } 30 | if (temp <= heap[child]) { 31 | break; 32 | } 33 | heap[i] = heap[child]; 34 | i = child; 35 | } 36 | heap[i] = temp; 37 | } 38 | 39 | void insert(int value, vector& heap) { 40 | heap.push_back(value); 41 | siftUp(heap.size() - 1, heap); 42 | } 43 | 44 | void deleteMin(vector& heap) { 45 | if (heap.size() > 1) { 46 | heap[1] = heap.back(); 47 | heap.pop_back(); 48 | siftDown(1, heap); 49 | } 50 | } 51 | 52 | void buildHeap(vector& heap) { 53 | int n = heap.size() - 1; 54 | for (int i = n / 2; i >= 1; --i) { 55 | siftDown(i, heap); 56 | } 57 | } 58 | 59 | int main() { 60 | int N, K, x; 61 | cin >> N >> K; 62 | vector heap = {0}; 63 | for (int i = 0; i < K; ++i) { 64 | int operation; 65 | cin >> operation; 66 | if (operation == 1) { 67 | cin >> x; 68 | insert(x, heap); 69 | } else if (operation == -1) { 70 | deleteMin(heap); 71 | } 72 | printHeap(heap); 73 | } 74 | 75 | int M; 76 | cin >> M; 77 | vector elements(M + 1, 0); 78 | for (int i = 1; i < M + 1; ++i) { 79 | cin >> elements[i]; 80 | } 81 | buildHeap(elements); 82 | printHeap(elements); 83 | 84 | system("pause"); 85 | return 0; 86 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-12/Hw 12_2 堆的建立.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void printHeap(const vector& heap) { 8 | for (int i = 0; i < heap.size(); ++i) { 9 | cout << heap[i] << (i < heap.size() - 1 ? " " : ""); 10 | } 11 | cout << endl; 12 | } 13 | 14 | void buildMaxHeap(vector elements) { 15 | make_heap(elements.begin(), elements.end()); 16 | printHeap(elements); 17 | } 18 | 19 | void buildMinHeap(vector elements) { 20 | make_heap(elements.begin(), elements.end(), greater()); 21 | printHeap(elements); 22 | } 23 | 24 | int main() { 25 | int n; 26 | cin >> n; 27 | 28 | vector elements(n); 29 | for (int i = 0; i < n; ++i) { 30 | cin >> elements[i]; 31 | } 32 | 33 | buildMaxHeap(elements); 34 | buildMinHeap(elements); 35 | 36 | system("pause"); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-13/Hw 13_1 折半(二分)查找.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int binary_search(const vector& arr, int left, int right, int x) { 8 | while (left <= right) { 9 | int mid = (left + right) / 2; 10 | 11 | if (arr[mid] == x) 12 | return mid; 13 | else if (arr[mid] < x) 14 | left = mid + 1; 15 | else 16 | right = mid - 1; 17 | } 18 | 19 | return -1; 20 | } 21 | 22 | int main() { 23 | int n, num; 24 | cin >> n; 25 | 26 | vector arr(n); 27 | 28 | for (int i = 0; i < n; i++) { 29 | cin >> arr[i]; 30 | } 31 | 32 | sort(arr.begin(), arr.end()); 33 | 34 | cin >> num; 35 | 36 | for (int i = 0; i < num; i++) { 37 | int a, b, c; 38 | cin >> a >> b >> c; 39 | 40 | int result = binary_search(arr, b, c, a); 41 | cout << (result != -1 ? result : -1) << endl; 42 | } 43 | 44 | system("pause"); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-13/Hw 13_2 部落冲突.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | long long calculateArea(int x, const vector>& oasis) { 6 | long long area = 0; 7 | for (const auto& o : oasis) { 8 | if (o[0] < x) { 9 | area += static_cast(min(x - o[0], o[2])) * static_cast(o[3]); 10 | } 11 | } 12 | return area; 13 | } 14 | 15 | int main() { 16 | int n; 17 | cin >> n; 18 | vector> oasis(n, vector(4)); 19 | long long total_area = 0; 20 | for (int i = 0; i < n; ++i) { 21 | for (int j = 0; j < 4; ++j) { 22 | cin >> oasis[i][j]; 23 | } 24 | total_area += static_cast(oasis[i][2]) * static_cast(oasis[i][3]); 25 | } 26 | 27 | int left = 0, right = 1000000; 28 | while (left < right) 29 | { 30 | int mid = (left + right) / 2; 31 | if (calculateArea(mid, oasis) * 2 < total_area) { 32 | left = mid + 1; 33 | } else { 34 | right = mid; 35 | } 36 | } 37 | 38 | cout << left << endl; 39 | 40 | system("pause"); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-14/Hw 14_1 判断是否二叉排序树.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | struct TreeNode { 7 | int val; 8 | TreeNode *left, *right; 9 | TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 10 | }; 11 | 12 | TreeNode* buildTree(const string &preorder, int &index) { 13 | if (index >= preorder.size() || preorder[index] == '*') { 14 | ++index; // Skip the '*' character 15 | return nullptr; 16 | } 17 | TreeNode* root = new TreeNode(preorder[index++] - '0'); 18 | root->left = buildTree(preorder, index); 19 | root->right = buildTree(preorder, index); 20 | return root; 21 | } 22 | 23 | void inOrderHelper(TreeNode* node, vector &result) { 24 | if (node != nullptr) { 25 | inOrderHelper(node->left, result); 26 | result.push_back(node->val); 27 | inOrderHelper(node->right, result); 28 | } 29 | } 30 | 31 | vector inOrderTree(TreeNode* root) { 32 | vector result; 33 | inOrderHelper(root, result); 34 | return result; 35 | } 36 | 37 | bool isBST(const vector& result) { 38 | for (int i = 1; i < result.size(); ++i) { 39 | if (result[i] <= result[i - 1]) { 40 | return false; 41 | } 42 | } 43 | return true; 44 | } 45 | 46 | int main() { 47 | string preorder; 48 | while (cin >> preorder) { 49 | int index = 0; 50 | TreeNode* root = buildTree(preorder, index); 51 | vector result = inOrderTree(root); 52 | cout << (isBST(result) ? "YES" : "NO") << endl; 53 | } 54 | 55 | system("pause"); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-15/Hw 15_1 整型关键字的散列映射.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(){ 7 | int numElements, hashSize; 8 | cin >> numElements >> hashSize; 9 | vector hashTable(hashSize, -1); 10 | vector result; 11 | 12 | for (int i = 0; i < numElements; i++) { 13 | int currentValue; 14 | cin >> currentValue; 15 | int index = currentValue % hashSize; 16 | 17 | if (hashTable[index] == -1) { 18 | hashTable[index] = currentValue; 19 | result.push_back(index); 20 | } else { 21 | int d = 0; 22 | int newIndex = index; 23 | 24 | while (hashTable[newIndex] != -1 && hashTable[newIndex] != currentValue) { 25 | d++; 26 | newIndex = (index + d) % hashSize; 27 | } 28 | 29 | hashTable[newIndex] = currentValue; 30 | result.push_back(newIndex); 31 | } 32 | } 33 | 34 | for (size_t i = 0; i < result.size() - 1; i++) { 35 | cout << result[i] << " "; 36 | } 37 | cout << result.back() << endl; 38 | 39 | system("pause"); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-16/Hw 16_1 图的深度优先搜索.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | #define MaxVexNum 20 // 最大顶点数目 6 | 7 | typedef struct { 8 | int arcs[MaxVexNum][MaxVexNum]; 9 | int vexnum, arcnum; 10 | } AMGraph; 11 | 12 | // 深度优先搜索函数 13 | void DFS(AMGraph &G, int v, vector &visited, vector &result) { 14 | visited[v] = true; 15 | result.push_back(v); 16 | for (int i = 0; i < G.vexnum; ++i) { 17 | if (G.arcs[v][i] == 1 && !visited[i]) { 18 | DFS(G, i, visited, result); 19 | } 20 | } 21 | } 22 | 23 | // 计算连通分量个数的函数 24 | int calculateConnectedComponents(AMGraph &G, vector &result) { 25 | vector visited(G.vexnum, false); 26 | int count = 0; 27 | for (int i = 0; i < G.vexnum; ++i) { 28 | if (!visited[i]) { 29 | DFS(G, i, visited, result); 30 | count++; 31 | } 32 | } 33 | return count; 34 | } 35 | 36 | int main() { 37 | AMGraph G; 38 | cin >> G.vexnum >> G.arcnum; 39 | for (int i = 0; i < G.vexnum; ++i) { 40 | for (int j = 0; j < G.vexnum; ++j) { 41 | G.arcs[i][j] = 0; // 初始化邻接矩阵 42 | } 43 | } 44 | 45 | for (int i = 0; i < G.arcnum; ++i) { 46 | int a, b; 47 | cin >> a >> b; 48 | G.arcs[a][b] = G.arcs[b][a] = 1; 49 | } 50 | 51 | vector dfsResult; 52 | int connectedComponents = calculateConnectedComponents(G, dfsResult); 53 | 54 | for (int i : dfsResult) { 55 | cout << i << " "; 56 | } 57 | cout << endl; 58 | 59 | cout << connectedComponents << endl; 60 | 61 | cout << G.arcnum << endl; 62 | 63 | system("pause"); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-16/Hw 16_2 抓住那头牛.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | const int MAX_POS = 100000; 7 | 8 | int catchCow(int N, int K) { 9 | if (N >= K) return N - K; 10 | vector time(MAX_POS + 1, -1); 11 | queue q; 12 | q.push(N); 13 | time[N] = 0; 14 | 15 | while (!q.empty()) { 16 | int current = q.front(); 17 | q.pop(); 18 | 19 | vector nextPos = {current - 1, current + 1, current * 2}; 20 | for (int next : nextPos) { 21 | if (next >= 0 && next <= MAX_POS && time[next] == -1) { 22 | time[next] = time[current] + 1; 23 | q.push(next); 24 | } 25 | } 26 | 27 | if (time[K] != -1) { 28 | break; 29 | } 30 | } 31 | return time[K]; 32 | } 33 | 34 | int main() { 35 | int N, K; 36 | cin >> N >> K; 37 | cout << catchCow(N, K) << endl; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-2/Hw 2_1 冰雹猜想.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int hail_conjecture(int n, int count) { 7 | vector number_list; 8 | number_list.push_back(n); 9 | while (n != 1) { 10 | if (n % 2 == 0) { 11 | n /= 2; 12 | } else if (n % 2 == 1) 13 | { 14 | n = n * 3 + 1; 15 | } 16 | number_list.push_back(n); 17 | count += 1; 18 | } 19 | number_list.push_back(1); 20 | for (int i = 0; i < count; ++i) { 21 | if (i == count - 1) cout << number_list[i]; 22 | else cout << number_list[i] << " "; 23 | } 24 | cout << endl; 25 | return count; 26 | } 27 | 28 | int main() { 29 | int n; 30 | cin >> n; 31 | 32 | int result = hail_conjecture(n, 1); 33 | cout << "count = " << result << endl; 34 | 35 | system("pause"); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-2/Hw 2_2 打印图形.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | void printDiamond(int n) { 6 | int space, stars; 7 | 8 | for (int i = 1; i <= n; ++i) { 9 | space = n - i; 10 | stars = 2 * i - 1; 11 | 12 | for (int j = 1; j <= space; ++j) { 13 | cout << " "; 14 | } 15 | for (int j = 1; j <= stars; ++j) { 16 | cout << "*"; 17 | } 18 | for (int j = 1; j <= space; ++j) { 19 | cout << " "; 20 | } 21 | cout << endl; 22 | } 23 | 24 | for (int i = n - 1; i >= 1; --i) { 25 | space = n - i; 26 | stars = 2 * i - 1; 27 | 28 | for (int j = 1; j <= space; ++j) { 29 | cout << " "; 30 | } 31 | for (int j = 1; j <= stars; ++j) { 32 | cout << "*"; 33 | } 34 | for (int j = 1; j <= space; ++j) { 35 | cout << " "; 36 | } 37 | cout << endl; 38 | } 39 | } 40 | 41 | int main() { 42 | int n; 43 | cin >> n; 44 | 45 | printDiamond(n); 46 | 47 | system("pause"); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-3/Hw 3_1 顺序表的删除.cpp: -------------------------------------------------------------------------------- 1 | List Delete( List &L, ElementType minD, ElementType maxD ){ 2 | for(int i =0;i<=L.last;i++){ 3 | if(L.Data[i]maxD){ 12 | for(int j = i;j<=L.last;j++){ 13 | L.Data[j]=L.Data[j+1]; 14 | } 15 | L.Data[L.last]=0; 16 | L.last--; 17 | } 18 | } 19 | for(int i=0;i<=L.last;i++) 20 | { 21 | printf("%d ",L.Data[i]); 22 | } 23 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-3/Hw 3_2 寻找链表元素的前驱节点.cpp: -------------------------------------------------------------------------------- 1 | ptr pre (ptr h, int x) 2 | { 3 | if (h == NULL || h->next == NULL) // 如果链表为空或只有一个结点,返回NULL 4 | { 5 | return NULL; 6 | } 7 | 8 | ptr curr = h; 9 | ptr next_node = curr->next; 10 | 11 | while (next_node != NULL) 12 | { 13 | if (next_node->data == x) // 找到了所查找元素的结点 14 | { 15 | return curr; // 返回前驱结点 16 | } 17 | curr = next_node; 18 | next_node = next_node->next; 19 | } 20 | return NULL; // 没有找到所查找元素的结点,返回NULL 21 | } -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-4/Hw 4_1 字符串匹配问题.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | string is_valid(const string& s) { 10 | stack stack; 11 | unordered_map mapping = { 12 | {')', '('}, 13 | {']', '['}, 14 | {'}', '{'}, 15 | {'>', '<'} 16 | }; 17 | string order = "<([{"; 18 | 19 | for (char charact : s) { 20 | if (order.find(charact) != string::npos) { 21 | if (!stack.empty() && order.find(stack.top()) < order.find(charact)) 22 | return "NO"; 23 | stack.push(charact); 24 | } else if (mapping.find(charact) != mapping.end()) { 25 | if (stack.empty() || mapping[charact] != stack.top()) 26 | return "NO"; 27 | stack.pop(); 28 | } else { 29 | return "NO"; 30 | } 31 | } 32 | 33 | return stack.empty() ? "YES" : "NO"; 34 | } 35 | 36 | int main() { 37 | int n; 38 | cin >> n; 39 | vector results; 40 | 41 | for (int i = 0; i < n; ++i) { 42 | string s; 43 | cin >> s; 44 | results.push_back(is_valid(s)); 45 | } 46 | 47 | for (const auto &res : results) 48 | cout << res << endl; 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-4/Hw 4_1 字符串匹配问题.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CQULeaf/DataStructure-Algorithm_Course_Resources/67f6e967a4c276f353dfffe241068f639cde701d/Homework-by-C++/Homework-Week-4/Hw 4_1 字符串匹配问题.exe -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-4/Hw 4_2 后缀表达式求值.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | int evaluate_postfix(stack& s, const string& op) { 9 | if (s.size() < 2) { 10 | cout << "Expression Error: " << (s.empty() ? 0 : s.top()) << endl; 11 | return -1; 12 | } 13 | 14 | int second = s.top(); s.pop(); 15 | int first = s.top(); s.pop(); 16 | 17 | if (op == "+") s.push(first + second); 18 | else if (op == "-") s.push(first - second); 19 | else if (op == "*") s.push(first * second); 20 | else if (op == "/") { 21 | if (second == 0) { 22 | cout << "Error: " << first << "/0" << endl; 23 | return -1; 24 | } 25 | s.push(first / second); 26 | } else { 27 | cout << "Expression Error: " << (s.empty() ? 0 : s.top()) << endl; 28 | return -1; 29 | } 30 | 31 | return 0; 32 | } 33 | 34 | int main() { 35 | stack s; 36 | string token; 37 | 38 | while (cin >> token) { 39 | if (token == "#") break; 40 | 41 | if (isdigit(token[0]) || (token[0] == '-' && token.size() > 1)) { 42 | try { 43 | s.push(stoi(token)); 44 | } catch (const invalid_argument& ia) { 45 | cerr << "Invalid argument: " << token << endl; 46 | return -1; 47 | } catch (const out_of_range& oor) { 48 | cerr << "Out of range: " << token << endl; 49 | return -1; 50 | } 51 | } else { 52 | if (evaluate_postfix(s, token) == -1) return -1; 53 | } 54 | } 55 | 56 | if (s.size() != 1) { 57 | cout << "Expression Error: " << s.top() << endl; 58 | return -1; 59 | } 60 | 61 | cout << s.top() << endl; 62 | 63 | system("pause"); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-4/Hw 4_3 大師と仙人との奇遇.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | long long calculate_profit(int N, vector& prices) { 8 | priority_queue, greater> min_heap; // Min-heap to track the prices of stocks bought 9 | long long total_profit = 0; 10 | 11 | for (int i = 0; i < N; ++i) { 12 | // Buy a stock every day 13 | min_heap.push(prices[i]); 14 | 15 | // If it's not the last day, check if there are any stocks to sell 16 | if (i != N - 1) { 17 | while (!min_heap.empty() && min_heap.top() < prices[i + 1]) { 18 | total_profit += prices[i + 1] - min_heap.top(); 19 | min_heap.pop(); 20 | } 21 | } 22 | // On the last day, sell all remaining stocks 23 | else { 24 | while (!min_heap.empty()) { 25 | total_profit += prices[i] - min_heap.top(); 26 | min_heap.pop(); 27 | } 28 | } 29 | } 30 | return total_profit; 31 | } 32 | 33 | int main() { 34 | int N; 35 | cin >> N; 36 | vector prices(N); 37 | for (int i = 0; i < N; ++i) { 38 | cin >> prices[i]; 39 | } 40 | 41 | cout << calculate_profit(N, prices) << endl; 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-4/Hw 4_3 大師と仙人との奇遇.md: -------------------------------------------------------------------------------- 1 | # Talk about this solution 2 | 3 | 4 | - [Talk about this solution](#talk-about-this-solution) 5 | - [About the `queue` header file](#about-the-queue-header-file) 6 | - [What's the differences between `list` in python and `vector` in C++](#whats-the-differences-between-list-in-python-and-vector-in-c) 7 | 8 | ## About the `queue` header file 9 | 10 | - `` is a header file in the C++ Standard Library that provides several queue-based data structures, including the basic `queue` and the `priority_queue`. 11 | - A priority queue is a data structure that keeps its elements in a sorted order according to some criteria (often based on the element values). The element with the highest priority is always at the front. Priority queues are often implemented using a heap data structure. 12 | 13 | ***The `queue` header file is relative to the code `priority_queue, greater> min_heap;`*** 14 | 15 | In the code, `priority_queue, greater> min_heap;` creates a min-heap, meaning that the smallest element is always at the top. Here is the detail: 16 | 17 | 1. The first template argument `int` specifies the type of the elements in the priority queue. 18 | 2. The second template argument `vector` specifies the underlying container to use. In this case, it's a vector. 19 | 3. The third template argument `greater` is a comparison functor that determines the order of the elements. `greater` makes it so that the priority queue behaves like a min-heap (with the smallest element at the top). If we used `less`, it would behave like a max-heap. 20 | 21 | In the provided code, the `min_heap` priority queue is used to track the prices of stocks bought. When deciding whether to sell a stock, the code checks the top of the `min_heap` to get the smallest price (i.e., the cheapest stock bought) and sells it if profitable. 22 | 23 | ## What's the differences between `list` in python and `vector` in C++ 24 | 25 | Both Python's `list` and C++'s `vector` are dynamic array-like data structures that allow us to store and manage collections of elements. They share several similarities in their basic usage, but there are some significant differences due to the nature of the two languages. 26 | 27 | 1. **Dynamically Resizable**:***(The same)*** 28 | - Both `list` in Python and `vector` in C++ can grow and shrink dynamically, meaning you don't need to know their size ahead of time. 29 | 30 | 2. **Data Type**: 31 | - **Python's `list`**: Can hold elements of different data types in the same list (e.g., a mix of integers, strings, and objects). 32 | - **C++'s `vector`**: Is a template class, and each instance of a `vector` can only hold elements of a specific type. For example, a `vector` can only hold integers. 33 | 34 | 3. **Performance & Memory**: 35 | - **Python's `list`**: Generally consumes more memory per element because of the overhead associated with dynamic typing and object storage. 36 | - **C++'s `vector`**: Tends to be more memory-efficient for simple types because it's storing them in a contiguous block without extra overhead. 37 | 38 | 4. **Operations**:***(partially the same)*** 39 | - Many of the basic operations are similar, like appending to the end (`append` in Python, `push_back` in C++), accessing an element by index, and finding the size (`len()` in Python, `size()` in C++). 40 | - However, C++'s `vector` also provides direct memory-related operations like `reserve()`, which can be used to pre-allocate memory for performance reasons. 41 | 42 | 5. **Underlying Implementation**:***(partially the same)*** 43 | - Both are backed by arrays, but the internal management, memory allocation, and resizing strategies might differ. 44 | 45 | 6. **Error Handling**: 46 | - **Python**: Will raise an exception (like `IndexError`) for out-of-bounds access or other issues. 47 | - **C++**: Out-of-bounds access on a `vector` without using the `at()` method is undefined behavior, which might lead to crashes or unexpected results. With `at()`, it throws an `out_of_range` exception. 48 | 49 | 7. **Memory Management**: 50 | - **Python**: Uses garbage collection to automatically reclaim memory. 51 | - **C++**: `vector` manages its memory automatically, but C++ in general requires more manual memory management (though `vector` abstracts much of this away). 52 | 53 | 8. **Safety & Flexibility**: 54 | - **Python**: Being a high-level language, it abstracts away many complexities and is more forgiving. 55 | - **C++**: Offers more control at the cost of safety. It allows for direct memory access, pointer manipulation, etc. 56 | 57 | In many ways, their usage is similar, especially for basic operations. For someone transitioning from Python to C++, a `vector` will often feel like the closest analog to a Python `list`. However, the static typing of C++ and the finer control it offers over memory and performance mean that there are more things to consider and more potential pitfalls when working with `vector`. 58 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-5/Hw 5_1 插入排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() 6 | { 7 | int N; 8 | cin >> N; 9 | int arr[N]; 10 | for(int i = 0; i < N; i++) 11 | { 12 | cin >> arr[i]; 13 | } 14 | 15 | for(int i = 1; i < N; i++) 16 | { 17 | int key = arr[i]; 18 | int j = i-1; 19 | while(j >= 0 && key < arr[j]) 20 | { 21 | arr[j+1] = arr[j]; 22 | j--; 23 | } 24 | arr[j+1] = key; 25 | for(int k = 0;k < N; k++) 26 | { 27 | if (k == N - 1) cout << arr[k]; 28 | else cout << arr[k] << " "; 29 | } 30 | cout << endl; 31 | } 32 | 33 | system("pause"); 34 | return 0; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-8/Hw 8_1 冒泡排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | void exchange(int arr[], int i, int j, bool& exchanged) 6 | { 7 | if(arr[i] > arr[j]) 8 | { 9 | swap(arr[i], arr[j]); 10 | exchanged = true; 11 | } 12 | } 13 | 14 | void display(int arr[], int N) 15 | { 16 | for(int i = 0; i < N; i++) 17 | { 18 | if(i != N-1) 19 | cout << arr[i] << " "; 20 | else 21 | cout << arr[i]; 22 | } 23 | cout << endl; 24 | } 25 | 26 | int main() 27 | { 28 | int N; 29 | cin >> N; 30 | int arr[N]; 31 | for(int i = 0; i < N; i++) 32 | { 33 | cin >> arr[i]; 34 | } 35 | 36 | for(int i = 0; i < N - 1; i++) 37 | { 38 | bool exchanged = false; 39 | for(int j = 0; j < N - 1 - i; j++) 40 | { 41 | exchange(arr, j, j + 1, exchanged); 42 | } 43 | if(!exchanged) 44 | break; 45 | else 46 | display(arr, N); 47 | } 48 | 49 | system("pause"); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-8/Hw 8_2 小球装箱游戏.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | // #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | struct Ball 9 | { 10 | int number; 11 | int color; 12 | }; 13 | 14 | 15 | int main() 16 | { 17 | /* 18 | To pass all the tests, it seems that this snippet is unnecessary 19 | ifstream infile("ball.in"); 20 | int N; 21 | infile >> N; 22 | 23 | vector balls(N); 24 | for(int i = 0; i < N; ++i) 25 | { 26 | infile >> balls[i].number >> balls[i].color; 27 | } 28 | infile.close(); 29 | */ 30 | 31 | int N; 32 | cin >> N; 33 | 34 | vector balls(N); 35 | for(int i = 0; i < N; ++i) 36 | { 37 | cin >> balls[i].number >> balls[i].color; 38 | } 39 | 40 | sort(balls.begin(), balls.end(), [](const Ball& a, const Ball& b) 41 | {return (a.number > b.number) || (a.number == b.number && a.color < b.color);}); 42 | 43 | int redA = 0, greenA = 0, redB = 0, greenB = 0; 44 | for(int i = 0; i < N/2; ++i) 45 | { 46 | if(balls[i].color == 0) ++redA; 47 | else ++greenA; 48 | } 49 | for(int i = N/2; i < N; ++i) 50 | { 51 | if(balls[i].color == 0) ++redB; 52 | else ++greenB; 53 | } 54 | /* 55 | To pass all the tests, it seems that this snippet is unnecessary 56 | ofstream outfile("ball.out"); 57 | outfile << redA << " " << greenA << endl; 58 | outfile << redB << " " << greenB << endl; 59 | outfile.close(); 60 | */ 61 | cout << redA << " " << greenA << endl; 62 | cout << redB << " " << greenB << endl; 63 | 64 | system("pause"); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-8/Hw 8_2 小球装箱游戏.md: -------------------------------------------------------------------------------- 1 | # Talk About This Interesting Problem 2 | 3 | 4 | - [Talk About This Interesting Problem](#talk-about-this-interesting-problem) 5 | - [Talk about `file operations`](#talk-about-file-operations) 6 | - [ifstream: Input File Stream](#ifstream-input-file-stream) 7 | - [Syntax for Opening a File (1)](#syntax-for-opening-a-file-1) 8 | - [Reading from File](#reading-from-file) 9 | - [Closing a File (1)](#closing-a-file-1) 10 | - [ofstream: Output File Stream](#ofstream-output-file-stream) 11 | - [Syntax for Opening a File (2)](#syntax-for-opening-a-file-2) 12 | - [Writing to File](#writing-to-file) 13 | - [Closing a File (2)](#closing-a-file-2) 14 | - [Example in the Current Context](#example-in-the-current-context) 15 | - [Reading from `ball.in`](#reading-from-ballin) 16 | - [Writing to `ball.out`](#writing-to-ballout) 17 | - [Talk about the `custom sort algorithm`](#talk-about-the-custom-sort-algorithm) 18 | - [Syntax](#syntax) 19 | - [Logic](#logic) 20 | 21 | ## Talk about `file operations` 22 | 23 | File operations are quite common in C++, and they're particularly useful when we want to read data from a file or write data to a file. The `` library provides all the necessary functionalities to deal with files. Here are some key concepts related to file operations: 24 | 25 | ### ifstream: Input File Stream 26 | 27 | `ifstream` is used to read data from files. We can think of it as an input stream for files. 28 | 29 | #### Syntax for Opening a File (1) 30 | 31 | ```cpp 32 | ifstream infile("file_name"); 33 | ``` 34 | 35 | #### Reading from File 36 | 37 | We can read from an `ifstream` object just like we read from `cin` (standard input). 38 | 39 | ```cpp 40 | int x; 41 | infile >> x; 42 | ``` 43 | 44 | #### Closing a File (1) 45 | 46 | It's a good practice to close the file after we're done reading. 47 | 48 | ```cpp 49 | infile.close(); 50 | ``` 51 | 52 | ### ofstream: Output File Stream 53 | 54 | `ofstream` is used to write data to files. We can think of it as an output stream but for files. 55 | 56 | #### Syntax for Opening a File (2) 57 | 58 | ```cpp 59 | ofstream outfile("file_name"); 60 | ``` 61 | 62 | #### Writing to File 63 | 64 | We can write to an `ofstream` object just like we write to `cout` (standard output). 65 | 66 | ```cpp 67 | outfile << "Hello, world!" << endl; 68 | ``` 69 | 70 | #### Closing a File (2) 71 | 72 | Closing the file after writing ensures that all data is flushed to the file. 73 | 74 | ```cpp 75 | outfile.close(); 76 | ``` 77 | 78 | ### Example in the Current Context 79 | 80 | In your program, we can see file operations being used like this: 81 | 82 | #### Reading from `ball.in` 83 | 84 | ```cpp 85 | ifstream infile("ball.in"); 86 | int N; 87 | infile >> N; 88 | // ... (reading more data) 89 | infile.close(); 90 | ``` 91 | 92 | #### Writing to `ball.out` 93 | 94 | ```cpp 95 | ofstream outfile("ball.out"); 96 | outfile << redA << " " << greenA << endl; 97 | outfile << redB << " " << greenB << endl; 98 | outfile.close(); 99 | ``` 100 | 101 | These operations help us read the number of balls and their properties from `ball.in` and write the sorted output to `ball.out`. 102 | 103 | *** 104 | 105 | ## Talk about the `custom sort algorithm` 106 | 107 | ```cpp 108 | sort(balls.begin(), balls.end(), [](const Ball& a, const Ball& b) 109 | {return (a.number > b.number) || (a.number == b.number && a.color < b.color);}); 110 | ``` 111 | 112 | ### Syntax 113 | 114 | ```cpp 115 | sort(balls.begin(), balls.end(), [](const Ball& a, const Ball& b) { 116 | return (a.number > b.number) || (a.number == b.number && a.color < b.color); 117 | }); 118 | ``` 119 | 120 | 1. `sort()`: This is the sorting function provided by the C++ Standard Library, specifically from the `` header. 121 | 122 | 2. `balls.begin(), balls.end()`: These are iterators pointing to the beginning and the end of the `balls` vector. They define the range of elements to be sorted. 123 | 124 | 3. `[](const Ball& a, const Ball& b)`: This is a lambda function. It is an anonymous function that defines custom comparison logic. The function takes two arguments, `a` and `b`, which are references to `Ball` structs. 125 | 126 | 4. `return (a.number > b.number) || (a.number == b.number && a.color < b.color);`: This is the body of the lambda function, which specifies the sorting criteria. 127 | 128 | ### Logic 129 | 130 | 1. The `sort` function will sort the `balls` vector. 131 | 132 | 2. The lambda function provides the custom rules for sorting, defined as follows: 133 | - `a.number > b.number`: Prioritize sorting by the `number` field in descending order. Larger numbers come before smaller numbers. 134 | - `a.number == b.number && a.color < b.color`: If two balls have the same `number`, then prioritize the ball with the smaller `color` value, which means red (0) comes before green (1). 135 | 136 | 3. The logical OR (`||`) in the return statement means that the first condition is checked first. If it's true, the second condition is not checked. If it's false, the second condition is checked. 137 | 138 | In summary, this snippet sorts the `balls` vector in such a way that balls with higher numbers come first, and when numbers are equal, red balls come before green balls. 139 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-9/Hw 9_1 二路归并排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void merge(vector& arr, int l, int m, int r) { 7 | int n1 = m - l + 1; 8 | int n2 = r - m; 9 | 10 | vector L(n1), R(n2); 11 | 12 | for (int i = 0; i < n1; ++i) 13 | L[i] = arr[l + i]; 14 | for (int j = 0; j < n2; ++j) 15 | R[j] = arr[m + j + 1]; 16 | 17 | int i = 0, j = 0, k = l; 18 | 19 | while (i < n1 && j < n2) { 20 | if (L[i] <= R[j]) { 21 | arr[k] = L[i]; 22 | ++i; 23 | } else { 24 | arr[k] = R[j]; 25 | ++j; 26 | } 27 | ++k; 28 | } 29 | 30 | while (i < n1) { 31 | arr[k] = L[i]; 32 | ++i; 33 | ++k; 34 | } 35 | while (j < n2) { 36 | arr[k] = R[j]; 37 | ++j; 38 | ++k; 39 | } 40 | 41 | // Display the entire array after each merge operation 42 | for (int i = 0; i < arr.size(); ++i) { 43 | cout << arr[i]; 44 | if (i < arr.size() - 1) { 45 | cout << ' '; 46 | } 47 | } 48 | cout << endl; 49 | } 50 | 51 | void merge_sort(vector& arr, int left, int right) { 52 | if (left < right) { 53 | int mid = (left + right) / 2; 54 | 55 | merge_sort(arr, left, mid); 56 | merge_sort(arr, mid + 1, right); 57 | 58 | merge(arr, left, mid, right); 59 | } 60 | } 61 | 62 | int main() { 63 | int n; 64 | cin >> n; 65 | vector arr(n); 66 | for (int i = 0; i < n; ++i) { 67 | cin >> arr[i]; 68 | } 69 | 70 | merge_sort(arr, 0, n - 1); 71 | 72 | system("pause"); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Homework-by-C++/Homework-Week-9/Hw 9_2 成绩排名.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct student 8 | { 9 | int id; 10 | int a; 11 | int b; 12 | }; 13 | 14 | int main() 15 | { 16 | int n; 17 | cin >> n; 18 | vector students(n); 19 | 20 | for(int i = 0; i < n; ++i) 21 | { 22 | cin >> students[i].id >> students[i].a >> students[i].b; 23 | } 24 | 25 | sort(students.begin(), students.end(), [](const student& x, const student& y) 26 | {return (x.a > y.a) || (x.a == y.a && x.b > y.b) || (x.a == y.a && x.b == y.b && x.id < y.id);}); 27 | 28 | for(int i = 0; i < n; ++i) 29 | { 30 | cout << students[i].id << endl; 31 | } 32 | 33 | system("pause"); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-1/Hw 1_1 最大公约数和最小公倍数.md: -------------------------------------------------------------------------------- 1 | # KEY POINTS ANALYSIS 2 | 3 | ```python 4 | def GCD(a,b): 5 | if b==0: 6 | return a 7 | else: 8 | return GCD(b,a%b) 9 | ``` 10 | 11 | ## Key Concepts 1 12 | 13 | 1. **Recursion**: The function calls itself to reduce the problem to smaller parts. 14 | 2. **Modulus Operator `%`**: Used to find the remainder when `a` is divided by `b`. 15 | 16 | ## Function Operation 1 17 | 18 | - `GCD(a, b)` calculates the Greatest Common Divisor of `a` and `b` using the Euclidean algorithm. 19 | - If `b == 0`, it returns `a`. 20 | - Otherwise, it recursively calls `GCD(b, a % b)`. 21 | 22 | *** 23 | 24 | ```python 25 | def LCM(a,b): 26 | return a*b//GCD(a,b) 27 | ``` 28 | 29 | ## Key Concepts 2 30 | 31 | 1. **LCM (Least Common Multiple)**: The smallest multiple that is evenly divisible by both `a` and `b`. 32 | 2. **Integer Division `//`**: Divides and rounds down to the nearest integer. (also called **Floor Division**) 33 | 34 | ## Function Operation 2 35 | 36 | - `LCM(a, b)` calculates the Least Common Multiple of `a` and `b` using the formula \( \text{LCM}(a, b) = \frac{a \times b}{\text{GCD}(a, b)} \). (refer to contents of number theory) 37 | 38 | *** 39 | 40 | ```python 41 | a,b=map(int,input().split()) 42 | ``` 43 | 44 | ## Key Concepts 3 45 | 46 | 1. **Tuple Unpacking**: `a, b = ...` assigns values to `a` and `b` simultaneously. 47 | 2. **`map()` Function**: Applies the `int` function to each element in the list. 48 | 3. **`input().split()`**: Reads a string from user input and splits it into a list. 49 | 50 | ## Function Operation 3 51 | 52 | - This line takes a space-separated string input, splits it into a list, converts each element to an integer, and then assigns them to `a` and `b`. 53 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-1/Hw 1_1 最大公约数和最小公倍数.py: -------------------------------------------------------------------------------- 1 | def GCD(a,b): 2 | if b==0: 3 | return a 4 | else: 5 | return GCD(b,a%b) 6 | 7 | def LCM(a,b): 8 | return a*b//GCD(a,b) 9 | 10 | a,b=map(int,input().split()) 11 | 12 | gcd_result = GCD(a,b) 13 | lcm_result = LCM(a,b) 14 | 15 | print (f"{gcd_result},{lcm_result}") 16 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-1/Hw 1_2 最大值和最小值.md: -------------------------------------------------------------------------------- 1 | # KEY POINTS ANALYSIS 2 | 3 | ## The `max()` function in python 4 | 5 | The `max()` function in Python is used to find the largest item among two or more arguments, or the largest item in an iterable like a list or a tuple. If you pass multiple individual values to `max()`, it returns the largest one. If you pass an iterable, it returns the largest item in that iterable. 6 | 7 | ### 1、With *individual arguments* 8 | 9 | ```python 10 | largest_number = max(3, 9, 5) 11 | # largest_number will be 9 12 | ``` 13 | 14 | ### 2、With an *iterable* 15 | 16 | ```python 17 | my_list = [1, 2, 3, 4, 5] 18 | largest_number = max(my_list) 19 | # largest_number will be 5 20 | ``` 21 | 22 | ### 3、With a *custom key function* 23 | 24 | We can also use a key function to customize the comparison. For example, to find the longest string in a list: 25 | 26 | ```python 27 | my_list = ["apple", "banana", "cherry"] 28 | longest_string = max(my_list, key=len) 29 | # longest_string will be 'banana' 30 | ``` 31 | 32 | Here, `key=len` specifies that the function `len` should be used for determining the "largeness" of each item. 33 | 34 | ### 4、With strings 35 | 36 | When used with strings, `max()` returns the string with the greatest lexicographical order (i.e., appears last in a dictionary). 37 | 38 | ```python 39 | largest_string = max("apple", "banana", "cherry") 40 | # largest_string will be 'cherry' 41 | ``` 42 | 43 | ***Notice: The `min()` function is the same*** 44 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-1/Hw 1_2 最大值和最小值.py: -------------------------------------------------------------------------------- 1 | N = int(input()) 2 | numbers = [] 3 | 4 | input_numbers = input() 5 | numbers = list(map(int,input_numbers.split())) 6 | 7 | maximum = max(numbers) 8 | minimum = min(numbers) 9 | 10 | result = maximum - minimum 11 | 12 | print(result) 13 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-1/Hw 1_3 数雷.md: -------------------------------------------------------------------------------- 1 | # KEY POINTS ANALYSIS 2 | 3 | ## Divide this code into 4 parts logically 4 | 5 | ### Part 1: `count_mines` Function 6 | 7 | ```python 8 | def count_mines(x, y, grid): 9 | count = 0 10 | directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] 11 | for dx, dy in directions: 12 | new_x, new_y = x + dx, y + dy 13 | if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]): 14 | if grid[new_x][new_y] == '*': 15 | count += 1 16 | return str(count) 17 | ``` 18 | 19 | - **Function Signature**: `count_mines(x, y, grid)` 20 | - `x` and `y`: coordinates in the grid. (coordinate means '坐标') 21 | - `grid`: 2D list representing the minefield. 22 | 23 | - **Variables**: 24 | - `count = 0`: Initialize mine counter. 25 | - `directions`: List of coordinate adjustments for neighboring cells. 26 | 27 | - **Loop for Counting Mines**: Iterates through `directions`, updates coordinates (`new_x`, `new_y`), and checks for mines (`*`). Updates `count` if a mine is found. 28 | - Special line ***(Boundary Check Condition)*** 29 | 30 | ```python 31 | if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]): 32 | ``` 33 | 34 | Key Concepts: 35 | 36 | 1. **Boundary Checking**: The line ensures that `(new_x, new_y)` lies within the grid dimensions. 37 | 38 | 2. **`len(grid)`**: This gives the number of rows in the 2D grid list. 39 | 40 | 3. **`len(grid[0])`**: This gives the number of columns in the 2D grid list. *(Normally:all rows have the same number of columns.)* 41 | 42 | Operation: 43 | 44 | - `0 <= new_x < len(grid)`: Makes sure that `new_x` is within the range of rows in the grid. 45 | 46 | - `0 <= new_y < len(grid[0])`: Ensures that `new_y` is within the range of columns in the grid. 47 | 48 | By using this condition, you're checking if the coordinates `(new_x, new_y)` are within the boundary of the 2D grid before attempting to access `grid[new_x][new_y]`. 49 | 50 | ### Part 2: Main Program Setup 51 | 52 | ```python 53 | # Number of test cases 54 | T = int(input()) 55 | 56 | all_outputs = [] 57 | ``` 58 | 59 | - **Variable `T`**: Number of test cases. 60 | - `T = int(input())`: Reads an integer from input. 61 | 62 | - **List `all_outputs`**: Stores output for each test case. 63 | 64 | ### Part 3: Loop for Each Test Case 65 | 66 | ```python 67 | for _ in range(T): 68 | # Read the dimensions of the grid 69 | x, y = map(int, input().split()) 70 | 71 | # Read the grid 72 | grid = [list(input()) for _ in range(x)] 73 | 74 | # Output grid 75 | output = [] 76 | 77 | for i in range(x): 78 | row = [] 79 | for j in range(y): 80 | if grid[i][j] == '*': 81 | row.append('*') 82 | else: 83 | row.append(count_mines(i, j, grid)) 84 | output.append(''.join(row)) 85 | all_outputs.append(output) 86 | ``` 87 | 88 | - **Grid Dimensions**: 89 | - `x, y = map(int, input().split())`: Reads grid dimensions. 90 | 91 | - **Reading the Grid**: 92 | - `grid = [list(input()) for _ in range(x)]`: Reads `x` rows of the grid. 93 | 94 | - **Initialize `output` List**: Stores the output grid for the current test case. 95 | 96 | - **`''.join(row)`:** The `join()` function joins all its (this refers to the list `row`) elements into a single string. The `''` serves as the separator between the list elements, meaning that the elements will be joined directly ***without any characters in between***. It can often be used in Python to efficiently concatenate strings. 97 | 98 | - **`output. append(''.join(row))`:** The `append()` method adds a new element to the end of a list. In this context, the element is the entire string you constructed with `join()`. Thus, each row of your grid, after being converted to a string, is stored as an element in the `output` list. This list becomes a sequence of strings, where each string represents a row in your grid. 99 | 100 | - **Why `output.append()` Adds to a New Line when printing**: When later printing each element of `output`, each one appears on a new line because of how the `print()` function works. By default, `print()` adds a newline character (`\n`) at the end of whatever it prints (This refers to every `list`) , thus moving the cursor to the beginning of the next line. 101 | 102 | ### Part 4: Display Output 103 | 104 | ```python 105 | for index, output in enumerate(all_outputs): 106 | for row in output: 107 | print(''.join(row)) 108 | if index < len(all_outputs) - 1: 109 | print() # Print a newline between test cases, but not after the last one 110 | ``` 111 | 112 | #### Key Concepts 113 | 114 | 1. **`enumerate()` Function**: This Python built-in function provides both the index and the value from the iterable. In this case, `index` is the current test case number, and `output` is the grid for that test case. 115 | 116 | - What Python's `enumerate()` Function Does: 117 | 118 | The `enumerate()` function takes an iterable (like a list, tuple, or string) and returns an iterator that produces tuples containing the index and the corresponding element from the iterable. 119 | 120 | - Basic Syntax: 121 | 122 | ```python 123 | enumerate(iterable, start=0) 124 | ``` 125 | 126 | - `iterable`: The collection you want to iterate over (list, tuple, etc.). 127 | - `start`: The index value from which enumeration starts (default is 0). 128 | 129 | - Basic Example: 130 | 131 | ```python 132 | fruits = ['apple', 'banana', 'cherry'] 133 | for index, element in enumerate(fruits): 134 | print(f"Index: {index}, Element: {element}") 135 | ``` 136 | 137 | Output: 138 | 139 | ```python 140 | Index: 0, Element: apple 141 | Index: 1, Element: banana 142 | Index: 2, Element: cherry 143 | ``` 144 | 145 | - How It Works: 146 | 147 | 1. **Initialization**: `enumerate()` takes `fruits` as input and starts with an index of 0. 148 | 149 | 2. **Iteration**: For each element in `fruits`, it returns a tuple of `(index, element)`. 150 | 151 | 3. **Output**: Inside the loop, `index` holds the current index, and `element` holds the value at that index in `fruits`. 152 | 153 | By using `enumerate()`, you can easily get both the index and the value during each iteration, making your code more readable and expressive. 154 | 155 | 2. **Nested `for` Loop**: Inside the main loop, another loop iterates through each `row` in the `output` grid. 156 | 157 | 3. **`if` Statement**: Checks whether to print an extra newline between test cases. 158 | 159 | #### Operation 160 | 161 | - `for index, output in enumerate(all_outputs)`: Loops through `all_outputs` while also keeping track of the current index (or test case number). 162 | 163 | - `for row in output`: Iterates through each row of the current `output` grid. 164 | 165 | - `print(''.join(row))`: Joins the elements in `row` into a single string and prints it. 166 | 167 | - `if index < len(all_outputs) - 1`: Checks if this is the last test case. 168 | 169 | - `print()`: Prints a newline between test cases, but not after the last one. 170 | 171 | The overall purpose of this block is to print each test case output, separated by a newline, except for the last test case. 172 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-1/Hw 1_3 数雷.py: -------------------------------------------------------------------------------- 1 | # Function to count the mines around a given cell 2 | def count_mines(x, y, grid): 3 | count = 0 4 | directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] 5 | for dx, dy in directions: 6 | new_x, new_y = x + dx, y + dy 7 | if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]): 8 | if grid[new_x][new_y] == '*': 9 | count += 1 10 | return str(count) 11 | 12 | T = int(input()) 13 | 14 | all_outputs = [] 15 | 16 | for _ in range(T): 17 | x, y = map(int, input().split()) 18 | 19 | grid = [list(input()) for _ in range(x)] 20 | 21 | output = [] 22 | 23 | for i in range(x): 24 | row = [] 25 | for j in range(y): 26 | if grid[i][j] == '*': 27 | row.append('*') 28 | else: 29 | row.append(count_mines(i, j, grid)) 30 | output.append(''.join(row)) 31 | all_outputs.append(output) 32 | 33 | for index, output in enumerate(all_outputs): 34 | for row in output: 35 | print(row) 36 | if index < len(all_outputs) - 1: 37 | print() 38 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-1/Hw 1_4 全排列.py: -------------------------------------------------------------------------------- 1 | def generate_permutations(arr, n, curr_permutation): 2 | if len(curr_permutation) == n: 3 | print(" ".join(map(str, curr_permutation))) 4 | return 5 | 6 | seen = set() 7 | for i in range(len(arr)): 8 | if arr[i] not in seen: 9 | seen.add(arr[i]) 10 | curr_permutation.append(arr[i]) 11 | next_arr = arr[:i] + arr[i+1:] 12 | generate_permutations(next_arr, n, curr_permutation) 13 | curr_permutation.pop() 14 | 15 | N = int(input()) 16 | arr = list(map(int, input().split())) 17 | 18 | generate_permutations(arr, N, []) 19 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-2/Hw 2 on choice.md: -------------------------------------------------------------------------------- 1 | # Calculate the time complexity 2 | 3 | ```c 4 | int sum = 0; 5 | for(int i=1;i 1: 7 | if n % 2 != 0: 8 | n = n * 3 + 1 9 | else: 10 | n = n // 2 11 | 12 | sequence.append(str(n)) 13 | 14 | score += 1 15 | 16 | print(" ".join(sequence)) 17 | 18 | print("count =", score) 19 | 20 | n = int(input()) 21 | hail_conjecture(n, 1) 22 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-2/Hw 2_2 打印图形.py: -------------------------------------------------------------------------------- 1 | def print_diamond(n): 2 | size = 2 * n - 1 3 | 4 | for i in range(1, size + 1, 2): 5 | spaces = (size - i) // 2 6 | 7 | print(" " * spaces + "*" * i + " " * spaces) 8 | 9 | for i in range(size - 2, 0, -2): 10 | spaces = (size - i) // 2 11 | 12 | print(" " * spaces + "*" * i + " " * spaces) 13 | 14 | n = int(input()) 15 | 16 | print_diamond(n) 17 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-4/Hw 4_1 字符串匹配问题.py: -------------------------------------------------------------------------------- 1 | def is_valid(s): 2 | stack = [] 3 | mapping = { 4 | ')': '(', 5 | ']': '[', 6 | '}': '{', 7 | '>': '<' 8 | } 9 | order = ['<', '(', '[', '{'] 10 | 11 | for char in s: 12 | if char in mapping.values(): 13 | if stack and order.index(stack[-1]) < order.index(char): 14 | return "NO" 15 | stack.append(char) 16 | elif char in mapping.keys(): 17 | if not stack or mapping[char] != stack.pop(): 18 | return "NO" 19 | else: 20 | return "NO" 21 | 22 | return "YES" if not stack else "NO" 23 | 24 | if __name__ == "__main__": 25 | n = int(input()) 26 | results = [] 27 | for _ in range(n): 28 | s = input() 29 | results.append(is_valid(s)) 30 | for res in results: 31 | print(res) 32 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-4/Hw 4_2 后缀表达式求值.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "def evaluate_postfix(expression):\n", 10 | " stack = []\n", 11 | "\n", 12 | " for token in expression:\n", 13 | " if token.isdigit() or (token[0] == '-' and token[1:].isdigit()): \n", 14 | " stack.append(int(token))\n", 15 | " else:\n", 16 | " if len(stack) < 2:\n", 17 | " return f\"Expression Error: {stack[-1]}\" if stack else \"Expression Error\"\n", 18 | " b = stack.pop()\n", 19 | " a = stack.pop()\n", 20 | "\n", 21 | " if token == '+':\n", 22 | " result = a + b\n", 23 | " elif token == '-':\n", 24 | " result = a - b\n", 25 | " elif token == '*':\n", 26 | " result = a * b\n", 27 | " elif token == '/':\n", 28 | " if b == 0:\n", 29 | " return f\"Error: {a}/0\"\n", 30 | " else:\n", 31 | " result = int(a / b)\n", 32 | " else:\n", 33 | " return \"Unknown operator\"\n", 34 | "\n", 35 | " stack.append(result)\n", 36 | "\n", 37 | " if len(stack) != 1:\n", 38 | " return f\"Expression Error: {stack[-1]}\"\n", 39 | "\n", 40 | " return stack[0]\n", 41 | "\n", 42 | "\n", 43 | "if __name__ == \"__main__\":\n", 44 | " postfix_expression = input().split()\n", 45 | " postfix_expression.pop()\n", 46 | "\n", 47 | " result = evaluate_postfix(postfix_expression)\n", 48 | "\n", 49 | " print(result)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "```python\n", 57 | "for token in expression:\n", 58 | "```\n", 59 | "Here, a `for` loop is initiated which iterates over each `token` in the provided `expression` list. Think of each `token` as an individual component of the expression; it can be either an operator (e.g., '+', '-', '*', '/') or an operand (i.e., a number).\n", 60 | "\n", 61 | "---\n", 62 | "\n", 63 | "```python\n", 64 | "if token.isdigit() or (token[0] == '-' and token[1:].isdigit()):\n", 65 | "```\n", 66 | "This is a conditional check to determine if the current `token` is a number.\n", 67 | "\n", 68 | "- `token.isdigit()`: This checks if the `token` consists only of digits, meaning it's a positive number (including 0).\n", 69 | "\n", 70 | "- `(token[0] == '-' and token[1:].isdigit())`: This checks if the `token` is a negative number. It first checks if the first character (`token[0]`) is a `-` sign, and then checks if the remainder of the `token` (from the second character onwards, represented by `token[1:]`) consists only of digits.\n", 71 | "\n", 72 | " - In Python, strings and lists share some similar properties, and one of those properties is slicing. You can indeed use slicing `[start:stop:step]` and indexing `[i]` on strings, just like you can with lists.\n", 73 | "\n", 74 | " - So when you see `token[0]` and `token[1:]`, it is using string slicing and indexing to refer to parts of the string `token`.\n", 75 | "\n", 76 | " - `token[0]` refers to the first character of the string `token`.\n", 77 | " - `token[1:]` refers to all characters in the string `token` from the second character to the end.\n", 78 | "\n", 79 | "Together, these checks ensure that the `token` is either a positive or a negative number (including 0).\n", 80 | "\n", 81 | "---\n", 82 | "\n", 83 | "```python\n", 84 | "stack.append(int(token))\n", 85 | "```\n", 86 | "If the above condition is true (i.e., the `token` is a number), this line of code will execute. Here, the `token` (which is a string representation of a number) is converted to an integer using the `int()` function. Then, this integer is appended to the `stack` list. This is essentially pushing the number onto the stack.\n", 87 | "\n", 88 | "---\n", 89 | "\n", 90 | "```python\n", 91 | "if len(stack) < 2:\n", 92 | "```\n", 93 | "Before processing an operator, we need to ensure that there are at least two operands on the stack, as the operators in this context (like '+', '-', '*', '/') are binary operators and require two operands. This line checks if the stack has fewer than two items.\n", 94 | "\n", 95 | "---\n", 96 | "\n", 97 | "```python\n", 98 | "return f\"Expression Error: {stack[-1]}\" if stack else \"Expression Error\"\n", 99 | "```\n", 100 | "If there are fewer than two items on the stack, this means there's an error in the postfix expression, as we can't perform any binary operation without two operands.\n", 101 | "\n", 102 | "- If the stack has at least one item, the error message will include the item at the top of the stack (`stack[-1]` refers to the last item in the list).\n", 103 | "\n", 104 | "- If the stack is empty, a general \"Expression Error\" message is returned.\n", 105 | "\n", 106 | "This code structure ensures that if there's an error in the expression, the function will immediately stop and return an error message." 107 | ] 108 | } 109 | ], 110 | "metadata": { 111 | "language_info": { 112 | "name": "python" 113 | } 114 | }, 115 | "nbformat": 4, 116 | "nbformat_minor": 2 117 | } 118 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-4/Hw 4_2 后缀表达式求值.py: -------------------------------------------------------------------------------- 1 | def evaluate_postfix(expression): 2 | stack = [] 3 | 4 | for token in expression: 5 | if token.isdigit() or (token[0] == '-' and token[1:].isdigit()): 6 | stack.append(int(token)) 7 | else: 8 | if len(stack) < 2: 9 | return f"Expression Error: {stack[-1]}" if stack else "Expression Error" 10 | b = stack.pop() 11 | a = stack.pop() 12 | 13 | if token == '+': 14 | result = a + b 15 | elif token == '-': 16 | result = a - b 17 | elif token == '*': 18 | result = a * b 19 | elif token == '/': 20 | if b == 0: 21 | return f"Error: {a}/0" 22 | result = int(a / b) 23 | else: 24 | return "Unknown operator" 25 | 26 | stack.append(result) 27 | 28 | if len(stack) != 1: 29 | return f"Expression Error: {stack[-1]}" 30 | 31 | return stack[0] 32 | 33 | 34 | if __name__ == "__main__": 35 | postfix_expression = input().split() 36 | postfix_expression.pop() 37 | 38 | result = evaluate_postfix(postfix_expression) 39 | 40 | print(result) 41 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-4/Hw 4_3 大師と仙人との奇遇.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | def calculate_profit(N, prices): 4 | # Using a list to represent the min-heap for bought stock prices 5 | bought_prices = [] 6 | # Total profit made 7 | total_profit = 0 8 | 9 | for i in range(N): 10 | # Buy a stock every day 11 | heapq.heappush(bought_prices, prices[i]) 12 | 13 | # If it's not the last day, check if there are any stocks to sell 14 | if i != N - 1: 15 | # Check the stock with the lowest purchase price 16 | while bought_prices and bought_prices[0] < prices[i + 1]: 17 | # Update the total profit by selling the stock 18 | total_profit += prices[i + 1] - heapq.heappop(bought_prices) 19 | 20 | # On the last day, sell all remaining stocks in hand 21 | else: 22 | while bought_prices: 23 | total_profit += prices[i] - heapq.heappop(bought_prices) 24 | 25 | return total_profit 26 | 27 | # Input 28 | N = int(input()) 29 | prices = list(map(int, input().split())) 30 | 31 | # Output 32 | print(calculate_profit(N, prices)) 33 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-5/Hw 5_1 插入排序.py: -------------------------------------------------------------------------------- 1 | def insertion_sort(arr): 2 | for i in range(1, len(arr)): 3 | key = arr[i] 4 | j = i - 1 5 | while j >= 0 and key < arr[j]: 6 | arr[j + 1] = arr[j] 7 | j -= 1 8 | arr[j + 1] = key 9 | print(" ".join(map(str, arr))) 10 | 11 | if __name__ == "__main__": 12 | N = int(input()) 13 | arr = list(map(int, input().split())) 14 | insertion_sort(arr) 15 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-8/Hw 8_1 冒泡排序.py: -------------------------------------------------------------------------------- 1 | def exchange(arr, i, j): 2 | arr[i], arr[j] = arr[j], arr[i] 3 | 4 | def compare(arr, i, j, exchanged): 5 | if arr[i] > arr[j]: 6 | exchange(arr, i, j) 7 | exchanged[0] = True # Use a mutable type like a list to reflect changes 8 | 9 | def display(arr): 10 | print(" ".join(map(str, arr))) 11 | 12 | def main(): 13 | N = int(input()) 14 | arr = list(map(int, input().split())) 15 | 16 | for i in range(N-1): 17 | exchanged = [False] 18 | for j in range(N-1-i): 19 | compare(arr, j, j+1, exchanged) 20 | if not exchanged[0]: 21 | break 22 | display(arr) 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-8/Hw 8_2 小球装箱游戏.py: -------------------------------------------------------------------------------- 1 | N = int(input()) 2 | balls = [] 3 | 4 | for _ in range(N): 5 | ball = list(map(int, input().split())) 6 | balls.append(ball) 7 | 8 | sorted_balls = sorted(balls, key = lambda x : (x[0], -x[1]), reverse=True) 9 | 10 | redA, greenA, redB, greenB = 0, 0, 0, 0 11 | 12 | for ball in sorted_balls[:N//2]: 13 | if ball[1] == 0: redA += 1 14 | else: greenA +=1 15 | 16 | for ball in sorted_balls[N//2:]: 17 | if ball[1] == 0: redB +=1 18 | else: greenB += 1 19 | 20 | print(redA, greenA) 21 | print(redB, greenB) 22 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-9/Hw 9_1 二路归并排序.py: -------------------------------------------------------------------------------- 1 | def merge_sort(arr, left, right): 2 | if left < right: 3 | mid = (left + right) // 2 4 | 5 | # Recursively sort first half and second half 6 | merge_sort(arr, left, mid) 7 | merge_sort(arr, mid + 1, right) 8 | 9 | # Merge the sorted halves 10 | merge(arr, left, mid, right) 11 | 12 | # Wrapper function to initiate the sort 13 | def initiate_merge_sort(arr): 14 | merge_sort(arr, 0, len(arr) - 1) 15 | 16 | # Define a merge function 17 | def merge(arr, left, mid, right): 18 | temp = [] 19 | i, j = left, mid + 1 20 | 21 | while i <= mid and j <= right: 22 | if arr[i] < arr[j]: 23 | temp.append(arr[i]) 24 | i += 1 25 | else: 26 | temp.append(arr[j]) 27 | j += 1 28 | 29 | temp.extend(arr[i:mid+1]) 30 | temp.extend(arr[j:right+1]) 31 | 32 | arr[left:right+1] = temp 33 | 34 | # Display the entire array after each merge operation 35 | print(" ".join(map(str, arr))) 36 | 37 | # Loop to read multiple sets of test data 38 | while True: 39 | try: 40 | n = int(input()) 41 | unsorted_arr = list(map(int, input().split())) 42 | initiate_merge_sort(unsorted_arr) 43 | except EOFError: 44 | break 45 | -------------------------------------------------------------------------------- /Homework-by-python/Homework-Week-9/Hw 9_2 成绩排名.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | n = int(input()) 3 | students = [] 4 | 5 | for i in range(n): 6 | student = list(map(int, input().split())) 7 | students.append(student) 8 | 9 | sorted_students = sorted(students, key = lambda x : (-x[1], -x[2], x[0])) 10 | 11 | for student in sorted_students: 12 | print(student[0]) 13 | 14 | if __name__ == "__main__": 15 | main() 16 | -------------------------------------------------------------------------------- /Lab-by-C++/Lab-1/Lab 1_1 模拟队列.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | int M; 9 | cin >> M; 10 | cin.ignore(); // Clear the newline character from the buffer 11 | queue myQueue; 12 | 13 | for (int i = 0; i < M; ++i) { 14 | string command; 15 | cin >> command; 16 | 17 | if (command == "push") { 18 | string value; 19 | cin >> value; // Read the value to be pushed 20 | cin.ignore(); // Clear the newline character from the buffer 21 | myQueue.push(value); 22 | } 23 | else if (command == "pop") { 24 | if (!myQueue.empty()) { 25 | myQueue.pop(); 26 | } 27 | } 28 | else if (command == "empty") { 29 | if (myQueue.empty()) { 30 | cout << "YES" << endl; 31 | } else { 32 | cout << "NO" << endl; 33 | } 34 | } 35 | else if (command == "query") { 36 | if (!myQueue.empty()) { 37 | cout << myQueue.front() << endl; 38 | } else { 39 | cout << "Queue is empty, cannot query." << endl; 40 | } 41 | } 42 | } 43 | system("pause"); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Lab-by-C++/Lab-1/Lab 1_2 括弧匹配检验.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | string isValid(const string &s){ 9 | stack myStack; 10 | unordered_map mapping = { 11 | {')','('}, 12 | {']','['} 13 | }; 14 | 15 | for (char character : s){ 16 | if (mapping.find(character) != mapping.end()) { 17 | if (myStack.empty() || myStack.top() != mapping[character]) 18 | return "Wrong"; 19 | myStack.pop(); 20 | } 21 | else { 22 | myStack.push(character); 23 | } 24 | } 25 | return myStack.empty() ? "OK" : "Wrong"; 26 | } 27 | 28 | int main(){ 29 | string s, result; 30 | cin >> s; 31 | result = isValid(s); 32 | cout << result << endl; 33 | system("pause"); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /Lab-by-C++/Lab-1/Lab 1_3 胡同.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | string can_exit(const vector& entry_sequence, const vector& exit_sequence) 9 | { 10 | stack s; 11 | int entryIndex = 0; 12 | 13 | for(int car : exit_sequence) 14 | { 15 | while(s.empty() || s.top() != car) 16 | { 17 | if (entryIndex >= entry_sequence.size()) 18 | return "No"; 19 | s.push(entry_sequence[entryIndex]); 20 | entryIndex++; 21 | } 22 | s.pop(); 23 | } 24 | return "Yes"; 25 | } 26 | 27 | int main() 28 | { 29 | int T; 30 | cin >> T; 31 | vector results; 32 | 33 | while (T--) { 34 | int n; 35 | cin >> n; 36 | 37 | vector cars(2*n); 38 | for(int i = 0; i < 2*n; ++i) 39 | { 40 | cin >> cars[i]; 41 | } 42 | 43 | vector entry_sequence(cars.begin(), cars.begin()+n); 44 | vector exit_sequence(cars.begin() + n, cars.end()); 45 | 46 | results.push_back(can_exit(entry_sequence, exit_sequence)); 47 | } 48 | 49 | for(const string& res : results) 50 | { 51 | cout << res << endl; 52 | } 53 | 54 | system("pause"); 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-1/Lab 1_4 包装机.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | string packagingMachine(int n, int m, int s_max, vector>& tracks, const vector& operations) { 10 | stack basket; 11 | string conveyorBelt; 12 | 13 | for (int op : operations) { 14 | if (op == 0) { 15 | if (!basket.empty()) { 16 | conveyorBelt.push_back(basket.top()); 17 | basket.pop(); 18 | } 19 | } 20 | else { 21 | int trackIndex = op - 1; 22 | if (!tracks[trackIndex].empty()) { 23 | if (basket.size() < s_max) { 24 | basket.push(tracks[trackIndex].front()); 25 | tracks[trackIndex].pop(); 26 | } else { 27 | conveyorBelt.push_back(basket.top()); 28 | basket.pop(); 29 | basket.push(tracks[trackIndex].front()); 30 | tracks[trackIndex].pop(); 31 | } 32 | } 33 | } 34 | } 35 | return conveyorBelt; 36 | } 37 | 38 | int main() { 39 | int n, m, s_max; 40 | cin >> n >> m >> s_max; 41 | 42 | vector> tracks(n); 43 | for (int i = 0; i < n; ++i) { 44 | for (int j = 0; j < m; ++j) { 45 | char ch; 46 | cin >> ch; 47 | tracks[i].push(ch); 48 | } 49 | } 50 | 51 | vector operations; 52 | int op; 53 | while (cin >> op) { 54 | if (op != -1) 55 | operations.push_back(op); 56 | else break; 57 | } 58 | 59 | string result = packagingMachine(n, m, s_max, tracks, operations); 60 | cout << result << endl; 61 | 62 | system("pause"); 63 | return 0; 64 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-1/Lab 1_5 列车车厢重排.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void placeCar(int car, vector>& tracks) { 8 | for (vector& track : tracks) { 9 | if (track.back() > car) { 10 | track.push_back(car); 11 | return; 12 | } 13 | } 14 | tracks.push_back(vector{car}); 15 | } 16 | 17 | void printResult (int car, const vector>& tracks) { 18 | for (const auto& track : tracks) { // we use `vector` instead of `queue` because `queue` doesn't allow traversing 19 | if (find(track.begin(), track.end(), car) != track.end()) { 20 | for (int i = 0; i < track.size(); ++i) { 21 | if (i != track.size() - 1) { 22 | cout << track[i] << " "; 23 | } 24 | else cout << track[i] << endl; 25 | } 26 | } 27 | } 28 | cout << tracks.size() << endl; 29 | } 30 | 31 | /* 32 | void printResult (const vector>& tracks) { 33 | for (auto& track : tracks) { 34 | for (int i = 0; i < track.size(); ++i) { 35 | if (i != track.size() - 1) cout << track[i] << " "; 36 | else cout << track[i] << endl; 37 | } 38 | } 39 | cout << tracks.size() << endl; 40 | } 41 | Output all the tracks 42 | */ 43 | 44 | int main() { 45 | int n; 46 | cin >> n; 47 | vector> tracks; 48 | 49 | for (int i = 0; i < n; ++i) { 50 | int car; 51 | cin >> car; 52 | placeCar(car, tracks); 53 | } 54 | 55 | printResult(1, tracks); 56 | 57 | system("pause"); 58 | return 0; 59 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-2/Lab 2_1 冒泡排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void BubbleSort(vector& arr, int n) { 7 | for (int i = 0; i < n; ++i) { 8 | for (int j = n - 1; j > i; --j) { 9 | if (arr[j] < arr[j - 1]) { 10 | swap(arr[j], arr[j - 1]); 11 | } 12 | } 13 | if (i < 3) { 14 | for (int k = 0; k < n; ++k) { 15 | cout << arr[k] << " "; 16 | } 17 | cout << endl; 18 | } 19 | } 20 | } 21 | 22 | int main() { 23 | int n; 24 | cin >> n; 25 | vector arr(n); 26 | for (int i = 0; i < n; ++i) { 27 | cin >> arr[i]; 28 | } 29 | 30 | BubbleSort(arr, n); 31 | 32 | system("pause"); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Lab-by-C++/Lab-2/Lab 2_2 快速排序的过程.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | /* 7 | Note that the output will vary depending on the different partitioning strategies 8 | */ 9 | 10 | void printArr(const vector& arr) { 11 | for (int num : arr) { 12 | cout << num << " "; 13 | } 14 | cout << endl; 15 | } 16 | 17 | int partition(vector& arr, int low, int high) { 18 | int pivot = arr[low]; 19 | int i = low + 1; 20 | 21 | for (int j = low + 1; j <= high; ++j) { 22 | if (arr[j] < pivot) { 23 | swap(arr[i], arr[j]); 24 | i++; 25 | } 26 | } 27 | swap(arr[i - 1], arr[low]); 28 | return i - 1; 29 | } 30 | 31 | void quickSort(vector& arr, int low, int high) { 32 | if (low < high) { 33 | int pi = partition(arr, low, high); 34 | 35 | printArr(arr); 36 | 37 | quickSort(arr, low, pi - 1); 38 | quickSort(arr, pi + 1, high); 39 | } 40 | } 41 | 42 | int main() { 43 | int n; 44 | cin >> n; 45 | vector arr(n); 46 | 47 | for (int i = 0; i < n; ++i) { 48 | cin >> arr[i]; 49 | } 50 | 51 | quickSort(arr, 0, n - 1); 52 | 53 | system("pause"); 54 | return 0; 55 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-2/Lab 2_3 数表.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | int n; 9 | cin >> n; 10 | vector arr(n); 11 | vector result; 12 | 13 | for (int i = 0; i < n; ++i) { 14 | cin >> arr[i]; 15 | } 16 | 17 | for (int i = 0; i < n; ++i) { 18 | for (int j = i + 1; j < n; ++j) { 19 | result.push_back(arr[i] + arr[j]); 20 | } 21 | } 22 | sort(result.begin(), result.end()); 23 | 24 | for (size_t i = 0; i < result.size(); ++i) { 25 | cout << result[i]; 26 | if (i < result.size() - 1) { 27 | cout << " "; 28 | } 29 | } 30 | cout << endl; 31 | 32 | system("pause"); 33 | return 0; 34 | 35 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-2/Lab 2_4 求交换次数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | long merge(vector& arr, int l, int m, int r) { 7 | long count = 0; 8 | int i = l, j = m + 1; 9 | vector temp; 10 | 11 | while (i <= m && j <= r) { 12 | if (arr[i] <= arr[j]) { 13 | temp.push_back(arr[i++]); 14 | } else { 15 | temp.push_back(arr[j++]); 16 | count += (m + 1 - i); 17 | } 18 | } 19 | while (i <= m) temp.push_back(arr[i++]); 20 | while (j <= r) temp.push_back(arr[j++]); 21 | 22 | for (int k = 0; k < temp.size(); ++k) { 23 | arr[l + k] = temp[k]; 24 | } 25 | 26 | return count; 27 | } 28 | 29 | long mergeSort(vector& arr, int l, int r) { 30 | if (l < r) { 31 | int m = (l + r) / 2; 32 | long count = mergeSort(arr, l, m) + mergeSort(arr, m + 1, r); 33 | count += merge(arr, l, m, r); 34 | return count; 35 | } else return 0; 36 | } 37 | 38 | int main() { 39 | int t; 40 | cin >> t; 41 | vector results(t); 42 | 43 | for (int i = 0; i < t; ++i) { 44 | int n; 45 | cin >> n; 46 | vector arr(n); 47 | for (int j = 0; j < n; ++j) { 48 | cin >> arr[j]; 49 | } 50 | results[i] = mergeSort(arr, 0, n - 1); 51 | } 52 | 53 | for (int i = 0; i < t; ++i) { 54 | cout << "Scenario #" << i + 1 << ":" << endl; 55 | cout << results[i] << endl; 56 | cout << endl; 57 | } 58 | 59 | system("pause"); 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /Lab-by-C++/Lab-2/Lab 2_5 最大三角形.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void findBiggestPerimeterTriangle(int n, vector& arr) { 8 | if (n < 3) { 9 | cout << "小棍的个数不能组成三角形" << endl; 10 | } else { 11 | sort(arr.begin(), arr.end(), greater()); 12 | for (int i = 0; i < n - 2; ++i) { 13 | if (arr[i] < arr[i + 1] + arr[i + 2]) { 14 | cout << "最大三角形的周长是" << arr[i] + arr[i + 1] + arr[i + 2] << endl; 15 | cout << "组成最大三角形的三条边是" << arr[i + 2] << "," << arr[i + 1] << "," << arr[i] << endl; 16 | return; 17 | } 18 | } 19 | } 20 | } 21 | 22 | int main() { 23 | int n; 24 | cin >> n; 25 | vector arr(n); 26 | 27 | for (int i = 0; i < n; ++i) { 28 | cin >> arr[i]; 29 | } 30 | 31 | findBiggestPerimeterTriangle(n, arr); 32 | 33 | system("pause"); 34 | return 0; 35 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-3/Lab 3_1 正整数质因数分解.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | void find_prime_factors(int number) { 6 | vector prime(number + 1, true); 7 | prime[0] = prime[1] = false; 8 | 9 | for (int i = 2; i * i <= number; i++) { 10 | if (prime[i]) { 11 | for (int j = i * 2; j <= number; j += i) { 12 | prime[j] = false; 13 | } 14 | } 15 | } 16 | 17 | bool firstPrint = true; 18 | for (int i = 2; i <= number; i++) { 19 | if (prime[i] && number % i == 0) { 20 | if (!firstPrint) { 21 | cout << " "; 22 | } 23 | cout << i; 24 | firstPrint = false; 25 | } 26 | } 27 | } 28 | 29 | int main() { 30 | int n; 31 | cin >> n; 32 | find_prime_factors(n); 33 | return 0; 34 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-3/Lab 3_2 二分查找.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | void print(const vector& arr) { 7 | for (int i = 0; i < arr.size() - 1; i++) 8 | cout << arr[i] << " "; 9 | cout << arr[arr.size() - 1]; 10 | } 11 | 12 | int binary_search(const vector& arr, int target) { 13 | int begin = 0; 14 | int end = arr.size() - 1; 15 | while (begin <= end) { 16 | int mid = begin + (end - begin) / 2; 17 | if (arr[mid] > target) 18 | end = mid - 1; 19 | else if (arr[mid] < target) 20 | begin = mid + 1; 21 | else 22 | return mid + 1; 23 | } 24 | return 0; 25 | } 26 | 27 | int main() { 28 | int n, m; 29 | while (cin >> n) { 30 | vector arr(n); 31 | for (int i = 0; i < n; i++) 32 | cin >> arr[i]; 33 | sort(arr.begin(), arr.end()); 34 | print(arr); 35 | cout << endl; 36 | 37 | cin >> m; 38 | vector res; 39 | while (m--) { 40 | int num; cin >> num; 41 | res.push_back(binary_search(arr, num)); 42 | } 43 | print(res); 44 | cout< 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | void print(vector& arr) 10 | { 11 | for (int i = 0; i < arr.size() - 1; i++) 12 | cout << arr[i] << " "; 13 | cout << arr[arr.size() - 1]; 14 | 15 | } 16 | 17 | int main() 18 | { 19 | priority_queuelist; 20 | int n,m; cin >> n>>m; 21 | while (n--) 22 | { 23 | int num; cin >> num; 24 | list.push(num); 25 | } 26 | vectorarr; 27 | while (m--) 28 | { 29 | if (!list.empty()) 30 | { 31 | arr.push_back(list.top()); 32 | list.pop(); 33 | } 34 | } 35 | print(arr); 36 | cout << endl; 37 | 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-3/Lab 3_4 关于堆的判断.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | vector heap; 9 | map positionMap; 10 | 11 | void up(int idx) { 12 | while (idx > 1 && heap[idx] < heap[idx / 2]) { 13 | swap(heap[idx], heap[idx / 2]); 14 | positionMap[heap[idx]] = idx; 15 | positionMap[heap[idx / 2]] = idx / 2; 16 | idx /= 2; 17 | } 18 | } 19 | 20 | bool isRoot(int x) { 21 | return positionMap[x] == 1; 22 | } 23 | 24 | bool isParentOf(int x, int y) { 25 | return positionMap[x] == positionMap[y] / 2; 26 | } 27 | 28 | bool isChildOf(int x, int y) { 29 | return positionMap[y] == positionMap[x] / 2; 30 | } 31 | 32 | bool areSiblings(int x, int y) { 33 | return positionMap[x] / 2 == positionMap[y] / 2; 34 | } 35 | 36 | int main() { 37 | int n, m; 38 | cin >> n >> m; 39 | heap.resize(n + 1); 40 | for (int i = 1; i <= n; ++i) { 41 | cin >> heap[i]; 42 | positionMap[heap[i]] = i; 43 | up(i); 44 | } 45 | 46 | while (m--) { 47 | int x; 48 | string rel, temp; 49 | cin >> x >> rel; 50 | if (rel == "is") { 51 | cin >> temp; 52 | if (temp == "the") { 53 | cin >> temp; 54 | if (temp == "root") { 55 | cout << (isRoot(x) ? "T" : "F") << endl; 56 | } else { // "parent" 57 | cin >> temp; 58 | int y; 59 | cin >> y; 60 | cout << (isParentOf(x, y) ? "T" : "F") << endl; 61 | } 62 | } else { // "a" child 63 | cin >> temp >> temp; 64 | int y; 65 | cin >> y; 66 | cout << (isChildOf(x, y) ? "T" : "F") << endl; 67 | } 68 | } else { // "and" 69 | int y; 70 | cin >> y >> temp >> temp; 71 | cout << (areSiblings(x, y) ? "T" : "F") << endl; 72 | } 73 | } 74 | 75 | return 0; 76 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-3/Lab 3_5 浦島太郎の玉手箱開き.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | vector calculate_averages(int n, const vector& numbers) { 9 | priority_queue max_heap; // Max-heap for the lower half 10 | priority_queue, greater> min_heap; // Min-heap for the upper half 11 | 12 | vector averages; // To store the result 13 | averages.reserve(n); // Reserve space for efficiency 14 | 15 | int current_min = numbers[0]; 16 | int current_max = numbers[0]; 17 | 18 | for (int number : numbers) { 19 | current_min = min(current_min, number); 20 | current_max = max(current_max, number); 21 | 22 | if (max_heap.empty() || number <= max_heap.top()) { 23 | max_heap.push(number); 24 | } else { 25 | min_heap.push(number); 26 | } 27 | 28 | // Balance the heaps if necessary 29 | if (max_heap.size() > min_heap.size() + 1) { 30 | min_heap.push(max_heap.top()); 31 | max_heap.pop(); 32 | } else if (min_heap.size() > max_heap.size()) { 33 | max_heap.push(min_heap.top()); 34 | min_heap.pop(); 35 | } 36 | 37 | // Calculate the average based on the number of elements 38 | int average; 39 | if (max_heap.size() == min_heap.size()) { 40 | // Even number of elements 41 | int median1 = max_heap.top(); 42 | int median2 = min_heap.top(); 43 | average = (current_min + current_max + median1 + median2) / 4; 44 | } else { 45 | // Odd number of elements 46 | int median = max_heap.top(); 47 | average = (current_min + current_max + median) / 3; 48 | } 49 | 50 | averages.push_back(average); 51 | } 52 | 53 | return averages; 54 | } 55 | 56 | int main() { 57 | ios_base::sync_with_stdio(false); // Speed up cin and cout 58 | cin.tie(nullptr); // Untie cin and cout 59 | 60 | int n; 61 | cin >> n; 62 | 63 | vector numbers(n); 64 | for (int& number : numbers) { 65 | cin >> number; 66 | } 67 | 68 | vector averages = calculate_averages(n, numbers); 69 | 70 | for (size_t i = 0; i < averages.size(); ++i) { 71 | cout << averages[i]; 72 | if (i < averages.size() - 1) { 73 | cout << " "; 74 | } 75 | } 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /Lab-by-C++/Lab-4/Lab 4_1 求同年同月同日生的最大人数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | int main() { 10 | int n; 11 | cin >> n; 12 | unordered_map storage; 13 | int maxCount = 0; 14 | while (n--) { 15 | string birth; 16 | cin >> birth; 17 | storage[birth]++; 18 | if (maxCount < storage[birth]) 19 | maxCount = storage[birth]; 20 | } 21 | 22 | cout << maxCount << endl; 23 | 24 | vector maxDates; 25 | for (const auto& it : storage) { 26 | if (it.second == maxCount) { 27 | maxDates.push_back(it.first); 28 | } 29 | } 30 | 31 | sort(maxDates.begin(), maxDates.end()); 32 | 33 | for (const string& date : maxDates) 34 | cout << date << endl; 35 | 36 | system("pause"); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-4/Lab 4_2 寻找签到题(二叉排序树).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | string findSignInProblem(int n, vector& colors) { 11 | unordered_map colorCount; 12 | 13 | for (const string& color : colors) { 14 | string lowerColor = color; 15 | transform(lowerColor.begin(), lowerColor.end(), lowerColor.begin(), [](char c){ 16 | return tolower(c); 17 | }); 18 | colorCount[lowerColor]++; 19 | } 20 | 21 | int maxCount = 0; 22 | string signInColor; 23 | for (const auto& entry : colorCount) { 24 | if (entry.second > maxCount || (entry.second == maxCount && entry.first < signInColor)) { 25 | maxCount = entry.second; 26 | signInColor = entry.first; 27 | } 28 | } 29 | 30 | return signInColor; 31 | } 32 | 33 | int main() { 34 | int t; 35 | cin >> t; 36 | 37 | for (int i = 0; i < t; ++i) { 38 | int n; 39 | cin >> n; 40 | vector colors(n); 41 | for (int j = 0; j < n; ++j) { 42 | cin >> colors[j]; 43 | } 44 | string signInColor = findSignInProblem(n, colors); 45 | cout << signInColor << endl; 46 | } 47 | 48 | system("pause"); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-4/Lab 4_3 航空公司VIP客户查询.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int main() { 6 | int n, k; 7 | cin >> n >> k; 8 | unordered_map hash; 9 | 10 | for (int i = 0; i < n; i++) { 11 | string ID; 12 | int mile; 13 | cin >> ID >> mile; 14 | if (mile < k) { 15 | mile = k; 16 | } 17 | hash[ID] += mile; 18 | } 19 | 20 | int m; 21 | cin >> m; 22 | for (int i = 0; i < m; i++) { 23 | string ID; 24 | cin >> ID; 25 | auto it = hash.find(ID); 26 | if (it != hash.end()) { 27 | cout << it->second << endl; 28 | } else { 29 | cout << "No Info" << endl; 30 | } 31 | } 32 | 33 | system("pause"); 34 | return 0; 35 | } -------------------------------------------------------------------------------- /Lab-by-C++/Lab-4/Lab 4_4 二叉搜索树的四种遍历.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 定义二叉树节点 6 | struct Node { 7 | int data; 8 | Node *left, *right; 9 | 10 | Node(int value) : data(value), left(nullptr), right(nullptr) {} 11 | }; 12 | 13 | // 插入新节点到BST 14 | Node* insert(Node* root, int value) { 15 | if (root == nullptr) { 16 | return new Node(value); 17 | } 18 | if (value < root->data) { 19 | root->left = insert(root->left, value); 20 | } else { 21 | root->right = insert(root->right, value); 22 | } 23 | return root; 24 | } 25 | 26 | // 前序遍历 27 | void preorder(Node* root) { 28 | if (root == nullptr) return; 29 | cout << root->data << " "; 30 | preorder(root->left); 31 | preorder(root->right); 32 | } 33 | 34 | // 中序遍历 35 | void inorder(Node* root) { 36 | if (root == nullptr) return; 37 | inorder(root->left); 38 | cout << root->data << " "; 39 | inorder(root->right); 40 | } 41 | 42 | // 后序遍历 43 | void postorder(Node* root) { 44 | if (root == nullptr) return; 45 | postorder(root->left); 46 | postorder(root->right); 47 | cout << root->data << " "; 48 | } 49 | 50 | // 层序遍历 51 | void levelorder(Node* root) { 52 | if (root == nullptr) return; 53 | queue q; 54 | q.push(root); 55 | while (!q.empty()) { 56 | Node* current = q.front(); 57 | q.pop(); 58 | cout << current->data << " "; 59 | if (current->left != nullptr) q.push(current->left); 60 | if (current->right != nullptr) q.push(current->right); 61 | } 62 | } 63 | 64 | int main() { 65 | int n; 66 | cin >> n; 67 | Node* root = nullptr; 68 | for (int i = 0; i < n; ++i) { 69 | int value; 70 | cin >> value; 71 | root = insert(root, value); 72 | } 73 | 74 | preorder(root); 75 | cout << endl; 76 | 77 | inorder(root); 78 | cout << endl; 79 | 80 | postorder(root); 81 | cout << endl; 82 | 83 | levelorder(root); 84 | cout << endl; 85 | 86 | system("pause"); 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /Lab-by-C++/Lab-4/Lab 4_5 平均查找长度之线性再散列.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | void print(vector& arr) 9 | { 10 | for (int i = 0; i < arr.size(); i++) 11 | cout << arr[i] << " "; 12 | } 13 | 14 | int main() 15 | { 16 | int n, m, p; cin >> n >> m >> p; 17 | int sum = 0; 18 | vectorarr(m); 19 | vectorjudge(m, true); 20 | for (int i = 0; i < n; i++) 21 | { 22 | int num; cin >> num; 23 | int count = 1; 24 | int index = num % p; 25 | if (judge[index]) 26 | { 27 | arr[index] = num; 28 | sum += count; 29 | judge[index] = false; 30 | } 31 | else 32 | { 33 | while (!judge[index]) 34 | { 35 | index=(index+1)%m; 36 | count++; 37 | } 38 | arr[index] = num; 39 | sum += count; 40 | judge[index] = false; 41 | } 42 | 43 | } 44 | cout << sum << '/' << n << endl; 45 | int sum1 = 0; 46 | for (int i = 0; i < p; i++) 47 | { 48 | int count = 1; int j = i; 49 | while (!judge[j]) 50 | { 51 | count++; 52 | j = (j + 1) % m; 53 | } 54 | 55 | sum1 += count; 56 | 57 | } 58 | cout << sum1<<'/'<