From b3c757c9f4824da543d869e7594a6457dccf4da6 Mon Sep 17 00:00:00 2001 From: krahets Date: Mon, 22 Apr 2024 02:35:43 +0800 Subject: [PATCH] build --- .../replace_linear_by_hashing.md | 2 +- docs/chapter_stack_and_queue/stack.md | 2 +- en/docs/chapter_stack_and_queue/stack.md | 2 +- .../divide_and_conquer.md | 2 +- zh-Hant/docs/chapter_heap/heap.md | 2 +- .../replace_linear_by_hashing.md | 2 +- zh-Hant/docs/chapter_sorting/counting_sort.md | 2 +- zh-Hant/docs/chapter_sorting/radix_sort.md | 2 +- zh-Hant/docs/chapter_stack_and_queue/stack.md | 2 +- .../array_representation_of_tree.md | 86 +++++++++- zh-Hant/docs/chapter_tree/avl_tree.md | 160 ++++++++++++++++-- .../docs/chapter_tree/binary_search_tree.md | 106 +++++++++++- zh-Hant/docs/chapter_tree/binary_tree.md | 32 +++- .../chapter_tree/binary_tree_traversal.md | 49 +++++- 14 files changed, 413 insertions(+), 38 deletions(-) diff --git a/docs/chapter_searching/replace_linear_by_hashing.md b/docs/chapter_searching/replace_linear_by_hashing.md index 3db51f347..0626c6b63 100755 --- a/docs/chapter_searching/replace_linear_by_hashing.md +++ b/docs/chapter_searching/replace_linear_by_hashing.md @@ -92,7 +92,7 @@ comments: true size := len(nums) // 两层循环,时间复杂度为 O(n^2) for i := 0; i < size-1; i++ { - for j := i + 1; i < size; j++ { + for j := i + 1; j < size; j++ { if nums[i]+nums[j] == target { return []int{i, j} } diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index fe0d8e3af..bd4af8118 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -1284,7 +1284,7 @@ comments: true def is_empty(self) -> bool: """判断栈是否为空""" - return self._size == 0 + return self.size() == 0 def push(self, item: int): """入栈""" diff --git a/en/docs/chapter_stack_and_queue/stack.md b/en/docs/chapter_stack_and_queue/stack.md index 32165bf45..74df1ae3a 100755 --- a/en/docs/chapter_stack_and_queue/stack.md +++ b/en/docs/chapter_stack_and_queue/stack.md @@ -1237,7 +1237,7 @@ Since the elements to be pushed onto the stack may continuously increase, we can def is_empty(self) -> bool: """判断栈是否为空""" - return self._size == 0 + return self.size() == 0 def push(self, item: int): """入栈""" diff --git a/zh-Hant/docs/chapter_divide_and_conquer/divide_and_conquer.md b/zh-Hant/docs/chapter_divide_and_conquer/divide_and_conquer.md index b19026737..8cd82a90e 100644 --- a/zh-Hant/docs/chapter_divide_and_conquer/divide_and_conquer.md +++ b/zh-Hant/docs/chapter_divide_and_conquer/divide_and_conquer.md @@ -72,7 +72,7 @@ $$ 並行最佳化在多核或多處理器的環境中尤其有效,因為系統可以同時處理多個子問題,更加充分地利用計算資源,從而顯著減少總體的執行時間。 -比如在圖 12-3 所示的“桶排序”中,我們將海量的資料平均分配到各個桶中,則可所有桶的排序任務分散到各個計算單元,完成後再合併結果。 +比如在圖 12-3 所示的“桶排序”中,我們將海量的資料平均分配到各個桶中,則可將所有桶的排序任務分散到各個計算單元,完成後再合併結果。 ![桶排序的平行計算](divide_and_conquer.assets/divide_and_conquer_parallel_computing.png){ class="animation-figure" } diff --git a/zh-Hant/docs/chapter_heap/heap.md b/zh-Hant/docs/chapter_heap/heap.md index e932e2388..04beeabbd 100644 --- a/zh-Hant/docs/chapter_heap/heap.md +++ b/zh-Hant/docs/chapter_heap/heap.md @@ -431,7 +431,7 @@ comments: true ## 8.1.2   堆積的實現 -下文實現的是大頂堆積。若要將其轉換為小頂堆積,只需將所有大小邏輯判斷取逆(例如,將 $\geq$ 替換為 $\leq$ )。感興趣的讀者可以自行實現。 +下文實現的是大頂堆積。若要將其轉換為小頂堆積,只需將所有大小邏輯判斷進行逆轉(例如,將 $\geq$ 替換為 $\leq$ )。感興趣的讀者可以自行實現。 ### 1.   堆積的儲存與表示 diff --git a/zh-Hant/docs/chapter_searching/replace_linear_by_hashing.md b/zh-Hant/docs/chapter_searching/replace_linear_by_hashing.md index 051e3e4b7..782563569 100755 --- a/zh-Hant/docs/chapter_searching/replace_linear_by_hashing.md +++ b/zh-Hant/docs/chapter_searching/replace_linear_by_hashing.md @@ -92,7 +92,7 @@ comments: true size := len(nums) // 兩層迴圈,時間複雜度為 O(n^2) for i := 0; i < size-1; i++ { - for j := i + 1; i < size; j++ { + for j := i + 1; j < size; j++ { if nums[i]+nums[j] == target { return []int{i, j} } diff --git a/zh-Hant/docs/chapter_sorting/counting_sort.md b/zh-Hant/docs/chapter_sorting/counting_sort.md index 177a3f637..f70d1e0d0 100644 --- a/zh-Hant/docs/chapter_sorting/counting_sort.md +++ b/zh-Hant/docs/chapter_sorting/counting_sort.md @@ -870,7 +870,7 @@ $$ ## 11.9.3   演算法特性 -- **時間複雜度為 $O(n + m)$** :涉及走訪 `nums` 和走訪 `counter` ,都使用線性時間。一般情況下 $n \gg m$ ,時間複雜度趨於 $O(n)$ 。 +- **時間複雜度為 $O(n + m)$、非自適應排序** :涉及走訪 `nums` 和走訪 `counter` ,都使用線性時間。一般情況下 $n \gg m$ ,時間複雜度趨於 $O(n)$ 。 - **空間複雜度為 $O(n + m)$、非原地排序**:藉助了長度分別為 $n$ 和 $m$ 的陣列 `res` 和 `counter` 。 - **穩定排序**:由於向 `res` 中填充元素的順序是“從右向左”的,因此倒序走訪 `nums` 可以避免改變相等元素之間的相對位置,從而實現穩定排序。實際上,正序走訪 `nums` 也可以得到正確的排序結果,但結果是非穩定的。 diff --git a/zh-Hant/docs/chapter_sorting/radix_sort.md b/zh-Hant/docs/chapter_sorting/radix_sort.md index 2f9a424e9..8ed828e50 100644 --- a/zh-Hant/docs/chapter_sorting/radix_sort.md +++ b/zh-Hant/docs/chapter_sorting/radix_sort.md @@ -761,6 +761,6 @@ $$ 相較於計數排序,基數排序適用於數值範圍較大的情況,**但前提是資料必須可以表示為固定位數的格式,且位數不能過大**。例如,浮點數不適合使用基數排序,因為其位數 $k$ 過大,可能導致時間複雜度 $O(nk) \gg O(n^2)$ 。 -- **時間複雜度為 $O(nk)$**:設資料量為 $n$、資料為 $d$ 進位制、最大位數為 $k$ ,則對某一位執行計數排序使用 $O(n + d)$ 時間,排序所有 $k$ 位使用 $O((n + d)k)$ 時間。通常情況下,$d$ 和 $k$ 都相對較小,時間複雜度趨向 $O(n)$ 。 +- **時間複雜度為 $O(nk)$、非自適應排序**:設資料量為 $n$、資料為 $d$ 進位制、最大位數為 $k$ ,則對某一位執行計數排序使用 $O(n + d)$ 時間,排序所有 $k$ 位使用 $O((n + d)k)$ 時間。通常情況下,$d$ 和 $k$ 都相對較小,時間複雜度趨向 $O(n)$ 。 - **空間複雜度為 $O(n + d)$、非原地排序**:與計數排序相同,基數排序需要藉助長度為 $n$ 和 $d$ 的陣列 `res` 和 `counter` 。 - **穩定排序**:當計數排序穩定時,基數排序也穩定;當計數排序不穩定時,基數排序無法保證得到正確的排序結果。 diff --git a/zh-Hant/docs/chapter_stack_and_queue/stack.md b/zh-Hant/docs/chapter_stack_and_queue/stack.md index 13b469ed9..6915f23f3 100755 --- a/zh-Hant/docs/chapter_stack_and_queue/stack.md +++ b/zh-Hant/docs/chapter_stack_and_queue/stack.md @@ -1284,7 +1284,7 @@ comments: true def is_empty(self) -> bool: """判斷堆疊是否為空""" - return self._size == 0 + return self.size() == 0 def push(self, item: int): """入堆疊""" diff --git a/zh-Hant/docs/chapter_tree/array_representation_of_tree.md b/zh-Hant/docs/chapter_tree/array_representation_of_tree.md index ca0645fb7..bd73b4be2 100644 --- a/zh-Hant/docs/chapter_tree/array_representation_of_tree.md +++ b/zh-Hant/docs/chapter_tree/array_representation_of_tree.md @@ -131,7 +131,9 @@ comments: true === "Ruby" ```ruby title="" - + ### 二元樹的陣列表示 ### + # 使用 nil 來表示空位 + tree = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] ``` === "Zig" @@ -1256,7 +1258,87 @@ comments: true === "Ruby" ```ruby title="array_binary_tree.rb" - [class]{ArrayBinaryTree}-[func]{} + ### 陣列表示下的二元樹類別 ### + class ArrayBinaryTree + ### 建構子 ### + def initialize(arr) + @tree = arr.to_a + end + + ### 串列容量 ### + def size + @tree.length + end + + ### 獲取索引為 i 節點的值 ### + def val(i) + # 若索引越界,則返回 nil ,代表空位 + return if i < 0 || i >= size + + @tree[i] + end + + ### 獲取索引為 i 節點的左子節點的索引 ### + def left(i) + 2 * i + 1 + end + + ### 獲取索引為 i 節點的右子節點的索引 ### + def right(i) + 2 * i + 2 + end + + ### 獲取索引為 i 節點的父節點的索引 ### + def parent(i) + (i - 1) / 2 + end + + ### 層序走訪 ### + def level_order + @res = [] + + # 直接走訪陣列 + for i in 0...size + @res << val(i) unless val(i).nil? + end + + @res + end + + ### 深度優先走訪 ### + def dfs(i, order) + return if val(i).nil? + # 前序走訪 + @res << val(i) if order == :pre + dfs(left(i), order) + # 中序走訪 + @res << val(i) if order == :in + dfs(right(i), order) + # 後序走訪 + @res << val(i) if order == :post + end + + ### 前序走訪 ### + def pre_order + @res = [] + dfs(0, :pre) + @res + end + + ### 中序走訪 ### + def in_order + @res = [] + dfs(0, :in) + @res + end + + ### 後序走訪 ### + def post_order + @res = [] + dfs(0, :post) + @res + end + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_tree/avl_tree.md b/zh-Hant/docs/chapter_tree/avl_tree.md index 707f45d56..d9ecc85c0 100644 --- a/zh-Hant/docs/chapter_tree/avl_tree.md +++ b/zh-Hant/docs/chapter_tree/avl_tree.md @@ -137,9 +137,9 @@ AVL 樹既是二元搜尋樹,也是平衡二元樹,同時滿足這兩類二 right: TreeNode | null; // 右子節點指標 constructor(val?: number, height?: number, left?: TreeNode | null, right?: TreeNode | null) { this.val = val === undefined ? 0 : val; - this.height = height === undefined ? 0 : height; - this.left = left === undefined ? null : left; - this.right = right === undefined ? null : right; + this.height = height === undefined ? 0 : height; + this.left = left === undefined ? null : left; + this.right = right === undefined ? null : right; } } ``` @@ -222,7 +222,18 @@ AVL 樹既是二元搜尋樹,也是平衡二元樹,同時滿足這兩類二 === "Ruby" ```ruby title="" + ### AVL 樹節點類別 ### + class TreeNode + attr_accessor :val # 節點值 + attr_accessor :height # 節點高度 + attr_accessor :left # 左子節點引用 + attr_accessor :right # 右子節點引用 + def initialize(val) + @val = val + @height = 0 + end + end ``` === "Zig" @@ -455,9 +466,19 @@ AVL 樹既是二元搜尋樹,也是平衡二元樹,同時滿足這兩類二 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{height} + ### 獲取節點高度 ### + def height(node) + # 空節點高度為 -1 ,葉節點高度為 0 + return node.height unless node.nil? + + -1 + end - [class]{AVLTree}-[func]{update_height} + ### 更新節點高度 ### + def update_height(node) + # 節點高度等於最高子樹高度 + 1 + node.height = [height(node.left), height(node.right)].max + 1 + end ``` === "Zig" @@ -638,7 +659,14 @@ AVL 樹既是二元搜尋樹,也是平衡二元樹,同時滿足這兩類二 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{balance_factor} + ### 獲取平衡因子 ### + def balance_factor(node) + # 空節點平衡因子為 0 + return 0 if node.nil? + + # 節點平衡因子 = 左子樹高度 - 右子樹高度 + height(node.left) - height(node.right) + end ``` === "Zig" @@ -913,7 +941,19 @@ AVL 樹的特點在於“旋轉”操作,它能夠在不影響二元樹的中 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{right_rotate} + ### 右旋操作 ### + def right_rotate(node) + child = node.left + grand_child = child.right + # 以 child 為原點,將 node 向右旋轉 + child.right = node + node.left = grand_child + # 更新節點高度 + update_height(node) + update_height(child) + # 返回旋轉後子樹的根節點 + child + end ``` === "Zig" @@ -1174,7 +1214,19 @@ AVL 樹的特點在於“旋轉”操作,它能夠在不影響二元樹的中 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{left_rotate} + ### 左旋操作 ### + def left_rotate(node) + child = node.right + grand_child = child.left + # 以 child 為原點,將 node 向左旋轉 + child.left = node + node.right = grand_child + # 更新節點高度 + update_height(node) + update_height(child) + # 返回旋轉後子樹的根節點 + child + end ``` === "Zig" @@ -1648,7 +1700,34 @@ AVL 樹的特點在於“旋轉”操作,它能夠在不影響二元樹的中 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{rotate} + ### 執行旋轉操作,使該子樹重新恢復平衡 ### + def rotate(node) + # 獲取節點 node 的平衡因子 + balance_factor = balance_factor(node) + # 左遍樹 + if balance_factor > 1 + if balance_factor(node.left) >= 0 + # 右旋 + return right_rotate(node) + else + # 先左旋後右旋 + node.left = left_rotate(node.left) + return right_rotate(node) + end + # 右遍樹 + elsif balance_factor < -1 + if balance_factor(node.right) <= 0 + # 左旋 + return left_rotate(node) + else + # 先右旋後左旋 + node.right = right_rotate(node.right) + return left_rotate(node) + end + end + # 平衡樹,無須旋轉,直接返回 + node + end ``` === "Zig" @@ -2039,9 +2118,28 @@ AVL 樹的節點插入操作與二元搜尋樹在主體上類似。唯一的區 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{insert} - - [class]{AVLTree}-[func]{insert_helper} + ### 插入節點 ### + def insert(val) + @root = insert_helper(@root, val) + end + + ### 遞迴插入節點(輔助方法)### + def insert_helper(node, val) + return TreeNode.new(val) if node.nil? + # 1. 查詢插入位置並插入節點 + if val < node.val + node.left = insert_helper(node.left, val) + elsif val > node.val + node.right = insert_helper(node.right, val) + else + # 重複節點不插入,直接返回 + return node + end + # 更新節點高度 + update_height(node) + # 2. 執行旋轉操作,使該子樹重新恢復平衡 + rotate(node) + end ``` === "Zig" @@ -2640,9 +2738,41 @@ AVL 樹的節點插入操作與二元搜尋樹在主體上類似。唯一的區 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{remove} - - [class]{AVLTree}-[func]{remove_helper} + ### 刪除節點 ### + def remove(val) + @root = remove_helper(@root, val) + end + + ### 遞迴刪除節點(輔助方法)### + def remove_helper(node, val) + return if node.nil? + # 1. 查詢節點並刪除 + if val < node.val + node.left = remove_helper(node.left, val) + elsif val > node.val + node.right = remove_helper(node.right, val) + else + if node.left.nil? || node.right.nil? + child = node.left || node.right + # 子節點數量 = 0 ,直接刪除 node 並返回 + return if child.nil? + # 子節點數量 = 1 ,直接刪除 node + node = child + else + # 子節點數量 = 2 ,則將中序走訪的下個節點刪除,並用該節點替換當前節點 + temp = node.right + while !temp.left.nil? + temp = temp.left + end + node.right = remove_helper(node.right, temp.val) + node.val = temp.val + end + end + # 更新節點高度 + update_height(node) + # 2. 執行旋轉操作,使該子樹重新恢復平衡 + rotate(node) + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_tree/binary_search_tree.md b/zh-Hant/docs/chapter_tree/binary_search_tree.md index 2ca6c70cf..17f7963be 100755 --- a/zh-Hant/docs/chapter_tree/binary_search_tree.md +++ b/zh-Hant/docs/chapter_tree/binary_search_tree.md @@ -316,7 +316,26 @@ comments: true === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{search} + ### 查詢節點 ### + def search(num) + cur = @root + + # 迴圈查詢,越過葉節點後跳出 + while !cur.nil? + # 目標節點在 cur 的右子樹中 + if cur.val < num + cur = cur.right + # 目標節點在 cur 的左子樹中 + elsif cur.val > num + cur = cur.left + # 找到目標節點,跳出迴圈 + else + break + end + end + + cur + end ``` === "Zig" @@ -773,7 +792,38 @@ comments: true === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{insert} + ### 插入節點 ### + def insert(num) + # 若樹為空,則初始化根節點 + if @root.nil? + @root = TreeNode.new(num) + return + end + + # 迴圈查詢,越過葉節點後跳出 + cur, pre = @root, nil + while !cur.nil? + # 找到重複節點,直接返回 + return if cur.val == num + + pre = cur + # 插入位置在 cur 的右子樹中 + if cur.val < num + cur = cur.right + # 插入位置在 cur 的左子樹中 + else + cur = cur.left + end + end + + # 插入節點 + node = TreeNode.new(num) + if pre.val < num + pre.right = node + else + pre.left = node + end + end ``` === "Zig" @@ -1545,7 +1595,57 @@ comments: true === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{remove} + ### 刪除節點 ### + def remove(num) + # 若樹為空,直接提前返回 + return if @root.nil? + + # 迴圈查詢,越過葉節點後跳出 + cur, pre = @root, nil + while !cur.nil? + # 找到待刪除節點,跳出迴圈 + break if cur.val == num + + pre = cur + # 待刪除節點在 cur 的右子樹中 + if cur.val < num + cur = cur.right + # 待刪除節點在 cur 的左子樹中 + else + cur = cur.left + end + end + # 若無待刪除節點,則直接返回 + return if cur.nil? + + # 子節點數量 = 0 or 1 + if cur.left.nil? || cur.right.nil? + # 當子節點數量 = 0 / 1 時, child = null / 該子節點 + child = cur.left || cur.right + # 刪除節點 cur + if cur != @root + if pre.left == cur + pre.left = child + else + pre.right = child + end + else + # 若刪除節點為根節點,則重新指定根節點 + @root = child + end + # 子節點數量 = 2 + else + # 獲取中序走訪中 cur 的下一個節點 + tmp = cur.right + while !tmp.left.nil? + tmp = tmp.left + end + # 遞迴刪除節點 tmp + remove(tmp.val) + # 用 tmp 覆蓋 cur + cur.val = tmp.val + end + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_tree/binary_tree.md b/zh-Hant/docs/chapter_tree/binary_tree.md index f7441717a..4f0733255 100644 --- a/zh-Hant/docs/chapter_tree/binary_tree.md +++ b/zh-Hant/docs/chapter_tree/binary_tree.md @@ -110,7 +110,7 @@ comments: true val: number; left: TreeNode | null; right: TreeNode | null; - + constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { this.val = val === undefined ? 0 : val; // 節點值 this.left = left === undefined ? null : left; // 左子節點引用 @@ -193,7 +193,16 @@ comments: true === "Ruby" ```ruby title="" + ### 二元樹節點類別 ### + class TreeNode + attr_accessor :val # 節點值 + attr_accessor :left # 左子節點引用 + attr_accessor :right # 右子節點引用 + def initialize(val) + @val = val + end + end ``` === "Zig" @@ -440,7 +449,18 @@ comments: true === "Ruby" ```ruby title="binary_tree.rb" - + # 初始化二元樹 + # 初始化節點 + n1 = TreeNode.new(1) + n2 = TreeNode.new(2) + n3 = TreeNode.new(3) + n4 = TreeNode.new(4) + n5 = TreeNode.new(5) + # 構建節點之間的引用(指標) + n1.left = n2 + n1.right = n3 + n2.left = n4 + n2.right = n5 ``` === "Zig" @@ -605,7 +625,13 @@ comments: true === "Ruby" ```ruby title="binary_tree.rb" - + # 插入與刪除節點 + _p = TreeNode.new(0) + # 在 n1 -> n2 中間插入節點 _p + n1.left = _p + _p.left = n2 + # 刪除節點 + n1.left = n2 ``` === "Zig" diff --git a/zh-Hant/docs/chapter_tree/binary_tree_traversal.md b/zh-Hant/docs/chapter_tree/binary_tree_traversal.md index e72af2ce6..abed7fb67 100755 --- a/zh-Hant/docs/chapter_tree/binary_tree_traversal.md +++ b/zh-Hant/docs/chapter_tree/binary_tree_traversal.md @@ -318,7 +318,20 @@ comments: true === "Ruby" ```ruby title="binary_tree_bfs.rb" - [class]{}-[func]{level_order} + ### 層序走訪 ### + def level_order(root) + # 初始化佇列,加入根節點 + queue = [root] + # 初始化一個串列,用於儲存走訪序列 + res = [] + while !queue.empty? + node = queue.shift # 隊列出隊 + res << node.val # 儲存節點值 + queue << node.left unless node.left.nil? # 左子節點入列 + queue << node.right unless node.right.nil? # 右子節點入列 + end + res + end ``` === "Zig" @@ -791,11 +804,35 @@ comments: true === "Ruby" ```ruby title="binary_tree_dfs.rb" - [class]{}-[func]{pre_order} - - [class]{}-[func]{in_order} - - [class]{}-[func]{post_order} + ### 前序走訪 ### + def pre_order(root) + return if root.nil? + + # 訪問優先順序:根節點 -> 左子樹 -> 右子樹 + $res << root.val + pre_order(root.left) + pre_order(root.right) + end + + ### 中序走訪 ### + def in_order(root) + return if root.nil? + + # 訪問優先順序:左子樹 -> 根節點 -> 右子樹 + in_order(root.left) + $res << root.val + in_order(root.right) + end + + ### 後序走訪 ### + def post_order(root) + return if root.nil? + + # 訪問優先順序:左子樹 -> 右子樹 -> 根節點 + post_order(root.left) + post_order(root.right) + $res << root.val + end ``` === "Zig"