diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..97582fc5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +*.java linguist-language=Java +*.cs linguist-language=Java +*.py linguist-language=Python +*.cpp linguist-language=C++ +*.c linguist-language=C++ +*.go linguist-language=Go +*.js linguist-language=JavaScript +*.ts linguist-language=JavaScript +*.swift linguist-language=Swift + +*.zig linguist-language=Other +*.rs linguist-language=Other + +*.html linguist-detectable=false +*.css linguist-detectable=false diff --git a/codes/cpp/chapter_array_and_linkedlist/array.cpp b/codes/cpp/chapter_array_and_linkedlist/array.cpp index 6cf4919b..149a1ca2 100644 --- a/codes/cpp/chapter_array_and_linkedlist/array.cpp +++ b/codes/cpp/chapter_array_and_linkedlist/array.cpp @@ -23,6 +23,8 @@ int* extend(int* nums, int size, int enlarge) { for (int i = 0; i < size; i++) { res[i] = nums[i]; } + // 释放内存 + delete[] nums; // 返回扩展后的新数组 return res; } @@ -82,10 +84,7 @@ int main() { /* 长度扩展 */ int enlarge = 3; - int* res = extend(nums, size, enlarge); - int* temp = nums; - nums = res; - delete[] temp; + nums = extend(nums, size, enlarge); size += enlarge; cout << "将数组长度扩展至 8 ,得到 nums = "; PrintUtil::printArray(nums, size); @@ -107,5 +106,9 @@ int main() { int index = find(nums, size, 3); cout << "在 nums 中查找元素 3 ,得到索引 = " << index << endl; + // 释放内存 + delete[] arr; + delete[] nums; + return 0; } diff --git a/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp b/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp index 5e976a89..3e457891 100644 --- a/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp +++ b/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp @@ -83,5 +83,8 @@ int main() { int index = find(n0, 2); cout << "链表中值为 2 的结点的索引 = " << index << endl; + // 释放内存 + freeMemoryLinkedList(n0); + return 0; } diff --git a/codes/cpp/chapter_array_and_linkedlist/my_list.cpp b/codes/cpp/chapter_array_and_linkedlist/my_list.cpp index 0b550475..7349e6f1 100644 --- a/codes/cpp/chapter_array_and_linkedlist/my_list.cpp +++ b/codes/cpp/chapter_array_and_linkedlist/my_list.cpp @@ -20,6 +20,11 @@ public: nums = new int[numsCapacity]; } + /* 析构函数 */ + ~MyList() { + delete[] nums; + } + /* 获取列表长度(即当前元素数量)*/ int size() { return numsSize; @@ -90,14 +95,14 @@ public: void extendCapacity() { // 新建一个长度为 size * extendRatio 的数组,并将原数组拷贝到新数组 int newCapacity = capacity() * extendRatio; - int* extend = new int[newCapacity]; + int* tmp = nums; + nums = new int[newCapacity]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size(); i++) { - extend[i] = nums[i]; + nums[i] = tmp[i]; } - int* temp = nums; - nums = extend; - delete[] temp; + // 释放内存 + delete[] tmp; numsCapacity = newCapacity; } @@ -160,5 +165,8 @@ int main() { PrintUtil::printVector(vec); cout << "容量 = " << list->capacity() << " ,长度 = " << list->size() << endl; + // 释放内存 + delete list; + return 0; } diff --git a/codes/cpp/chapter_computational_complexity/leetcode_two_sum.cpp b/codes/cpp/chapter_computational_complexity/leetcode_two_sum.cpp index dd561d54..f68f242b 100644 --- a/codes/cpp/chapter_computational_complexity/leetcode_two_sum.cpp +++ b/codes/cpp/chapter_computational_complexity/leetcode_two_sum.cpp @@ -56,5 +56,9 @@ int main() { cout << "方法二 res = "; PrintUtil::printVector(res); + // 释放内存 + delete slt1; + delete slt2; + return 0; } diff --git a/codes/cpp/chapter_computational_complexity/space_complexity.cpp b/codes/cpp/chapter_computational_complexity/space_complexity.cpp index 6352b9d4..4a0e79ec 100644 --- a/codes/cpp/chapter_computational_complexity/space_complexity.cpp +++ b/codes/cpp/chapter_computational_complexity/space_complexity.cpp @@ -18,7 +18,7 @@ void constant(int n) { const int a = 0; int b = 0; vector nums(10000); - ListNode* node = new ListNode(0); + ListNode node(0); // 循环中的变量占用 O(1) 空间 for (int i = 0; i < n; i++) { int c = 0; @@ -34,9 +34,9 @@ void linear(int n) { // 长度为 n 的数组占用 O(n) 空间 vector nums(n); // 长度为 n 的列表占用 O(n) 空间 - vector nodes; + vector nodes; for (int i = 0; i < n; i++) { - nodes.push_back(new ListNode(i)); + nodes.push_back(ListNode(i)); } // 长度为 n 的哈希表占用 O(n) 空间 unordered_map map; @@ -98,5 +98,8 @@ int main() { TreeNode* root = buildTree(n); PrintUtil::printTree(root); + // 释放内存 + freeMemoryTree(root); + return 0; } diff --git a/codes/cpp/chapter_sorting/quick_sort.cpp b/codes/cpp/chapter_sorting/quick_sort.cpp index c298f5be..e72691bc 100644 --- a/codes/cpp/chapter_sorting/quick_sort.cpp +++ b/codes/cpp/chapter_sorting/quick_sort.cpp @@ -59,7 +59,7 @@ private: static int medianThree(vector& nums, int left, int mid, int right) { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; diff --git a/codes/cpp/chapter_stack_and_queue/array_queue.cpp b/codes/cpp/chapter_stack_and_queue/array_queue.cpp index de5e780f..56b086e7 100644 --- a/codes/cpp/chapter_stack_and_queue/array_queue.cpp +++ b/codes/cpp/chapter_stack_and_queue/array_queue.cpp @@ -21,6 +21,10 @@ public: nums = new int[capacity]; } + ~ArrayQueue() { + delete[] nums; + } + /* 获取队列的容量 */ int capacity() { return cap; @@ -117,5 +121,8 @@ int main() { PrintUtil::printVector(queue->toVector()); } + // 释放内存 + delete queue; + return 0; } diff --git a/codes/cpp/chapter_stack_and_queue/array_stack.cpp b/codes/cpp/chapter_stack_and_queue/array_stack.cpp index e6159e8c..7f705d7e 100644 --- a/codes/cpp/chapter_stack_and_queue/array_stack.cpp +++ b/codes/cpp/chapter_stack_and_queue/array_stack.cpp @@ -78,5 +78,8 @@ int main() { bool empty = stack->empty(); cout << "栈是否为空 = " << empty << endl; + // 释放内存 + delete stack; + return 0; } diff --git a/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp b/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp index ae22740d..6c830ff8 100644 --- a/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp +++ b/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp @@ -19,6 +19,11 @@ public: queSize = 0; } + ~LinkedListQueue() { + delete front; + delete rear; + } + /* 获取队列的长度 */ int size() { return queSize; @@ -108,5 +113,8 @@ int main() { bool empty = queue->empty(); cout << "队列是否为空 = " << empty << endl; + // 释放内存 + delete queue; + return 0; } diff --git a/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp b/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp index 495f2660..7b25a9e4 100644 --- a/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp +++ b/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp @@ -18,6 +18,10 @@ public: stkSize = 0; } + ~LinkedListStack() { + freeMemoryLinkedList(stackTop); + } + /* 获取栈的长度 */ int size() { return stkSize; @@ -97,5 +101,8 @@ int main() { bool empty = stack->empty(); cout << "栈是否为空 = " << empty << endl; + // 释放内存 + delete stack; + return 0; } diff --git a/codes/cpp/chapter_tree/binary_search_tree.cpp b/codes/cpp/chapter_tree/binary_search_tree.cpp index 006d7d30..cd6a712d 100644 --- a/codes/cpp/chapter_tree/binary_search_tree.cpp +++ b/codes/cpp/chapter_tree/binary_search_tree.cpp @@ -17,6 +17,10 @@ public: root = buildTree(nums, 0, nums.size() - 1); // 构建二叉搜索树 } + ~BinarySearchTree() { + freeMemoryTree(root); + } + /* 获取二叉树根结点 */ TreeNode* getRoot() { return root; @@ -82,9 +86,9 @@ public: // 找到待删除结点,跳出循环 if (cur->val == num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur->val < num) cur = cur->right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur->left; } // 若无待删除结点,则直接返回 @@ -152,5 +156,8 @@ int main() { cout << endl << "删除结点 4 后,二叉树为\n" << endl; PrintUtil::printTree(bst->getRoot()); + // 释放内存 + delete bst; + return 0; } diff --git a/codes/cpp/chapter_tree/binary_tree.cpp b/codes/cpp/chapter_tree/binary_tree.cpp index cd06778a..f6a0a5d8 100644 --- a/codes/cpp/chapter_tree/binary_tree.cpp +++ b/codes/cpp/chapter_tree/binary_tree.cpp @@ -37,5 +37,8 @@ int main() { cout << endl << "删除结点 P 后\n" << endl; PrintUtil::printTree(n1); + // 释放内存 + freeMemoryTree(n1); + return 0; } diff --git a/codes/cpp/include/ListNode.hpp b/codes/cpp/include/ListNode.hpp index 9e6bd069..7b1eb413 100644 --- a/codes/cpp/include/ListNode.hpp +++ b/codes/cpp/include/ListNode.hpp @@ -48,3 +48,18 @@ ListNode* getListNode(ListNode *head, int val) { } return head; } + +/** + * @brief Free the memory allocated to a linked list + * + * @param cur + */ +void freeMemoryLinkedList(ListNode *cur) { + // 释放内存 + ListNode *pre; + while (cur != nullptr) { + pre = cur; + cur = cur->next; + delete pre; + } +} diff --git a/codes/cpp/include/TreeNode.hpp b/codes/cpp/include/TreeNode.hpp index 82f2ce98..505c4069 100644 --- a/codes/cpp/include/TreeNode.hpp +++ b/codes/cpp/include/TreeNode.hpp @@ -68,3 +68,16 @@ TreeNode *getTreeNode(TreeNode *root, int val) { TreeNode *right = getTreeNode(root->right, val); return left != nullptr ? left : right; } + +/** + * @brief Free the memory allocated to a tree + * + * @param root + */ +void freeMemoryTree(TreeNode *root) { + if (root == nullptr) return; + freeMemoryTree(root->left); + freeMemoryTree(root->right); + // 释放内存 + delete root; +} diff --git a/codes/csharp/chapter_sorting/quick_sort.cs b/codes/csharp/chapter_sorting/quick_sort.cs index 020d4f34..90de5c19 100644 --- a/codes/csharp/chapter_sorting/quick_sort.cs +++ b/codes/csharp/chapter_sorting/quick_sort.cs @@ -65,7 +65,7 @@ namespace hello_algo.chapter_sorting { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; diff --git a/codes/csharp/chapter_tree/binary_search_tree.cs b/codes/csharp/chapter_tree/binary_search_tree.cs index e12cdd42..cb832769 100644 --- a/codes/csharp/chapter_tree/binary_search_tree.cs +++ b/codes/csharp/chapter_tree/binary_search_tree.cs @@ -94,9 +94,9 @@ namespace hello_algo.chapter_tree // 找到待删除结点,跳出循环 if (cur.val == num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur.val < num) cur = cur.right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur.left; } // 若无待删除结点,则直接返回 diff --git a/codes/go/chapter_heap/my_heap.go b/codes/go/chapter_heap/my_heap.go index 0b3d0a3b..ab870eec 100644 --- a/codes/go/chapter_heap/my_heap.go +++ b/codes/go/chapter_heap/my_heap.go @@ -24,7 +24,7 @@ func newHeap() *maxHeap { /* 构造函数,根据切片建堆 */ func newMaxHeap(nums []any) *maxHeap { - // 所有元素入堆 + // 将列表元素原封不动添加进堆 h := &maxHeap{data: nums} for i := len(h.data) - 1; i >= 0; i-- { // 堆化除叶结点以外的其他所有结点 @@ -98,6 +98,7 @@ func (h *maxHeap) poll() any { // 判空处理 if h.isEmpty() { fmt.Println("error") + return nil } // 交换根结点与最右叶结点(即交换首元素与尾元素) h.swap(0, h.size()-1) diff --git a/codes/go/chapter_sorting/quick_sort.go b/codes/go/chapter_sorting/quick_sort.go index 853bce45..ab7a2575 100644 --- a/codes/go/chapter_sorting/quick_sort.go +++ b/codes/go/chapter_sorting/quick_sort.go @@ -47,9 +47,11 @@ func (q *quickSort) quickSort(nums []int, left, right int) { /* 选取三个元素的中位数 */ func (q *quickSortMedian) medianThree(nums []int, left, mid, right int) int { - if (nums[left] > nums[mid]) != (nums[left] > nums[right]) { + // 使用了异或操作来简化代码(!= 在这里起到异或的作用) + // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 + if (nums[left] < nums[mid]) != (nums[left] < nums[right]) { return left - } else if (nums[mid] < nums[left]) != (nums[mid] > nums[right]) { + } else if (nums[mid] < nums[left]) != (nums[mid] < nums[right]) { return mid } return right diff --git a/codes/java/chapter_heap/heap.java b/codes/java/chapter_heap/heap.java index 1a0c53b9..35ca6af0 100644 --- a/codes/java/chapter_heap/heap.java +++ b/codes/java/chapter_heap/heap.java @@ -1,5 +1,5 @@ /** - * File: my_heap.java + * File: heap.java * Created Time: 2023-01-07 * Author: Krahets (krahets@163.com) */ diff --git a/codes/java/chapter_heap/my_heap.java b/codes/java/chapter_heap/my_heap.java index b80ce6d0..f823824e 100644 --- a/codes/java/chapter_heap/my_heap.java +++ b/codes/java/chapter_heap/my_heap.java @@ -20,7 +20,7 @@ class MaxHeap { /* 构造函数,根据输入列表建堆 */ public MaxHeap(List nums) { - // 所有元素入堆 + // 将列表元素原封不动添加进堆 maxHeap = new ArrayList<>(nums); // 堆化除叶结点以外的其他所有结点 for (int i = parent(size() - 1); i >= 0; i--) { diff --git a/codes/java/chapter_sorting/quick_sort.java b/codes/java/chapter_sorting/quick_sort.java index b121b757..1eaa1011 100644 --- a/codes/java/chapter_sorting/quick_sort.java +++ b/codes/java/chapter_sorting/quick_sort.java @@ -58,7 +58,7 @@ class QuickSortMedian { static int medianThree(int[] nums, int left, int mid, int right) { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; diff --git a/codes/java/chapter_tree/binary_search_tree.java b/codes/java/chapter_tree/binary_search_tree.java index a3b0f758..a0a554e3 100644 --- a/codes/java/chapter_tree/binary_search_tree.java +++ b/codes/java/chapter_tree/binary_search_tree.java @@ -83,9 +83,9 @@ class BinarySearchTree { // 找到待删除结点,跳出循环 if (cur.val == num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur.val < num) cur = cur.right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur.left; } // 若无待删除结点,则直接返回 diff --git a/codes/javascript/chapter_sorting/bubble_sort.js b/codes/javascript/chapter_sorting/bubble_sort.js index 3d3c6a83..6ddb0a17 100644 --- a/codes/javascript/chapter_sorting/bubble_sort.js +++ b/codes/javascript/chapter_sorting/bubble_sort.js @@ -11,10 +11,10 @@ function bubbleSort(nums) { // 内循环:冒泡操作 for (let j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // 交换 nums[j] 与 nums[j + 1] - let tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; + // 交换 nums[j] 与 nums[j + 1] + let tmp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = tmp; } } } @@ -40,10 +40,10 @@ function bubbleSortWithFlag(nums) { } /* Driver Code */ -var nums = [4, 1, 3, 1, 5, 2] -bubbleSort(nums) -console.log("排序后数组 nums =", nums) +const nums = [4, 1, 3, 1, 5, 2]; +bubbleSort(nums); +console.log("排序后数组 nums =", nums); -var nums1 = [4, 1, 3, 1, 5, 2] -bubbleSortWithFlag(nums1) -console.log("排序后数组 nums =", nums1) +const nums1 = [4, 1, 3, 1, 5, 2]; +bubbleSortWithFlag(nums1); +console.log("排序后数组 nums =", nums1); diff --git a/codes/javascript/chapter_sorting/insertion_sort.js b/codes/javascript/chapter_sorting/insertion_sort.js index 02c45a23..66264d23 100644 --- a/codes/javascript/chapter_sorting/insertion_sort.js +++ b/codes/javascript/chapter_sorting/insertion_sort.js @@ -19,6 +19,6 @@ function insertionSort(nums) { } /* Driver Code */ -var nums = [4, 1, 3, 1, 5, 2] -insertionSort(nums) -console.log("排序后数组 nums =", nums) +const nums = [4, 1, 3, 1, 5, 2]; +insertionSort(nums); +console.log('排序后数组 nums =', nums); diff --git a/codes/javascript/chapter_sorting/merge_sort.js b/codes/javascript/chapter_sorting/merge_sort.js index b00c17bc..4e2449af 100644 --- a/codes/javascript/chapter_sorting/merge_sort.js +++ b/codes/javascript/chapter_sorting/merge_sort.js @@ -5,10 +5,10 @@ */ /** -* 合并左子数组和右子数组 -* 左子数组区间 [left, mid] -* 右子数组区间 [mid + 1, right] -*/ + * 合并左子数组和右子数组 + * 左子数组区间 [left, mid] + * 右子数组区间 [mid + 1, right] + */ function merge(nums, left, mid, right) { // 初始化辅助数组 let tmp = nums.slice(left, right + 1); @@ -46,6 +46,6 @@ function mergeSort(nums, left, right) { } /* Driver Code */ -var nums = [ 7, 3, 2, 6, 0, 1, 5, 4 ] +const nums = [ 7, 3, 2, 6, 0, 1, 5, 4 ] mergeSort(nums, 0, nums.length - 1) -console.log("归并排序完成后 nums =", nums) +console.log('归并排序完成后 nums =', nums) diff --git a/codes/javascript/chapter_sorting/quick_sort.js b/codes/javascript/chapter_sorting/quick_sort.js index 405bf762..3915a178 100644 --- a/codes/javascript/chapter_sorting/quick_sort.js +++ b/codes/javascript/chapter_sorting/quick_sort.js @@ -8,38 +8,38 @@ class QuickSort { /* 元素交换 */ swap(nums, i, j) { - let tmp = nums[i] - nums[i] = nums[j] - nums[j] = tmp + let tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; } /* 哨兵划分 */ - partition(nums, left, right){ + partition(nums, left, right) { // 以 nums[left] 作为基准数 - let i = left, j = right - while(i < j){ - while(i < j && nums[j] >= nums[left]){ - j -= 1 // 从右向左找首个小于基准数的元素 + let i = left, j = right; + while (i < j) { + while (i < j && nums[j] >= nums[left]) { + j -= 1; // 从右向左找首个小于基准数的元素 } - while(i < j && nums[i] <= nums[left]){ - i += 1 // 从左向右找首个大于基准数的元素 + while (i < j && nums[i] <= nums[left]) { + i += 1; // 从左向右找首个大于基准数的元素 } // 元素交换 - this.swap(nums, i, j) // 交换这两个元素 + this.swap(nums, i, j); // 交换这两个元素 } - this.swap(nums, i, left) // 将基准数交换至两子数组的分界线 - return i // 返回基准数的索引 + this.swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 } /* 快速排序 */ - quickSort(nums, left, right){ + quickSort(nums, left, right) { // 子数组长度为 1 时终止递归 - if(left >= right) return + if (left >= right) return; // 哨兵划分 - const pivot = this.partition(nums, left, right) + const pivot = this.partition(nums, left, right); // 递归左子数组、右子数组 - this.quickSort(nums, left, pivot - 1) - this.quickSort(nums, pivot + 1, right) + this.quickSort(nums, left, pivot - 1); + this.quickSort(nums, pivot + 1, right); } } @@ -47,21 +47,18 @@ class QuickSort { class QuickSortMedian { /* 元素交换 */ swap(nums, i, j) { - let tmp = nums[i] - nums[i] = nums[j] - nums[j] = tmp + let tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; } /* 选取三个元素的中位数 */ medianThree(nums, left, mid, right) { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) - return left; - else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) - return mid; - else - return right; + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; + else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; + else return right; } /* 哨兵划分(三数取中值) */ @@ -73,14 +70,12 @@ class QuickSortMedian { // 以 nums[left] 作为基准数 let i = left, j = right; while (i < j) { - while (i < j && nums[j] >= nums[left]) - j--; // 从右向左找首个小于基准数的元素 - while (i < j && nums[i] <= nums[left]) - i++; // 从左向右找首个大于基准数的元素 + while (i < j && nums[j] >= nums[left]) j--; // 从右向左找首个小于基准数的元素 + while (i < j && nums[i] <= nums[left]) i++; // 从左向右找首个大于基准数的元素 this.swap(nums, i, j); // 交换这两个元素 } - this.swap(nums, i, left); // 将基准数交换至两子数组的分界线 - return i; // 返回基准数的索引 + this.swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 } /* 快速排序 */ @@ -99,9 +94,9 @@ class QuickSortMedian { class QuickSortTailCall { /* 元素交换 */ swap(nums, i, j) { - let tmp = nums[i] - nums[i] = nums[j] - nums[j] = tmp + let tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; } /* 哨兵划分 */ @@ -109,13 +104,11 @@ class QuickSortTailCall { // 以 nums[left] 作为基准数 let i = left, j = right; while (i < j) { - while (i < j && nums[j] >= nums[left]) - j--; // 从右向左找首个小于基准数的元素 - while (i < j && nums[i] <= nums[left]) - i++; // 从左向右找首个大于基准数的元素 + while (i < j && nums[j] >= nums[left]) j--; // 从右向左找首个小于基准数的元素 + while (i < j && nums[i] <= nums[left]) i++; // 从左向右找首个大于基准数的元素 this.swap(nums, i, j); // 交换这两个元素 } - this.swap(nums, i, left); // 将基准数交换至两子数组的分界线 + this.swap(nums, i, left); // 将基准数交换至两子数组的分界线 return i; // 返回基准数的索引 } @@ -127,8 +120,8 @@ class QuickSortTailCall { let pivot = this.partition(nums, left, right); // 对两个子数组中较短的那个执行快排 if (pivot - left < right - pivot) { - this.quickSort(nums, left, pivot - 1); // 递归排序左子数组 - left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right] + this.quickSort(nums, left, pivot - 1); // 递归排序左子数组 + left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right] } else { this.quickSort(nums, pivot + 1, right); // 递归排序右子数组 right = pivot - 1; // 剩余待排序区间为 [left, pivot - 1] @@ -139,19 +132,19 @@ class QuickSortTailCall { /* Driver Code */ /* 快速排序 */ -var nums = [4, 1, 3, 1, 5, 2] -var quickSort = new QuickSort() -quickSort.quickSort(nums, 0, nums.length - 1) -console.log("快速排序完成后 nums =", nums) +const nums = [4, 1, 3, 1, 5, 2]; +const quickSort = new QuickSort(); +quickSort.quickSort(nums, 0, nums.length - 1); +console.log('快速排序完成后 nums =', nums); /* 快速排序(中位基准数优化) */ -nums1 = [4, 1, 3, 1, 5,2] -var quickSortMedian = new QuickSort() -quickSortMedian.quickSort(nums1, 0, nums1.length - 1) -console.log("快速排序(中位基准数优化)完成后 nums =", nums1) +const nums1 = [4, 1, 3, 1, 5, 2]; +const quickSortMedian = new QuickSort(); +quickSortMedian.quickSort(nums1, 0, nums1.length - 1); +console.log('快速排序(中位基准数优化)完成后 nums =', nums1); /* 快速排序(尾递归优化) */ -nums2 = [4, 1, 3, 1, 5, 2] -var quickSortTailCall = new QuickSort() -quickSortTailCall.quickSort(nums2, 0, nums2.length - 1) -console.log("快速排序(尾递归优化)完成后 nums =", nums2) +const nums2 = [4, 1, 3, 1, 5, 2]; +const quickSortTailCall = new QuickSort(); +quickSortTailCall.quickSort(nums2, 0, nums2.length - 1); +console.log('快速排序(尾递归优化)完成后 nums =', nums2); diff --git a/codes/javascript/chapter_tree/binary_search_tree.js b/codes/javascript/chapter_tree/binary_search_tree.js index 9c808aaa..d619ab9f 100644 --- a/codes/javascript/chapter_tree/binary_search_tree.js +++ b/codes/javascript/chapter_tree/binary_search_tree.js @@ -80,9 +80,9 @@ function remove(num) { // 找到待删除结点,跳出循环 if (cur.val === num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur.val < num) cur = cur.right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur.left; } // 若无待删除结点,则直接返回 diff --git a/codes/python/chapter_sorting/quick_sort.py b/codes/python/chapter_sorting/quick_sort.py index f5ce8120..75245b61 100644 --- a/codes/python/chapter_sorting/quick_sort.py +++ b/codes/python/chapter_sorting/quick_sort.py @@ -42,7 +42,7 @@ class QuickSortMedian: def median_three(self, nums, left, mid, right): # 使用了异或操作来简化代码 # 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if (nums[left] > nums[mid]) ^ (nums[left] > nums[right]): + if (nums[left] < nums[mid]) ^ (nums[left] < nums[right]): return left elif (nums[mid] < nums[left]) ^ (nums[mid] > nums[right]): return mid diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index 8817d4a5..fdedf6c9 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -94,9 +94,9 @@ class BinarySearchTree: if cur.val == num: break pre = cur - if cur.val < num: # 待删除结点在 root 的右子树中 + if cur.val < num: # 待删除结点在 cur 的右子树中 cur = cur.right - else: # 待删除结点在 root 的左子树中 + else: # 待删除结点在 cur 的左子树中 cur = cur.left # 若无待删除结点,则直接返回 diff --git a/codes/swift/Package.swift b/codes/swift/Package.swift index 89c03d9f..c20c58f9 100644 --- a/codes/swift/Package.swift +++ b/codes/swift/Package.swift @@ -19,6 +19,7 @@ let package = Package( .executable(name: "queue", targets: ["queue"]), .executable(name: "linkedlist_queue", targets: ["linkedlist_queue"]), .executable(name: "array_queue", targets: ["array_queue"]), + .executable(name: "deque", targets: ["deque"]), ], targets: [ .target(name: "utils", path: "utils"), @@ -36,5 +37,6 @@ let package = Package( .executableTarget(name: "queue", path: "chapter_stack_and_queue", sources: ["queue.swift"]), .executableTarget(name: "linkedlist_queue", dependencies: ["utils"], path: "chapter_stack_and_queue", sources: ["linkedlist_queue.swift"]), .executableTarget(name: "array_queue", path: "chapter_stack_and_queue", sources: ["array_queue.swift"]), + .executableTarget(name: "deque", path: "chapter_stack_and_queue", sources: ["deque.swift"]), ] ) diff --git a/codes/swift/chapter_stack_and_queue/deque.swift b/codes/swift/chapter_stack_and_queue/deque.swift new file mode 100644 index 00000000..6638eacb --- /dev/null +++ b/codes/swift/chapter_stack_and_queue/deque.swift @@ -0,0 +1,44 @@ +/** + * File: deque.swift + * Created Time: 2023-01-14 + * Author: nuomi1 (nuomi1@qq.com) + */ + +@main +enum Deque { + /* Driver Code */ + static func main() { + /* 初始化双向队列 */ + // Swift 没有内置的双向队列类,可以把 Array 当作双向队列来使用 + var deque: [Int] = [] + + /* 元素入队 */ + deque.append(2) + deque.append(5) + deque.append(4) + deque.insert(3, at: 0) + deque.insert(1, at: 0) + print("双向队列 deque = \(deque)") + + /* 访问元素 */ + let peekFirst = deque.first! + print("队首元素 peekFirst = \(peekFirst)") + let peekLast = deque.last! + print("队尾元素 peekLast = \(peekLast)") + + /* 元素出队 */ + // 使用 Array 模拟时 pollFirst 的复杂度为 O(n) + let pollFirst = deque.removeFirst() + print("队首出队元素 pollFirst = \(pollFirst),队首出队后 deque = \(deque)") + let pollLast = deque.removeLast() + print("队尾出队元素 pollLast = \(pollLast),队尾出队后 deque = \(deque)") + + /* 获取双向队列的长度 */ + let size = deque.count + print("双向队列长度 size = \(size)") + + /* 判断双向队列是否为空 */ + let isEmpty = deque.isEmpty + print("双向队列是否为空 = \(isEmpty)") + } +} diff --git a/codes/swift/chapter_stack_and_queue/queue.swift b/codes/swift/chapter_stack_and_queue/queue.swift index f13af36f..ea1e9472 100644 --- a/codes/swift/chapter_stack_and_queue/queue.swift +++ b/codes/swift/chapter_stack_and_queue/queue.swift @@ -25,6 +25,7 @@ enum Queue { print("队首元素 peek = \(peek)") /* 元素出队 */ + // 使用 Array 模拟时 poll 的复杂度为 O(n) let pool = queue.removeFirst() print("出队元素 poll = \(pool),出队后 queue = \(queue)") diff --git a/codes/typescript/chapter_sorting/merge_sort.ts b/codes/typescript/chapter_sorting/merge_sort.ts index a4cb5e1c..75450294 100644 --- a/codes/typescript/chapter_sorting/merge_sort.ts +++ b/codes/typescript/chapter_sorting/merge_sort.ts @@ -23,10 +23,10 @@ function merge(nums: number[], left: number, mid: number, right: number): void { // 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++ if (i > leftEnd) { nums[k] = tmp[j++]; - // 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++ + // 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++ } else if (j > rightEnd || tmp[i] <= tmp[j]) { nums[k] = tmp[i++]; - // 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ + // 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ } else { nums[k] = tmp[j++]; } diff --git a/codes/typescript/chapter_sorting/quick_sort.ts b/codes/typescript/chapter_sorting/quick_sort.ts index 6379e08f..1f6de5a3 100644 --- a/codes/typescript/chapter_sorting/quick_sort.ts +++ b/codes/typescript/chapter_sorting/quick_sort.ts @@ -58,7 +58,7 @@ class QuickSortMedian { medianThree(nums: number[], left: number, mid: number, right: number): number { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if (Number(nums[left] > nums[mid]) ^ Number(nums[left] > nums[right])) { + if (Number(nums[left] < nums[mid]) ^ Number(nums[left] < nums[right])) { return left; } else if (Number(nums[mid] < nums[left]) ^ Number(nums[mid] < nums[right])) { return mid; diff --git a/codes/typescript/chapter_tree/binary_search_tree.ts b/codes/typescript/chapter_tree/binary_search_tree.ts index 9adf8cd1..a19ea32a 100644 --- a/codes/typescript/chapter_tree/binary_search_tree.ts +++ b/codes/typescript/chapter_tree/binary_search_tree.ts @@ -97,9 +97,9 @@ function remove(num: number): TreeNode | null { } pre = cur; if (cur.val < num) { - cur = cur.right as TreeNode; // 待删除结点在 root 的右子树中 + cur = cur.right as TreeNode; // 待删除结点在 cur 的右子树中 } else { - cur = cur.left as TreeNode; // 待删除结点在 root 的左子树中 + cur = cur.left as TreeNode; // 待删除结点在 cur 的左子树中 } } // 若无待删除结点,则直接返回 diff --git a/codes/zig/build.zig b/codes/zig/build.zig index a8738fae..cc0a1f18 100644 --- a/codes/zig/build.zig +++ b/codes/zig/build.zig @@ -160,6 +160,75 @@ pub fn build(b: *std.build.Builder) void { const run_step_array_stack = b.step("run_array_stack", "Run array_stack"); run_step_array_stack.dependOn(&run_cmd_array_stack.step); + // Section: "Hash Map" + // Source File: "chapter_hashing/hash_map.zig" + // Run Command: zig build run_hash_map + const exe_hash_map = b.addExecutable("hash_map", "chapter_hashing/hash_map.zig"); + exe_hash_map.addPackagePath("include", "include/include.zig"); + exe_hash_map.setTarget(target); + exe_hash_map.setBuildMode(mode); + exe_hash_map.install(); + const run_cmd_hash_map = exe_hash_map.run(); + run_cmd_hash_map.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd_hash_map.addArgs(args); + const run_step_hash_map= b.step("run_hash_map", "Run hash_map"); + run_step_hash_map.dependOn(&run_cmd_hash_map.step); + + // Section: "Binary Tree" + // Source File: "chapter_tree/binary_tree.zig" + // Run Command: zig build run_binary_tree + const exe_binary_tree = b.addExecutable("hash_map", "chapter_tree/binary_tree.zig"); + exe_binary_tree.addPackagePath("include", "include/include.zig"); + exe_binary_tree.setTarget(target); + exe_binary_tree.setBuildMode(mode); + exe_binary_tree.install(); + const run_cmd_binary_tree = exe_binary_tree.run(); + run_cmd_binary_tree.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd_binary_tree.addArgs(args); + const run_step_binary_tree= b.step("run_binary_tree", "Run binary_tree"); + run_step_binary_tree.dependOn(&run_cmd_binary_tree.step); + + // Section: "Heap" + // Source File: "chapter_heap/heap.zig" + // Run Command: zig build run_heap + const exe_heap = b.addExecutable("heap", "chapter_heap/heap.zig"); + exe_heap.addPackagePath("include", "include/include.zig"); + exe_heap.setTarget(target); + exe_heap.setBuildMode(mode); + exe_heap.install(); + const run_cmd_heap = exe_heap.run(); + run_cmd_heap.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd_heap.addArgs(args); + const run_step_heap = b.step("run_heap", "Run heap"); + run_step_heap.dependOn(&run_cmd_heap.step); + + // Source File: "chapter_heap/my_heap.zig" + // Run Command: zig build run_my_heap + const exe_my_heap = b.addExecutable("my_heap", "chapter_heap/my_heap.zig"); + exe_my_heap.addPackagePath("include", "include/include.zig"); + exe_my_heap.setTarget(target); + exe_my_heap.setBuildMode(mode); + exe_my_heap.install(); + const run_cmd_my_heap = exe_my_heap.run(); + run_cmd_my_heap.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd_my_heap.addArgs(args); + const run_step_my_heap = b.step("run_my_heap", "Run my_heap"); + run_step_my_heap.dependOn(&run_cmd_my_heap.step); + + // Section: "Linear Search" + // Source File: "chapter_searching/linear_search.zig" + // Run Command: zig build run_linear_search + const exe_linear_search = b.addExecutable("linear_search", "chapter_searching/linear_search.zig"); + exe_linear_search.addPackagePath("include", "include/include.zig"); + exe_linear_search.setTarget(target); + exe_linear_search.setBuildMode(mode); + exe_linear_search.install(); + const run_cmd_linear_search = exe_linear_search.run(); + run_cmd_linear_search.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd_linear_search.addArgs(args); + const run_step_linear_search= b.step("run_linear_search", "Run linear_search"); + run_step_linear_search.dependOn(&run_cmd_linear_search.step); + // Section: "Bubble Sort" // Source File: "chapter_sorting/bubble_sort.zig" // Run Command: zig build run_bubble_sort diff --git a/codes/zig/chapter_hashing/hash_map.zig b/codes/zig/chapter_hashing/hash_map.zig new file mode 100644 index 00000000..1e217c43 --- /dev/null +++ b/codes/zig/chapter_hashing/hash_map.zig @@ -0,0 +1,55 @@ +// File: hash_map.zig +// Created Time: 2023-01-13 +// Author: sjinzh (sjinzh@gmail.com) + +const std = @import("std"); +const inc = @import("include"); + +// Driver Code +pub fn main() !void { + // 初始化哈希表 + var map = std.AutoHashMap(i32, []const u8).init(std.heap.page_allocator); + // 延迟释放内存 + defer map.deinit(); + + // 添加操作 + // 在哈希表中添加键值对 (key, value) + try map.put(12836, "小哈"); + try map.put(15937, "小啰"); + try map.put(16750, "小算"); + try map.put(13276, "小法"); + try map.put(10583, "小鸭"); + std.debug.print("\n添加完成后,哈希表为\nKey -> Value\n", .{}); + inc.PrintUtil.printHashMap(i32, []const u8, map); + + // 查询操作 + // 向哈希表输入键 key ,得到值 value + var name = map.get(15937).?; + std.debug.print("\n输入学号 15937 ,查询到姓名 {s}\n", .{name}); + + // 删除操作 + // 在哈希表中删除键值对 (key, value) + _ = map.remove(10583); + std.debug.print("\n删除 10583 后,哈希表为\nKey -> Value\n", .{}); + inc.PrintUtil.printHashMap(i32, []const u8, map); + + // 遍历哈希表 + std.debug.print("\n遍历键值对 Key->Value\n", .{}); + inc.PrintUtil.printHashMap(i32, []const u8, map); + + std.debug.print("\n单独遍历键 Key\n", .{}); + var it = map.iterator(); + while (it.next()) |kv| { + std.debug.print("{}\n", .{kv.key_ptr.*}); + } + + std.debug.print("\n单独遍历值 value\n", .{}); + it = map.iterator(); + while (it.next()) |kv| { + std.debug.print("{s}\n", .{kv.value_ptr.*}); + } + + const getchar = try std.io.getStdIn().reader().readByte(); + _ = getchar; +} + diff --git a/codes/zig/chapter_heap/heap.zig b/codes/zig/chapter_heap/heap.zig new file mode 100644 index 00000000..e2f215d0 --- /dev/null +++ b/codes/zig/chapter_heap/heap.zig @@ -0,0 +1,81 @@ +// File: heap.zig +// Created Time: 2023-01-14 +// Author: sjinzh (sjinzh@gmail.com) + +const std = @import("std"); +const inc = @import("include"); + +fn lessThan(context: void, a: i32, b: i32) std.math.Order { + _ = context; + return std.math.order(a, b); +} + +fn greaterThan(context: void, a: i32, b: i32) std.math.Order { + return lessThan(context, a, b).invert(); +} + +fn testPush(comptime T: type, mem_allocator: std.mem.Allocator, heap: anytype, val: T) !void { + try heap.add(val); //元素入堆 + std.debug.print("\n元素 {} 入堆后\n", .{val}); + try inc.PrintUtil.printHeap(T, mem_allocator, heap); +} + +fn testPop(comptime T: type, mem_allocator: std.mem.Allocator, heap: anytype) !void { + var val = heap.remove(); //堆顶元素出堆 + std.debug.print("\n堆顶元素 {} 出堆后\n", .{val}); + try inc.PrintUtil.printHeap(T, mem_allocator, heap); +} + +// Driver Code +pub fn main() !void { + // 初始化内存分配器 + var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer mem_arena.deinit(); + const mem_allocator = mem_arena.allocator(); + + // 初始化堆 + // 初始化小顶堆 + const PQlt = std.PriorityQueue(i32, void, lessThan); + var minHeap = PQlt.init(std.heap.page_allocator, {}); + defer minHeap.deinit(); + // 初始化大顶堆 + const PQgt = std.PriorityQueue(i32, void, greaterThan); + var maxHeap = PQgt.init(std.heap.page_allocator, {}); + defer maxHeap.deinit(); + + std.debug.print("\n以下测试样例为大顶堆", .{}); + + // 元素入堆 + try testPush(i32, mem_allocator, &maxHeap, 1); + try testPush(i32, mem_allocator, &maxHeap, 3); + try testPush(i32, mem_allocator, &maxHeap, 2); + try testPush(i32, mem_allocator, &maxHeap, 5); + try testPush(i32, mem_allocator, &maxHeap, 4); + + // 获取堆顶元素 + var peek = maxHeap.peek().?; + std.debug.print("\n堆顶元素为 {}\n", .{peek}); + + // 堆顶元素出堆 + try testPop(i32, mem_allocator, &maxHeap); + try testPop(i32, mem_allocator, &maxHeap); + try testPop(i32, mem_allocator, &maxHeap); + try testPop(i32, mem_allocator, &maxHeap); + try testPop(i32, mem_allocator, &maxHeap); + + // 获取堆的大小 + var size = maxHeap.len; + std.debug.print("\n堆元素数量为 {}\n", .{size}); + + // 判断堆是否为空 + var isEmpty = if (maxHeap.len == 0) true else false; + std.debug.print("\n堆是否为空 {}\n", .{isEmpty}); + + // 输入列表并建堆 + try minHeap.addSlice(&[_]i32{ 1, 3, 2, 5, 4 }); + std.debug.print("\n输入列表并建立小顶堆后\n", .{}); + try inc.PrintUtil.printHeap(i32, mem_allocator, minHeap); + + const getchar = try std.io.getStdIn().reader().readByte(); + _ = getchar; +} \ No newline at end of file diff --git a/codes/zig/chapter_heap/my_heap.zig b/codes/zig/chapter_heap/my_heap.zig new file mode 100644 index 00000000..c74b1091 --- /dev/null +++ b/codes/zig/chapter_heap/my_heap.zig @@ -0,0 +1,190 @@ +// File: my_heap.zig +// Created Time: 2023-01-14 +// Author: sjinzh (sjinzh@gmail.com) + +const std = @import("std"); +const inc = @import("include"); + +// 堆类简易实现 +// 编译期泛型 +pub fn MaxHeap(comptime T: type) type { + return struct { + const Self = @This(); + + maxHeap: ?std.ArrayList(T) = null, // 使用列表而非数组,这样无需考虑扩容问题 + + // 构造函数,根据输入列表建堆 + pub fn init(self: *Self, allocator: std.mem.Allocator, nums: []const T) !void { + if (self.maxHeap != null) return; + self.maxHeap = std.ArrayList(T).init(allocator); + // 将列表元素原封不动添加进堆 + try self.maxHeap.?.appendSlice(nums); + // 堆化除叶结点以外的其他所有结点 + var i: usize = parent(self.size() - 1) + 1; + while (i > 0) : (i -= 1) { + try self.siftDown(i - 1); + } + } + + // 析构函数,释放内存 + pub fn deinit(self: *Self) void { + if (self.maxHeap != null) self.maxHeap.?.deinit(); + } + + // 获取左子结点索引 + fn left(i: usize) usize { + return 2 * i + 1; + } + + // 获取右子结点索引 + fn right(i: usize) usize { + return 2 * i + 2; + } + + // 获取父结点索引 + fn parent(i: usize) usize { + // return (i - 1) / 2; // 向下整除 + return @divFloor(i - 1, 2); + } + + // 交换元素 + fn swap(self: *Self, i: usize, j: usize) !void { + var a = self.maxHeap.?.items[i]; + var b = self.maxHeap.?.items[j]; + var tmp = a; + try self.maxHeap.?.replaceRange(i, 1, &[_]T{b}); + try self.maxHeap.?.replaceRange(j, 1, &[_]T{tmp}); + } + + // 获取堆大小 + pub fn size(self: *Self) usize { + return self.maxHeap.?.items.len; + } + + // 判断堆是否为空 + pub fn isEmpty(self: *Self) bool { + return self.size() == 0; + } + + // 访问堆顶元素 + pub fn peek(self: *Self) T { + return self.maxHeap.?.items[0]; + } + + // 元素入堆 + pub fn push(self: *Self, val: T) !void { + // 添加结点 + try self.maxHeap.?.append(val); + // 从底至顶堆化 + try self.siftUp(self.size() - 1); + } + + // 从结点 i 开始,从底至顶堆化 + fn siftUp(self: *Self, i_: usize) !void { + var i = i_; + while (true) { + // 获取结点 i 的父结点 + var p = parent(i); + // 当“越过根结点”或“结点无需修复”时,结束堆化 + if (p < 0 or self.maxHeap.?.items[i] <= self.maxHeap.?.items[p]) break; + // 交换两结点 + try self.swap(i, p); + // 循环向上堆化 + i = p; + } + } + + // 元素出堆 + pub fn poll(self: *Self) !T { + // 判断处理 + if (self.isEmpty()) unreachable; + // 交换根结点与最右叶结点(即交换首元素与尾元素) + try self.swap(0, self.size() - 1); + // 删除结点 + var val = self.maxHeap.?.pop(); + // 从顶至底堆化 + try self.siftDown(0); + // 返回堆顶元素 + return val; + } + + // 从结点 i 开始,从顶至底堆化 + fn siftDown(self: *Self, i_: usize) !void { + var i = i_; + while (true) { + // 判断结点 i, l, r 中值最大的结点,记为 ma + var l = left(i); + var r = right(i); + var ma = i; + if (l < self.size() and self.maxHeap.?.items[l] > self.maxHeap.?.items[ma]) ma = l; + if (r < self.size() and self.maxHeap.?.items[r] > self.maxHeap.?.items[ma]) ma = r; + // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if (ma == i) break; + // 交换两结点 + try self.swap(i, ma); + // 循环向下堆化 + i = ma; + } + } + + fn lessThan(context: void, a: T, b: T) std.math.Order { + _ = context; + return std.math.order(a, b); + } + + fn greaterThan(context: void, a: T, b: T) std.math.Order { + return lessThan(context, a, b).invert(); + } + + // 打印堆(二叉树) + pub fn print(self: *Self, mem_allocator: std.mem.Allocator) !void { + const PQgt = std.PriorityQueue(T, void, greaterThan); + var queue = PQgt.init(std.heap.page_allocator, {}); + defer queue.deinit(); + try queue.addSlice(self.maxHeap.?.items); + try inc.PrintUtil.printHeap(T, mem_allocator, queue); + } + }; +} + +// Driver Code +pub fn main() !void { + // 初始化内存分配器 + var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer mem_arena.deinit(); + const mem_allocator = mem_arena.allocator(); + + // 初始化大顶堆 + var maxHeap = MaxHeap(i32){}; + try maxHeap.init(std.heap.page_allocator, &[_]i32{ 9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2 }); + defer maxHeap.deinit(); + std.debug.print("\n输入列表并建堆后\n", .{}); + try maxHeap.print(mem_allocator); + + // 获取堆顶元素 + var peek = maxHeap.peek(); + std.debug.print("\n堆顶元素为 {}\n", .{peek}); + + // 元素入堆 + const val = 7; + try maxHeap.push(val); + std.debug.print("\n元素 {} 入堆后\n", .{val}); + try maxHeap.print(mem_allocator); + + // 堆顶元素出堆 + peek = try maxHeap.poll(); + std.debug.print("\n堆顶元素 {} 出堆后\n", .{peek}); + try maxHeap.print(mem_allocator); + + // 获取堆的大小 + var size = maxHeap.size(); + std.debug.print("\n堆元素数量为 {}", .{size}); + + // 判断堆是否为空 + var isEmpty = maxHeap.isEmpty(); + std.debug.print("\n堆是否为空 {}\n", .{isEmpty}); + + const getchar = try std.io.getStdIn().reader().readByte(); + _ = getchar; +} + diff --git a/codes/zig/chapter_searching/linear_search.zig b/codes/zig/chapter_searching/linear_search.zig new file mode 100644 index 00000000..3ba21313 --- /dev/null +++ b/codes/zig/chapter_searching/linear_search.zig @@ -0,0 +1,56 @@ +// File: linear_search.zig +// Created Time: 2023-01-13 +// Author: sjinzh (sjinzh@gmail.com) + +const std = @import("std"); +const inc = @import("include"); + +// 线性查找(数组) +fn linearSearchList(comptime T: type, nums: std.ArrayList(T), target: T) T { + // 遍历数组 + for (nums.items) |num, i| { + // 找到目标元素, 返回其索引 + if (num == target) { + return @intCast(T, i); + } + } + // 未找到目标元素,返回 -1 + return -1; +} + +// 线性查找(链表) +pub fn linearSearchLinkedList(comptime T: type, node: ?*inc.ListNode(T), target: T) ?*inc.ListNode(T) { + var head = node; + // 遍历链表 + while (head != null) { + // 找到目标结点,返回之 + if (head.?.val == target) return head; + head = head.?.next; + } + return null; +} + +// Driver Code +pub fn main() !void { + var target: i32 = 3; + + // 在数组中执行线性查找 + var nums = std.ArrayList(i32).init(std.heap.page_allocator); + defer nums.deinit(); + try nums.appendSlice(&[_]i32{ 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }); + var index = linearSearchList(i32, nums, target); + std.debug.print("目标元素 3 的索引 = {}\n", .{index}); + + // 在链表中执行线性查找 + var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer mem_arena.deinit(); + const mem_allocator = mem_arena.allocator(); + var head = try inc.ListUtil.listToLinkedList(i32, mem_allocator, nums); + var node = linearSearchLinkedList(i32, head, target); + std.debug.print("目标结点值 3 的对应结点对象为 ", .{}); + try inc.PrintUtil.printLinkedList(i32, node); + + const getchar = try std.io.getStdIn().reader().readByte(); + _ = getchar; +} + diff --git a/codes/zig/chapter_sorting/bubble_sort.zig b/codes/zig/chapter_sorting/bubble_sort.zig index 86319096..17cb0d97 100644 --- a/codes/zig/chapter_sorting/bubble_sort.zig +++ b/codes/zig/chapter_sorting/bubble_sort.zig @@ -1,4 +1,4 @@ -// File: time_complexity.zig +// File: bubble_sort.zig // Created Time: 2023-01-08 // Author: sjinzh (sjinzh@gmail.com) diff --git a/codes/zig/chapter_sorting/insertion_sort.zig b/codes/zig/chapter_sorting/insertion_sort.zig index 3c7594c2..5c954791 100644 --- a/codes/zig/chapter_sorting/insertion_sort.zig +++ b/codes/zig/chapter_sorting/insertion_sort.zig @@ -1,4 +1,4 @@ -// File: time_complexity.zig +// File: insertion_sort.zig // Created Time: 2023-01-08 // Author: sjinzh (sjinzh@gmail.com) diff --git a/codes/zig/chapter_stack_and_queue/array_stack.zig b/codes/zig/chapter_stack_and_queue/array_stack.zig index 868d9d94..36b1c7ca 100644 --- a/codes/zig/chapter_stack_and_queue/array_stack.zig +++ b/codes/zig/chapter_stack_and_queue/array_stack.zig @@ -1,4 +1,4 @@ -// File: stack.zig +// File: array_stack.zig // Created Time: 2023-01-08 // Author: sjinzh (sjinzh@gmail.com) diff --git a/codes/zig/chapter_tree/binary_tree.zig b/codes/zig/chapter_tree/binary_tree.zig new file mode 100644 index 00000000..b2cb9a96 --- /dev/null +++ b/codes/zig/chapter_tree/binary_tree.zig @@ -0,0 +1,40 @@ +// File: binary_tree.zig +// Created Time: 2023-01-14 +// Author: sjinzh (sjinzh@gmail.com) + +const std = @import("std"); +const inc = @import("include"); + +// Driver Code +pub fn main() !void { + // 初始化二叉树 + // 初始化结点 + var n1 = inc.TreeNode(i32){ .val = 1 }; + var n2 = inc.TreeNode(i32){ .val = 2 }; + var n3 = inc.TreeNode(i32){ .val = 3 }; + var n4 = inc.TreeNode(i32){ .val = 4 }; + var n5 = inc.TreeNode(i32){ .val = 5 }; + // 构建引用指向(即指针) + n1.left = &n2; + n1.right = &n3; + n2.left = &n4; + n2.right = &n5; + std.debug.print("初始化二叉树\n", .{}); + try inc.PrintUtil.printTree(&n1, null, false); + + // 插入与删除结点 + var p = inc.TreeNode(i32){ .val = 0 }; + // 在 n1 -> n2 中间插入结点 P + n1.left = &p; + p.left = &n2; + std.debug.print("插入结点 P 后\n", .{}); + try inc.PrintUtil.printTree(&n1, null, false); + // 删除结点 + n1.left = &n2; + std.debug.print("删除结点 P 后\n", .{}); + try inc.PrintUtil.printTree(&n1, null, false); + + const getchar = try std.io.getStdIn().reader().readByte(); + _ = getchar; +} + diff --git a/codes/zig/include/ListNode.zig b/codes/zig/include/ListNode.zig index ae0246c0..da7e667c 100644 --- a/codes/zig/include/ListNode.zig +++ b/codes/zig/include/ListNode.zig @@ -16,6 +16,21 @@ pub fn ListNode(comptime T: type) type { // Initialize a list node with specific value pub fn init(self: *Self, x: i32) void { self.val = x; + self.next = null; } }; +} + +// Generate a linked list with a list +pub fn listToLinkedList(comptime T: type, mem_allocator: std.mem.Allocator, list: std.ArrayList(T)) !?*ListNode(T) { + var dum = try mem_allocator.create(ListNode(T)); + dum.init(0); + var head = dum; + for (list.items) |val| { + var tmp = try mem_allocator.create(ListNode(T)); + tmp.init(val); + head.next = tmp; + head = head.next.?; + } + return dum.next; } \ No newline at end of file diff --git a/codes/zig/include/PrintUtil.zig b/codes/zig/include/PrintUtil.zig index 4d2d2089..d126acb3 100644 --- a/codes/zig/include/PrintUtil.zig +++ b/codes/zig/include/PrintUtil.zig @@ -3,8 +3,10 @@ // Author: sjinzh (sjinzh@gmail.com) const std = @import("std"); -const ListNode = @import("ListNode.zig").ListNode; -const TreeNode = @import("TreeNode.zig").TreeNode; +pub const ListUtil = @import("ListNode.zig"); +pub const ListNode = ListUtil.ListNode; +pub const TreeUtil = @import("TreeNode.zig"); +pub const TreeNode = TreeUtil.TreeNode; // Print an array pub fn printArray(comptime T: type, nums: []T) void { @@ -46,6 +48,27 @@ pub fn printLinkedList(comptime T: type, node: ?*ListNode(T)) !void { } } +// Print a HashMap +pub fn printHashMap(comptime TKey: type, comptime TValue: type, map: std.AutoHashMap(TKey, TValue)) void { + var it = map.iterator(); + while (it.next()) |kv| { + var key = kv.key_ptr.*; + var value = kv.value_ptr.*; + std.debug.print("{} -> {s}\n", .{key, value}); + } +} + +// print a heap (PriorityQueue) +pub fn printHeap(comptime T: type, mem_allocator: std.mem.Allocator, queue: anytype) !void { + var arr = queue.items; + var len = queue.len; + std.debug.print("堆的数组表示:", .{}); + printArray(T, arr[0..len]); + std.debug.print("\n堆的树状表示:\n", .{}); + var root = try TreeUtil.arrToTree(T, mem_allocator, arr[0..len]); + try printTree(root, null, false); +} + // This tree printer is borrowed from TECHIE DELIGHT // https://www.techiedelight.com/c-program-print-binary-tree/ const Trunk = struct { diff --git a/codes/zig/include/TreeNode.zig b/codes/zig/include/TreeNode.zig index 12af9e8f..0e4f5b15 100644 --- a/codes/zig/include/TreeNode.zig +++ b/codes/zig/include/TreeNode.zig @@ -17,6 +17,46 @@ pub fn TreeNode(comptime T: type) type { // Initialize a tree node with specific value pub fn init(self: *Self, x: i32) void { self.val = x; + self.left = null; + self.right = null; } }; +} + +// Generate a binary tree with an array +pub fn arrToTree(comptime T: type, mem_allocator: std.mem.Allocator, arr: []T) !?*TreeNode(T) { + if (arr.len == 0) return null; + var root = try mem_allocator.create(TreeNode(T)); + root.init(arr[0]); + const L = std.TailQueue(*TreeNode(T)); + var que = L{}; + var root_node = try mem_allocator.create(L.Node); + root_node.data = root; + que.append(root_node); + var index: usize = 0; + while (que.len > 0) { + var que_node = que.popFirst().?; + var node = que_node.data; + index += 1; + if (index >= arr.len) break; + if (index < arr.len) { + var tmp = try mem_allocator.create(TreeNode(T)); + tmp.init(arr[index]); + node.left = tmp; + var tmp_node = try mem_allocator.create(L.Node); + tmp_node.data = node.left.?; + que.append(tmp_node); + } + index += 1; + if (index >= arr.len) break; + if (index < arr.len) { + var tmp = try mem_allocator.create(TreeNode(T)); + tmp.init(arr[index]); + node.right = tmp; + var tmp_node = try mem_allocator.create(L.Node); + tmp_node.data = node.right.?; + que.append(tmp_node); + } + } + return root; } \ No newline at end of file diff --git a/codes/zig/include/include.zig b/codes/zig/include/include.zig index 20dfca90..42cd76cf 100644 --- a/codes/zig/include/include.zig +++ b/codes/zig/include/include.zig @@ -3,5 +3,7 @@ // Author: sjinzh (sjinzh@gmail.com) pub const PrintUtil = @import("PrintUtil.zig"); -pub const ListNode = @import("ListNode.zig").ListNode; -pub const TreeNode = @import("TreeNode.zig").TreeNode; \ No newline at end of file +pub const ListUtil = @import("ListNode.zig"); +pub const ListNode = ListUtil.ListNode; +pub const TreeUtil = @import("TreeNode.zig"); +pub const TreeNode = TreeUtil.TreeNode; \ No newline at end of file diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md index 2251362d..fcbdf9ab 100644 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -245,6 +245,8 @@ elementAddr = firtstElementAddr + elementLength * elementIndex for (int i = 0; i < size; i++) { res[i] = nums[i]; } + // 释放内存 + delete[] nums; // 返回扩展后的新数组 return res; } diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index 1a47a0d1..e57d4987 100644 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -748,6 +748,11 @@ comments: true nums = new int[numsCapacity]; } + /* 析构函数 */ + ~MyList() { + delete[] nums; + } + /* 获取列表长度(即当前元素数量)*/ int size() { return numsSize; @@ -818,14 +823,14 @@ comments: true void extendCapacity() { // 新建一个长度为 size * extendRatio 的数组,并将原数组拷贝到新数组 int newCapacity = capacity() * extendRatio; - int* extend = new int[newCapacity]; + int* tmp = nums; + nums = new int[newCapacity]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size(); i++) { - extend[i] = nums[i]; + nums[i] = tmp[i]; } - int* temp = nums; - nums = extend; - delete[] temp; + // 释放内存 + delete[] tmp; numsCapacity = newCapacity; } }; diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index e594bec8..96873fc1 100644 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -507,7 +507,7 @@ $$ const int a = 0; int b = 0; vector nums(10000); - ListNode* node = new ListNode(0); + ListNode node(0); // 循环中的变量占用 O(1) 空间 for (int i = 0; i < n; i++) { int c = 0; @@ -654,9 +654,9 @@ $$ // 长度为 n 的数组占用 O(n) 空间 vector nums(n); // 长度为 n 的列表占用 O(n) 空间 - vector nodes; + vector nodes; for (int i = 0; i < n; i++) { - nodes.push_back(new ListNode(i)); + nodes.push_back(ListNode(i)); } // 长度为 n 的哈希表占用 O(n) 空间 unordered_map map; diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 15d22e78..21f7f533 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -606,6 +606,7 @@ comments: true // 判空处理 if h.isEmpty() { fmt.Println("error") + return nil } // 交换根结点与最右叶结点(即交换首元素与尾元素) h.swap(0, h.size()-1) @@ -709,10 +710,10 @@ comments: true ```go title="my_heap.go" /* 构造函数,根据切片建堆 */ func newMaxHeap(nums []any) *maxHeap { - // 所有元素入堆 + // 将列表元素原封不动添加进堆 h := &maxHeap{data: nums} + // 堆化除叶结点以外的其他所有结点 for i := len(h.data) - 1; i >= 0; i-- { - // 堆化除叶结点以外的其他所有结点 h.siftDown(i) } return h diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index 3bb0bc99..07984764 100644 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -228,7 +228,7 @@ comments: true **稳定排序**:不交换相等元素。 -**自适排序**:引入 `flag` 优化后(见下文),最佳时间复杂度为 $O(N)$ 。 +**自适应排序**:引入 `flag` 优化后(见下文),最佳时间复杂度为 $O(N)$ 。 ## 效率优化 diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md index a712a1bf..2c000e19 100644 --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -16,20 +16,28 @@ comments: true === "Step 1" ![pivot_division_step1](quick_sort.assets/pivot_division_step1.png) + === "Step 2" ![pivot_division_step2](quick_sort.assets/pivot_division_step2.png) + === "Step 3" ![pivot_division_step3](quick_sort.assets/pivot_division_step3.png) + === "Step 4" ![pivot_division_step4](quick_sort.assets/pivot_division_step4.png) + === "Step 5" ![pivot_division_step5](quick_sort.assets/pivot_division_step5.png) + === "Step 6" ![pivot_division_step6](quick_sort.assets/pivot_division_step6.png) + === "Step 7" ![pivot_division_step7](quick_sort.assets/pivot_division_step7.png) + === "Step 8" ![pivot_division_step8](quick_sort.assets/pivot_division_step8.png) + === "Step 9" ![pivot_division_step9](quick_sort.assets/pivot_division_step9.png) @@ -134,27 +142,27 @@ comments: true ``` js title="quick_sort.js" /* 元素交换 */ function swap(nums, i, j) { - let tmp = nums[i] - nums[i] = nums[j] - nums[j] = tmp + let tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; } /* 哨兵划分 */ - function partition(nums, left, right){ + function partition(nums, left, right) { // 以 nums[left] 作为基准数 - let i = left, j = right - while(i < j){ - while(i < j && nums[j] >= nums[left]){ - j -= 1 // 从右向左找首个小于基准数的元素 + let i = left, j = right; + while (i < j) { + while (i < j && nums[j] >= nums[left]) { + j -= 1; // 从右向左找首个小于基准数的元素 } - while(i < j && nums[i] <= nums[left]){ - i += 1 // 从左向右找首个大于基准数的元素 + while (i < j && nums[i] <= nums[left]) { + i += 1; // 从左向右找首个大于基准数的元素 } // 元素交换 - swap(nums, i, j) // 交换这两个元素 + swap(nums, i, j); // 交换这两个元素 } - swap(nums, i, left) // 将基准数交换至两子数组的分界线 - return i // 返回基准数的索引 + swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 } ``` @@ -220,7 +228,6 @@ comments: true swap(nums, i, left); // 将基准数交换至两子数组的分界线 return i; // 返回基准数的索引 } - ``` === "Swift" @@ -313,14 +320,14 @@ comments: true ```js title="quick_sort.js" /* 快速排序 */ - function quickSort(nums, left, right){ + function quickSort(nums, left, right) { // 子数组长度为 1 时终止递归 - if(left >= right) return + if (left >= right) return; // 哨兵划分 - const pivot = partition(nums, left, right) + const pivot = partition(nums, left, right); // 递归左子数组、右子数组 - quick_sort(nums, left, pivot - 1) - quick_sort(nums, pivot + 1, right) + quickSort(nums, left, pivot - 1); + quickSort(nums, pivot + 1, right); } ``` @@ -408,7 +415,7 @@ comments: true int medianThree(int[] nums, int left, int mid, int right) { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; @@ -434,7 +441,7 @@ comments: true int medianThree(vector& nums, int left, int mid, int right) { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; @@ -460,7 +467,7 @@ comments: true def median_three(self, nums, left, mid, right): # 使用了异或操作来简化代码 # 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if (nums[left] > nums[mid]) ^ (nums[left] > nums[right]): + if (nums[left] < nums[mid]) ^ (nums[left] < nums[right]): return left elif (nums[mid] < nums[left]) ^ (nums[mid] > nums[right]): return mid @@ -481,9 +488,9 @@ comments: true ```go title="quick_sort.go" /* 选取三个元素的中位数 */ func medianThree(nums []int, left, mid, right int) int { - if (nums[left] > nums[mid]) != (nums[left] > nums[right]) { + if (nums[left] < nums[mid]) != (nums[left] < nums[right]) { return left - } else if (nums[mid] < nums[left]) != (nums[mid] > nums[right]) { + } else if (nums[mid] > nums[left]) != (nums[mid] > nums[right]) { return mid } return right @@ -507,7 +514,7 @@ comments: true function medianThree(nums, left, mid, right) { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; @@ -533,7 +540,7 @@ comments: true function medianThree(nums: number[], left: number, mid: number, right: number): number { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if (Number(nums[left] > nums[mid]) ^ Number(nums[left] > nums[right])) { + if (Number(nums[left] < nums[mid]) ^ Number(nums[left] < nums[right])) { return left; } else if (Number(nums[mid] < nums[left]) ^ Number(nums[mid] < nums[right])) { return mid; @@ -566,7 +573,7 @@ comments: true { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] > nums[mid]) ^ (nums[left] > nums[right])) + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; diff --git a/docs/chapter_stack_and_queue/deque.md b/docs/chapter_stack_and_queue/deque.md index 4671d5c9..b8d4df9a 100644 --- a/docs/chapter_stack_and_queue/deque.md +++ b/docs/chapter_stack_and_queue/deque.md @@ -196,5 +196,29 @@ comments: true === "Swift" ```swift title="deque.swift" - + /* 初始化双向队列 */ + // Swift 没有内置的双向队列类,可以把 Array 当作双向队列来使用 + var deque: [Int] = [] + + /* 元素入队 */ + deque.append(2) // 添加至队尾 + deque.append(5) + deque.append(4) + deque.insert(3, at: 0) // 添加至队首 + deque.insert(1, at: 0) + + /* 访问元素 */ + let peekFirst = deque.first! // 队首元素 + let peekLast = deque.last! // 队尾元素 + + /* 元素出队 */ + // 使用 Array 模拟时 pollFirst 的复杂度为 O(n) + let pollFirst = deque.removeFirst() // 队首元素出队 + let pollLast = deque.removeLast() // 队尾元素出队 + + /* 获取双向队列的长度 */ + let size = deque.count + + /* 判断双向队列是否为空 */ + let isEmpty = deque.isEmpty ``` diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index d70b3e52..35d6c41f 100644 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -246,6 +246,7 @@ comments: true let peek = queue.first! /* 元素出队 */ + // 使用 Array 模拟时 poll 的复杂度为 O(n) let pool = queue.removeFirst() /* 获取队列的长度 */ @@ -330,6 +331,10 @@ comments: true rear = nullptr; queSize = 0; } + ~LinkedListQueue() { + delete front; + delete rear; + } /* 获取队列的长度 */ int size() { return queSize; @@ -784,6 +789,9 @@ comments: true cap = capacity; nums = new int[capacity]; } + ~ArrayQueue() { + delete[] nums; + } /* 获取队列的容量 */ int capacity() { return cap; diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index c47f7cc8..66b46187 100644 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -324,6 +324,9 @@ comments: true stackTop = nullptr; stkSize = 0; } + ~LinkedListStack() { + freeMemoryLinkedList(stackTop); + } /* 获取栈的长度 */ int size() { return stkSize; diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png b/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png index fcacaa02..f7ec9983 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png and b/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png differ diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index a0322154..393221b7 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -22,19 +22,15 @@ comments: true - 若 `cur.val = num` ,说明找到目标结点,跳出循环并返回该结点即可; === "Step 1" - ![bst_search_1](binary_search_tree.assets/bst_search_1.png) === "Step 2" - ![bst_search_2](binary_search_tree.assets/bst_search_2.png) === "Step 3" - ![bst_search_3](binary_search_tree.assets/bst_search_3.png) === "Step 4" - ![bst_search_4](binary_search_tree.assets/bst_search_4.png) 二叉搜索树的查找操作和二分查找算法如出一辙,也是在每轮排除一半情况。循环次数最多为二叉树的高度,当二叉树平衡时,使用 $O(\log n)$ 时间。 @@ -483,9 +479,9 @@ comments: true // 找到待删除结点,跳出循环 if (cur.val == num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur.val < num) cur = cur.right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur.left; } // 若无待删除结点,则直接返回 @@ -527,9 +523,9 @@ comments: true // 找到待删除结点,跳出循环 if (cur->val == num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur->val < num) cur = cur->right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur->left; } // 若无待删除结点,则直接返回 @@ -575,9 +571,9 @@ comments: true if cur.val == num: break pre = cur - if cur.val < num: # 待删除结点在 root 的右子树中 + if cur.val < num: # 待删除结点在 cur 的右子树中 cur = cur.right - else: # 待删除结点在 root 的左子树中 + else: # 待删除结点在 cur 的左子树中 cur = cur.left # 若无待删除结点,则直接返回 @@ -677,9 +673,9 @@ comments: true // 找到待删除结点,跳出循环 if (cur.val === num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur.val < num) cur = cur.right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur.left; } // 若无待删除结点,则直接返回 @@ -725,9 +721,9 @@ comments: true } pre = cur; if (cur.val < num) { - cur = cur.right as TreeNode; // 待删除结点在 root 的右子树中 + cur = cur.right as TreeNode; // 待删除结点在 cur 的右子树中 } else { - cur = cur.left as TreeNode; // 待删除结点在 root 的左子树中 + cur = cur.left as TreeNode; // 待删除结点在 cur 的左子树中 } } // 若无待删除结点,则直接返回 @@ -780,9 +776,9 @@ comments: true // 找到待删除结点,跳出循环 if (cur.val == num) break; pre = cur; - // 待删除结点在 root 的右子树中 + // 待删除结点在 cur 的右子树中 if (cur.val < num) cur = cur.right; - // 待删除结点在 root 的左子树中 + // 待删除结点在 cur 的左子树中 else cur = cur.left; } // 若无待删除结点,则直接返回 diff --git a/docs/index.assets/animation.gif b/docs/index.assets/animation.gif index 6522ef9f..60f53f20 100644 Binary files a/docs/index.assets/animation.gif and b/docs/index.assets/animation.gif differ diff --git a/docs/index.assets/comment.gif b/docs/index.assets/comment.gif index d64787ac..e7a74cf9 100644 Binary files a/docs/index.assets/comment.gif and b/docs/index.assets/comment.gif differ diff --git a/docs/index.assets/conceptual_rendering.png b/docs/index.assets/conceptual_rendering.png index 591d633b..87c5181a 100644 Binary files a/docs/index.assets/conceptual_rendering.png and b/docs/index.assets/conceptual_rendering.png differ diff --git a/docs/index.assets/demo.png b/docs/index.assets/demo.png deleted file mode 100644 index af3e0059..00000000 Binary files a/docs/index.assets/demo.png and /dev/null differ diff --git a/docs/index.assets/learning_route.png b/docs/index.assets/learning_route.png deleted file mode 100644 index 7423808d..00000000 Binary files a/docs/index.assets/learning_route.png and /dev/null differ diff --git a/docs/index.assets/running_code.gif b/docs/index.assets/running_code.gif index 7377773c..dfe17531 100644 Binary files a/docs/index.assets/running_code.gif and b/docs/index.assets/running_code.gif differ