From 739f8a31bb6fff1cd61f952209ffe9e48bd081a9 Mon Sep 17 00:00:00 2001 From: krahets Date: Thu, 11 Apr 2024 01:11:20 +0800 Subject: [PATCH] build --- .../linked_list.md | 2 +- docs/chapter_array_and_linkedlist/list.md | 4 +- .../backtracking_algorithm.md | 12 +- .../knapsack_problem.md | 24 +- .../unbounded_knapsack_problem.md | 8 +- docs/chapter_graph/graph_operations.md | 8 +- docs/chapter_hashing/hash_collision.md | 24 +- docs/chapter_hashing/hash_map.md | 26 +- docs/chapter_heap/build_heap.md | 8 +- docs/chapter_heap/heap.md | 8 +- docs/chapter_preface/suggestions.md | 5 + docs/chapter_sorting/radix_sort.md | 3 +- docs/chapter_stack_and_queue/deque.md | 8 +- .../array_representation_of_tree.md | 14 +- docs/chapter_tree/avl_tree.md | 34 +- docs/chapter_tree/binary_search_tree.md | 18 +- docs/chapter_tree/binary_tree_traversal.md | 8 +- .../linked_list.md | 2 +- en/docs/chapter_array_and_linkedlist/list.md | 4 +- en/docs/chapter_graph/graph_operations.md | 8 +- en/docs/chapter_hashing/hash_collision.md | 24 +- en/docs/chapter_hashing/hash_map.md | 26 +- en/docs/chapter_heap/build_heap.md | 8 +- en/docs/chapter_heap/heap.md | 8 +- en/docs/chapter_stack_and_queue/deque.md | 8 +- .../array_representation_of_tree.md | 14 +- en/docs/chapter_tree/avl_tree.md | 34 +- en/docs/chapter_tree/binary_search_tree.md | 18 +- en/docs/chapter_tree/binary_tree_traversal.md | 8 +- .../chapter_array_and_linkedlist/array.md | 37 +- .../linked_list.md | 35 +- .../docs/chapter_array_and_linkedlist/list.md | 42 +- .../backtracking_algorithm.md | 46 +-- .../chapter_backtracking/n_queens_problem.md | 20 +- .../permutations_problem.md | 26 +- .../subset_sum_problem.md | 46 +-- .../iteration_and_recursion.md | 32 +- .../space_complexity.md | 28 +- .../time_complexity.md | 69 ++-- .../basic_data_types.md | 9 +- .../chapter_data_structure/number_encoding.md | 2 +- .../docs/chapter_data_structure/summary.md | 32 ++ .../binary_search_recur.md | 4 +- .../build_binary_tree_problem.md | 14 +- .../hanota_problem.md | 6 +- .../dp_problem_features.md | 16 +- .../dp_solution_pipeline.md | 39 +- .../edit_distance_problem.md | 16 +- .../intro_to_dynamic_programming.md | 33 +- .../knapsack_problem.md | 45 ++- .../unbounded_knapsack_problem.md | 49 +-- .../docs/chapter_graph/graph_operations.md | 35 +- zh-Hant/docs/chapter_graph/graph_traversal.md | 38 +- .../fractional_knapsack_problem.md | 30 +- .../docs/chapter_greedy/greedy_algorithm.md | 4 +- .../chapter_greedy/max_capacity_problem.md | 8 +- .../max_product_cutting_problem.md | 10 +- .../docs/chapter_hashing/hash_algorithm.md | 8 +- .../docs/chapter_hashing/hash_collision.md | 57 +-- zh-Hant/docs/chapter_hashing/hash_map.md | 78 ++-- zh-Hant/docs/chapter_heap/build_heap.md | 19 +- zh-Hant/docs/chapter_heap/heap.md | 24 +- zh-Hant/docs/chapter_heap/top_k.md | 4 +- zh-Hant/docs/chapter_preface/suggestions.md | 5 + .../docs/chapter_searching/binary_search.md | 8 +- .../chapter_searching/binary_search_edge.md | 8 +- .../binary_search_insertion.md | 8 +- .../replace_linear_by_hashing.md | 8 +- zh-Hant/docs/chapter_sorting/bubble_sort.md | 10 +- zh-Hant/docs/chapter_sorting/bucket_sort.md | 8 +- zh-Hant/docs/chapter_sorting/counting_sort.md | 12 +- zh-Hant/docs/chapter_sorting/heap_sort.md | 13 +- .../docs/chapter_sorting/insertion_sort.md | 6 +- zh-Hant/docs/chapter_sorting/merge_sort.md | 10 +- zh-Hant/docs/chapter_sorting/quick_sort.md | 16 +- zh-Hant/docs/chapter_sorting/radix_sort.md | 16 +- .../docs/chapter_sorting/selection_sort.md | 7 +- zh-Hant/docs/chapter_stack_and_queue/deque.md | 371 +++++++++++++++--- zh-Hant/docs/chapter_stack_and_queue/queue.md | 263 ++++++++++--- zh-Hant/docs/chapter_stack_and_queue/stack.md | 218 +++++++--- .../array_representation_of_tree.md | 41 +- zh-Hant/docs/chapter_tree/avl_tree.md | 48 ++- .../docs/chapter_tree/binary_search_tree.md | 66 ++-- zh-Hant/docs/chapter_tree/binary_tree.md | 8 +- .../chapter_tree/binary_tree_traversal.md | 47 +-- 85 files changed, 1555 insertions(+), 979 deletions(-) diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md index df33f9097..626758c70 100755 --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -1253,7 +1253,7 @@ comments: true var index = 0 var h = head while (h != null) { - if (h.value == target) + if (h._val == target) return index h = h.next index++ diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index 5ef0ecc26..0abf3d22d 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -2309,7 +2309,7 @@ comments: true # 元素数量超出容量时,触发扩容机制 extend_capacity if size == capacity @arr[size] = num - + # 更新元素数量 @size += 1 end @@ -2323,7 +2323,7 @@ comments: true # 将索引 index 以及之后的元素都向后移动一位 for j in (size - 1).downto(index) - @arr[j + 1] = @arr[j] + @arr[j + 1] = @arr[j] end @arr[index] = num diff --git a/docs/chapter_backtracking/backtracking_algorithm.md b/docs/chapter_backtracking/backtracking_algorithm.md index 2e4181b17..4c0a89fcc 100644 --- a/docs/chapter_backtracking/backtracking_algorithm.md +++ b/docs/chapter_backtracking/backtracking_algorithm.md @@ -208,7 +208,7 @@ comments: true if (root == null) { return } - if (root.value == 7) { + if (root._val == 7) { // 记录解 res!!.add(root) } @@ -508,7 +508,7 @@ comments: true } // 尝试 path!!.add(root) - if (root.value == 7) { + if (root._val == 7) { // 记录解 res!!.add(path!!.toMutableList()) } @@ -847,12 +847,12 @@ comments: true /* 前序遍历:例题三 */ fun preOrder(root: TreeNode?) { // 剪枝 - if (root == null || root.value == 3) { + if (root == null || root._val == 3) { return } // 尝试 path!!.add(root) - if (root.value == 7) { + if (root._val == 7) { // 记录解 res!!.add(path!!.toMutableList()) } @@ -1791,7 +1791,7 @@ comments: true ```kotlin title="preorder_traversal_iii_template.kt" /* 判断当前状态是否为解 */ fun isSolution(state: MutableList): Boolean { - return state.isNotEmpty() && state[state.size - 1]?.value == 7 + return state.isNotEmpty() && state[state.size - 1]?._val == 7 } /* 记录解 */ @@ -1801,7 +1801,7 @@ comments: true /* 判断在当前状态下,该选择是否合法 */ fun isValid(state: MutableList?, choice: TreeNode?): Boolean { - return choice != null && choice.value != 3 + return choice != null && choice._val != 3 } /* 更新状态 */ diff --git a/docs/chapter_dynamic_programming/knapsack_problem.md b/docs/chapter_dynamic_programming/knapsack_problem.md index 0b802848d..347b598fd 100644 --- a/docs/chapter_dynamic_programming/knapsack_problem.md +++ b/docs/chapter_dynamic_programming/knapsack_problem.md @@ -301,7 +301,7 @@ $$ /* 0-1 背包:暴力搜索 */ fun knapsackDFS( wgt: IntArray, - value: IntArray, + _val: IntArray, i: Int, c: Int ): Int { @@ -311,11 +311,11 @@ $$ } // 若超过背包容量,则只能选择不放入背包 if (wgt[i - 1] > c) { - return knapsackDFS(wgt, value, i - 1, c) + return knapsackDFS(wgt, _val, i - 1, c) } // 计算不放入和放入物品 i 的最大价值 - val no = knapsackDFS(wgt, value, i - 1, c) - val yes = knapsackDFS(wgt, value, i - 1, c - wgt[i - 1]) + value[i - 1] + val no = knapsackDFS(wgt, _val, i - 1, c) + val yes = knapsackDFS(wgt, _val, i - 1, c - wgt[i - 1]) + _val[i - 1] // 返回两种方案中价值更大的那一个 return max(no, yes) } @@ -671,7 +671,7 @@ $$ /* 0-1 背包:记忆化搜索 */ fun knapsackDFSMem( wgt: IntArray, - value: IntArray, + _val: IntArray, mem: Array, i: Int, c: Int @@ -686,11 +686,11 @@ $$ } // 若超过背包容量,则只能选择不放入背包 if (wgt[i - 1] > c) { - return knapsackDFSMem(wgt, value, mem, i - 1, c) + return knapsackDFSMem(wgt, _val, mem, i - 1, c) } // 计算不放入和放入物品 i 的最大价值 - val no = knapsackDFSMem(wgt, value, mem, i - 1, c) - val yes = knapsackDFSMem(wgt, value, mem, i - 1, c - wgt[i - 1]) + value[i - 1] + val no = knapsackDFSMem(wgt, _val, mem, i - 1, c) + val yes = knapsackDFSMem(wgt, _val, mem, i - 1, c - wgt[i - 1]) + _val[i - 1] // 记录并返回两种方案中价值更大的那一个 mem[i][c] = max(no, yes) return mem[i][c] @@ -1038,7 +1038,7 @@ $$ /* 0-1 背包:动态规划 */ fun knapsackDP( wgt: IntArray, - value: IntArray, + _val: IntArray, cap: Int ): Int { val n = wgt.size @@ -1052,7 +1052,7 @@ $$ dp[i][c] = dp[i - 1][c] } else { // 不选和选物品 i 这两种方案的较大值 - dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + value[i - 1]) + dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + _val[i - 1]) } } } @@ -1431,7 +1431,7 @@ $$ /* 0-1 背包:空间优化后的动态规划 */ fun knapsackDPComp( wgt: IntArray, - value: IntArray, + _val: IntArray, cap: Int ): Int { val n = wgt.size @@ -1444,7 +1444,7 @@ $$ if (wgt[i - 1] <= c) { // 不选和选物品 i 这两种方案的较大值 dp[c] = - max(dp[c], dp[c - wgt[i - 1]] + value[i - 1]) + max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1]) } } } diff --git a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md index eccd216d2..74403af4c 100644 --- a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md +++ b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md @@ -327,7 +327,7 @@ $$ ```kotlin title="unbounded_knapsack.kt" /* 完全背包:动态规划 */ - fun unboundedKnapsackDP(wgt: IntArray, value: IntArray, cap: Int): Int { + fun unboundedKnapsackDP(wgt: IntArray, _val: IntArray, cap: Int): Int { val n = wgt.size // 初始化 dp 表 val dp = Array(n + 1) { IntArray(cap + 1) } @@ -339,7 +339,7 @@ $$ dp[i][c] = dp[i - 1][c] } else { // 不选和选物品 i 这两种方案的较大值 - dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + value[i - 1]) + dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + _val[i - 1]) } } } @@ -684,7 +684,7 @@ $$ /* 完全背包:空间优化后的动态规划 */ fun unboundedKnapsackDPComp( wgt: IntArray, - value: IntArray, + _val: IntArray, cap: Int ): Int { val n = wgt.size @@ -698,7 +698,7 @@ $$ dp[c] = dp[c] } else { // 不选和选物品 i 这两种方案的较大值 - dp[c] = max(dp[c], dp[c - wgt[i - 1]] + value[i - 1]) + dp[c] = max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1]) } } } diff --git a/docs/chapter_graph/graph_operations.md b/docs/chapter_graph/graph_operations.md index f8768ba6f..114725456 100644 --- a/docs/chapter_graph/graph_operations.md +++ b/docs/chapter_graph/graph_operations.md @@ -1066,10 +1066,10 @@ comments: true } /* 添加顶点 */ - fun addVertex(value: Int) { + fun addVertex(_val: Int) { val n = size() // 向顶点列表中添加新顶点的值 - vertices.add(value) + vertices.add(_val) // 在邻接矩阵中添加一行 val newRow = mutableListOf() for (j in 0..() for (vertex in pair.value) { - tmp.add(vertex.value) + tmp.add(vertex._val) } - println("${pair.key.value}: $tmp,") + println("${pair.key._val}: $tmp,") } } } diff --git a/docs/chapter_hashing/hash_collision.md b/docs/chapter_hashing/hash_collision.md index 29a61532c..067c26d9b 100644 --- a/docs/chapter_hashing/hash_collision.md +++ b/docs/chapter_hashing/hash_collision.md @@ -1347,14 +1347,14 @@ comments: true val bucket = buckets[index] // 遍历桶,若找到 key ,则返回对应 val for (pair in bucket) { - if (pair.key == key) return pair.value + if (pair.key == key) return pair._val } // 若未找到 key ,则返回 null return null } /* 添加操作 */ - fun put(key: Int, value: String) { + fun put(key: Int, _val: String) { // 当负载因子超过阈值时,执行扩容 if (loadFactor() > loadThres) { extend() @@ -1364,12 +1364,12 @@ comments: true // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 for (pair in bucket) { if (pair.key == key) { - pair.value = value + pair._val = _val return } } // 若无该 key ,则将键值对添加至尾部 - val pair = Pair(key, value) + val pair = Pair(key, _val) bucket.add(pair) size++ } @@ -1403,7 +1403,7 @@ comments: true // 将键值对从原哈希表搬运至新哈希表 for (bucket in bucketsTmp) { for (pair in bucket) { - put(pair.key, pair.value) + put(pair.key, pair._val) } } } @@ -1414,7 +1414,7 @@ comments: true val res = mutableListOf() for (pair in bucket) { val k = pair.key - val v = pair.value + val v = pair._val res.add("$k -> $v") } println(res) @@ -3017,14 +3017,14 @@ comments: true val index = findBucket(key) // 若找到键值对,则返回对应 val if (buckets[index] != null && buckets[index] != TOMBSTONE) { - return buckets[index]?.value + return buckets[index]?._val } // 若键值对不存在,则返回 null return null } /* 添加操作 */ - fun put(key: Int, value: String) { + fun put(key: Int, _val: String) { // 当负载因子超过阈值时,执行扩容 if (loadFactor() > loadThres) { extend() @@ -3033,11 +3033,11 @@ comments: true val index = findBucket(key) // 若找到键值对,则覆盖 val 并返回 if (buckets[index] != null && buckets[index] != TOMBSTONE) { - buckets[index]!!.value = value + buckets[index]!!._val = _val return } // 若键值对不存在,则添加该键值对 - buckets[index] = Pair(key, value) + buckets[index] = Pair(key, _val) size++ } @@ -3063,7 +3063,7 @@ comments: true // 将键值对从原哈希表搬运至新哈希表 for (pair in bucketsTmp) { if (pair != null && pair != TOMBSTONE) { - put(pair.key, pair.value) + put(pair.key, pair._val) } } } @@ -3076,7 +3076,7 @@ comments: true } else if (pair == TOMBSTONE) { println("TOMESTOME") } else { - println("${pair.key} -> ${pair.value}") + println("${pair.key} -> ${pair._val}") } } } diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 90caede5b..927103289 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -1584,7 +1584,7 @@ index = hash(key) % capacity /* 键值对 */ class Pair( var key: Int, - var value: String + var _val: String ) /* 基于数组实现的哈希表 */ @@ -1602,12 +1602,12 @@ index = hash(key) % capacity fun get(key: Int): String? { val index = hashFunc(key) val pair = buckets[index] ?: return null - return pair.value + return pair._val } /* 添加操作 */ - fun put(key: Int, value: String) { - val pair = Pair(key, value) + fun put(key: Int, _val: String) { + val pair = Pair(key, _val) val index = hashFunc(key) buckets[index] = pair } @@ -1643,7 +1643,7 @@ index = hash(key) % capacity fun valueSet(): MutableList { val valueSet = mutableListOf() for (pair in buckets) { - pair?.let { valueSet.add(it.value) } + pair?.let { valueSet.add(it._val) } } return valueSet } @@ -1652,8 +1652,8 @@ index = hash(key) % capacity fun print() { for (kv in pairSet()) { val key = kv.key - val value = kv.value - println("${key} -> ${value}") + val _val = kv._val + println("${key} -> ${_val}") } } } @@ -1673,12 +1673,12 @@ index = hash(key) % capacity fun get(key: Int): String? { val index = hashFunc(key) val pair = buckets[index] ?: return null - return pair.value + return pair._val } /* 添加操作 */ - fun put(key: Int, value: String) { - val pair = Pair(key, value) + fun put(key: Int, _val: String) { + val pair = Pair(key, _val) val index = hashFunc(key) buckets[index] = pair } @@ -1714,7 +1714,7 @@ index = hash(key) % capacity fun valueSet(): MutableList { val valueSet = mutableListOf() for (pair in buckets) { - pair?.let { valueSet.add(it.value) } + pair?.let { valueSet.add(it._val) } } return valueSet } @@ -1723,8 +1723,8 @@ index = hash(key) % capacity fun print() { for (kv in pairSet()) { val key = kv.key - val value = kv.value - println("${key} -> ${value}") + val _val = kv._val + println("${key} -> ${_val}") } } } diff --git a/docs/chapter_heap/build_heap.md b/docs/chapter_heap/build_heap.md index 897147dff..93a931e68 100644 --- a/docs/chapter_heap/build_heap.md +++ b/docs/chapter_heap/build_heap.md @@ -240,9 +240,9 @@ comments: true } /* 元素入堆 */ - fun push(value: Int) { + fun push(_val: Int) { // 添加节点 - maxHeap.add(value) + maxHeap.add(_val) // 从底至顶堆化 siftUp(size() - 1) } @@ -270,11 +270,11 @@ comments: true // 交换根节点与最右叶节点(交换首元素与尾元素) swap(0, size() - 1) // 删除节点 - val value = maxHeap.removeAt(size() - 1) + val _val = maxHeap.removeAt(size() - 1) // 从顶至底堆化 siftDown(0) // 返回堆顶元素 - return value + return _val } /* 从节点 i 开始,从顶至底堆化 */ diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 00e886c14..678f242a5 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -1184,9 +1184,9 @@ comments: true ```kotlin title="my_heap.kt" /* 元素入堆 */ - fun push(value: Int) { + fun push(_val: Int) { // 添加节点 - maxHeap.add(value) + maxHeap.add(_val) // 从底至顶堆化 siftUp(size() - 1) } @@ -1736,11 +1736,11 @@ comments: true // 交换根节点与最右叶节点(交换首元素与尾元素) swap(0, size() - 1) // 删除节点 - val value = maxHeap.removeAt(size() - 1) + val _val = maxHeap.removeAt(size() - 1) // 从顶至底堆化 siftDown(0) // 返回堆顶元素 - return value + return _val } /* 从节点 i 开始,从顶至底堆化 */ diff --git a/docs/chapter_preface/suggestions.md b/docs/chapter_preface/suggestions.md index 9b9fb2a0a..89831b0fb 100644 --- a/docs/chapter_preface/suggestions.md +++ b/docs/chapter_preface/suggestions.md @@ -176,7 +176,12 @@ comments: true === "Ruby" ```ruby title="" + ### 标题注释,用于标注函数、类、测试样例等 ### + # 内容注释,用于详解代码 + + # 多行 + # 注释 ``` === "Zig" diff --git a/docs/chapter_sorting/radix_sort.md b/docs/chapter_sorting/radix_sort.md index 3f98d3ed1..1db0eaff2 100644 --- a/docs/chapter_sorting/radix_sort.md +++ b/docs/chapter_sorting/radix_sort.md @@ -170,12 +170,13 @@ $$ if (num > m) m = num; // 按照从低位到高位的顺序遍历 - for (int exp = 1; exp <= m; exp *= 10) + for (int exp = 1; exp <= m; exp *= 10) { // 对数组元素的第 k 位执行计数排序 // k = 1 -> exp = 1 // k = 2 -> exp = 10 // 即 exp = 10^(k-1) countingSortDigit(nums, exp); + } } ``` diff --git a/docs/chapter_stack_and_queue/deque.md b/docs/chapter_stack_and_queue/deque.md index 456e3fcd9..eba2a04e1 100644 --- a/docs/chapter_stack_and_queue/deque.md +++ b/docs/chapter_stack_and_queue/deque.md @@ -1958,10 +1958,10 @@ comments: true fun pop(isFront: Boolean): Int { if (isEmpty()) throw IndexOutOfBoundsException() - val value: Int + val _val: Int // 队首出队操作 if (isFront) { - value = front!!._val // 暂存头节点值 + _val = front!!._val // 暂存头节点值 // 删除头节点 val fNext = front!!.next if (fNext != null) { @@ -1971,7 +1971,7 @@ comments: true front = fNext // 更新头节点 // 队尾出队操作 } else { - value = rear!!._val // 暂存尾节点值 + _val = rear!!._val // 暂存尾节点值 // 删除尾节点 val rPrev = rear!!.prev if (rPrev != null) { @@ -1981,7 +1981,7 @@ comments: true rear = rPrev // 更新尾节点 } queSize-- // 更新队列长度 - return value + return _val } /* 队首出队 */ diff --git a/docs/chapter_tree/array_representation_of_tree.md b/docs/chapter_tree/array_representation_of_tree.md index e0a418810..ea64d31b9 100644 --- a/docs/chapter_tree/array_representation_of_tree.md +++ b/docs/chapter_tree/array_representation_of_tree.md @@ -1180,7 +1180,7 @@ comments: true } /* 获取索引为 i 节点的值 */ - fun value(i: Int): Int? { + fun _val(i: Int): Int? { // 若索引越界,则返回 null ,代表空位 if (i < 0 || i >= size()) return null return tree[i] @@ -1206,8 +1206,8 @@ comments: true val res = mutableListOf() // 直接遍历数组 for (i in 0..) { // 若为空位,则返回 - if (value(i) == null) + if (_val(i) == null) return // 前序遍历 if ("pre" == order) - res.add(value(i)) + res.add(_val(i)) dfs(left(i), order, res) // 中序遍历 if ("in" == order) - res.add(value(i)) + res.add(_val(i)) dfs(right(i), order, res) // 后序遍历 if ("post" == order) - res.add(value(i)) + res.add(_val(i)) } /* 前序遍历 */ diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index 77f785b81..7ad343062 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -2012,20 +2012,20 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区 ```kotlin title="avl_tree.kt" /* 插入节点 */ - fun insert(value: Int) { - root = insertHelper(root, value) + fun insert(_val: Int) { + root = insertHelper(root, _val) } /* 递归插入节点(辅助方法) */ - fun insertHelper(n: TreeNode?, value: Int): TreeNode { + fun insertHelper(n: TreeNode?, _val: Int): TreeNode { if (n == null) - return TreeNode(value) + return TreeNode(_val) var node = n /* 1. 查找插入位置并插入节点 */ - if (value < node.value) - node.left = insertHelper(node.left, value) - else if (value > node.value) - node.right = insertHelper(node.right, value) + if (_val < node._val) + node.left = insertHelper(node.left, _val) + else if (_val > node._val) + node.right = insertHelper(node.right, _val) else return node // 重复节点不插入,直接返回 updateHeight(node) // 更新节点高度 @@ -2595,18 +2595,18 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区 ```kotlin title="avl_tree.kt" /* 删除节点 */ - fun remove(value: Int) { - root = removeHelper(root, value) + fun remove(_val: Int) { + root = removeHelper(root, _val) } /* 递归删除节点(辅助方法) */ - fun removeHelper(n: TreeNode?, value: Int): TreeNode? { + fun removeHelper(n: TreeNode?, _val: Int): TreeNode? { var node = n ?: return null /* 1. 查找节点并删除 */ - if (value < node.value) - node.left = removeHelper(node.left, value) - else if (value > node.value) - node.right = removeHelper(node.right, value) + if (_val < node._val) + node.left = removeHelper(node.left, _val) + else if (_val > node._val) + node.right = removeHelper(node.right, _val) else { if (node.left == null || node.right == null) { val child = if (node.left != null) @@ -2625,8 +2625,8 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区 while (temp!!.left != null) { temp = temp.left } - node.right = removeHelper(node.right, temp.value) - node.value = temp.value + node.right = removeHelper(node.right, temp._val) + node._val = temp._val } } updateHeight(node) // 更新节点高度 diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 759e29013..741a6e4f0 100755 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -299,10 +299,10 @@ comments: true // 循环查找,越过叶节点后跳出 while (cur != null) { // 目标节点在 cur 的右子树中 - cur = if (cur.value < num) + cur = if (cur._val < num) cur.right // 目标节点在 cur 的左子树中 - else if (cur.value > num) + else if (cur._val > num) cur.left // 找到目标节点,跳出循环 else @@ -751,11 +751,11 @@ comments: true // 循环查找,越过叶节点后跳出 while (cur != null) { // 找到重复节点,直接返回 - if (cur.value == num) + if (cur._val == num) return pre = cur // 插入位置在 cur 的右子树中 - cur = if (cur.value < num) + cur = if (cur._val < num) cur.right // 插入位置在 cur 的左子树中 else @@ -763,7 +763,7 @@ comments: true } // 插入节点 val node = TreeNode(num) - if (pre?.value!! < num) + if (pre?._val!! < num) pre.right = node else pre.left = node @@ -1497,11 +1497,11 @@ comments: true // 循环查找,越过叶节点后跳出 while (cur != null) { // 找到待删除节点,跳出循环 - if (cur.value == num) + if (cur._val == num) break pre = cur // 待删除节点在 cur 的右子树中 - cur = if (cur.value < num) + cur = if (cur._val < num) cur.right // 待删除节点在 cur 的左子树中 else @@ -1535,9 +1535,9 @@ comments: true tmp = tmp.left } // 递归删除节点 tmp - remove(tmp.value) + remove(tmp._val) // 用 tmp 覆盖 cur - cur.value = tmp.value + cur._val = tmp._val } } ``` diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index 3688a6359..1ef8576b5 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -305,7 +305,7 @@ comments: true val list = mutableListOf() while (queue.isNotEmpty()) { val node = queue.poll() // 队列出队 - list.add(node?.value!!) // 保存节点值 + list.add(node?._val!!) // 保存节点值 if (node.left != null) queue.offer(node.left) // 左子节点入队 if (node.right != null) @@ -764,7 +764,7 @@ comments: true fun preOrder(root: TreeNode?) { if (root == null) return // 访问优先级:根节点 -> 左子树 -> 右子树 - list.add(root.value) + list.add(root._val) preOrder(root.left) preOrder(root.right) } @@ -774,7 +774,7 @@ comments: true if (root == null) return // 访问优先级:左子树 -> 根节点 -> 右子树 inOrder(root.left) - list.add(root.value) + list.add(root._val) inOrder(root.right) } @@ -784,7 +784,7 @@ comments: true // 访问优先级:左子树 -> 右子树 -> 根节点 postOrder(root.left) postOrder(root.right) - list.add(root.value) + list.add(root._val) } ``` diff --git a/en/docs/chapter_array_and_linkedlist/linked_list.md b/en/docs/chapter_array_and_linkedlist/linked_list.md index ff49de71d..e28168773 100755 --- a/en/docs/chapter_array_and_linkedlist/linked_list.md +++ b/en/docs/chapter_array_and_linkedlist/linked_list.md @@ -1200,7 +1200,7 @@ Traverse the linked list to locate a node whose value matches `target`, and then var index = 0 var h = head while (h != null) { - if (h.value == target) + if (h._val == target) return index h = h.next index++ diff --git a/en/docs/chapter_array_and_linkedlist/list.md b/en/docs/chapter_array_and_linkedlist/list.md index ceca2c68f..4b549f7ae 100755 --- a/en/docs/chapter_array_and_linkedlist/list.md +++ b/en/docs/chapter_array_and_linkedlist/list.md @@ -2175,7 +2175,7 @@ To enhance our understanding of how lists work, we will attempt to implement a s # 元素数量超出容量时,触发扩容机制 extend_capacity if size == capacity @arr[size] = num - + # 更新元素数量 @size += 1 end @@ -2189,7 +2189,7 @@ To enhance our understanding of how lists work, we will attempt to implement a s # 将索引 index 以及之后的元素都向后移动一位 for j in (size - 1).downto(index) - @arr[j + 1] = @arr[j] + @arr[j + 1] = @arr[j] end @arr[index] = num diff --git a/en/docs/chapter_graph/graph_operations.md b/en/docs/chapter_graph/graph_operations.md index b007477cb..d489e8023 100644 --- a/en/docs/chapter_graph/graph_operations.md +++ b/en/docs/chapter_graph/graph_operations.md @@ -1066,10 +1066,10 @@ Below is the implementation code for graphs represented using an adjacency matri } /* 添加顶点 */ - fun addVertex(value: Int) { + fun addVertex(_val: Int) { val n = size() // 向顶点列表中添加新顶点的值 - vertices.add(value) + vertices.add(_val) // 在邻接矩阵中添加一行 val newRow = mutableListOf() for (j in 0..() for (vertex in pair.value) { - tmp.add(vertex.value) + tmp.add(vertex._val) } - println("${pair.key.value}: $tmp,") + println("${pair.key._val}: $tmp,") } } } diff --git a/en/docs/chapter_hashing/hash_collision.md b/en/docs/chapter_hashing/hash_collision.md index ca9b83363..469044bf0 100644 --- a/en/docs/chapter_hashing/hash_collision.md +++ b/en/docs/chapter_hashing/hash_collision.md @@ -1347,14 +1347,14 @@ The code below provides a simple implementation of a separate chaining hash tabl val bucket = buckets[index] // 遍历桶,若找到 key ,则返回对应 val for (pair in bucket) { - if (pair.key == key) return pair.value + if (pair.key == key) return pair._val } // 若未找到 key ,则返回 null return null } /* 添加操作 */ - fun put(key: Int, value: String) { + fun put(key: Int, _val: String) { // 当负载因子超过阈值时,执行扩容 if (loadFactor() > loadThres) { extend() @@ -1364,12 +1364,12 @@ The code below provides a simple implementation of a separate chaining hash tabl // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 for (pair in bucket) { if (pair.key == key) { - pair.value = value + pair._val = _val return } } // 若无该 key ,则将键值对添加至尾部 - val pair = Pair(key, value) + val pair = Pair(key, _val) bucket.add(pair) size++ } @@ -1403,7 +1403,7 @@ The code below provides a simple implementation of a separate chaining hash tabl // 将键值对从原哈希表搬运至新哈希表 for (bucket in bucketsTmp) { for (pair in bucket) { - put(pair.key, pair.value) + put(pair.key, pair._val) } } } @@ -1414,7 +1414,7 @@ The code below provides a simple implementation of a separate chaining hash tabl val res = mutableListOf() for (pair in bucket) { val k = pair.key - val v = pair.value + val v = pair._val res.add("$k -> $v") } println(res) @@ -3017,14 +3017,14 @@ The code below implements an open addressing (linear probing) hash table with la val index = findBucket(key) // 若找到键值对,则返回对应 val if (buckets[index] != null && buckets[index] != TOMBSTONE) { - return buckets[index]?.value + return buckets[index]?._val } // 若键值对不存在,则返回 null return null } /* 添加操作 */ - fun put(key: Int, value: String) { + fun put(key: Int, _val: String) { // 当负载因子超过阈值时,执行扩容 if (loadFactor() > loadThres) { extend() @@ -3033,11 +3033,11 @@ The code below implements an open addressing (linear probing) hash table with la val index = findBucket(key) // 若找到键值对,则覆盖 val 并返回 if (buckets[index] != null && buckets[index] != TOMBSTONE) { - buckets[index]!!.value = value + buckets[index]!!._val = _val return } // 若键值对不存在,则添加该键值对 - buckets[index] = Pair(key, value) + buckets[index] = Pair(key, _val) size++ } @@ -3063,7 +3063,7 @@ The code below implements an open addressing (linear probing) hash table with la // 将键值对从原哈希表搬运至新哈希表 for (pair in bucketsTmp) { if (pair != null && pair != TOMBSTONE) { - put(pair.key, pair.value) + put(pair.key, pair._val) } } } @@ -3076,7 +3076,7 @@ The code below implements an open addressing (linear probing) hash table with la } else if (pair == TOMBSTONE) { println("TOMESTOME") } else { - println("${pair.key} -> ${pair.value}") + println("${pair.key} -> ${pair._val}") } } } diff --git a/en/docs/chapter_hashing/hash_map.md b/en/docs/chapter_hashing/hash_map.md index 6bab96460..8ab6f96dd 100755 --- a/en/docs/chapter_hashing/hash_map.md +++ b/en/docs/chapter_hashing/hash_map.md @@ -1543,7 +1543,7 @@ The following code implements a simple hash table. Here, we encapsulate `key` an /* 键值对 */ class Pair( var key: Int, - var value: String + var _val: String ) /* 基于数组实现的哈希表 */ @@ -1561,12 +1561,12 @@ The following code implements a simple hash table. Here, we encapsulate `key` an fun get(key: Int): String? { val index = hashFunc(key) val pair = buckets[index] ?: return null - return pair.value + return pair._val } /* 添加操作 */ - fun put(key: Int, value: String) { - val pair = Pair(key, value) + fun put(key: Int, _val: String) { + val pair = Pair(key, _val) val index = hashFunc(key) buckets[index] = pair } @@ -1602,7 +1602,7 @@ The following code implements a simple hash table. Here, we encapsulate `key` an fun valueSet(): MutableList { val valueSet = mutableListOf() for (pair in buckets) { - pair?.let { valueSet.add(it.value) } + pair?.let { valueSet.add(it._val) } } return valueSet } @@ -1611,8 +1611,8 @@ The following code implements a simple hash table. Here, we encapsulate `key` an fun print() { for (kv in pairSet()) { val key = kv.key - val value = kv.value - println("${key} -> ${value}") + val _val = kv._val + println("${key} -> ${_val}") } } } @@ -1632,12 +1632,12 @@ The following code implements a simple hash table. Here, we encapsulate `key` an fun get(key: Int): String? { val index = hashFunc(key) val pair = buckets[index] ?: return null - return pair.value + return pair._val } /* 添加操作 */ - fun put(key: Int, value: String) { - val pair = Pair(key, value) + fun put(key: Int, _val: String) { + val pair = Pair(key, _val) val index = hashFunc(key) buckets[index] = pair } @@ -1673,7 +1673,7 @@ The following code implements a simple hash table. Here, we encapsulate `key` an fun valueSet(): MutableList { val valueSet = mutableListOf() for (pair in buckets) { - pair?.let { valueSet.add(it.value) } + pair?.let { valueSet.add(it._val) } } return valueSet } @@ -1682,8 +1682,8 @@ The following code implements a simple hash table. Here, we encapsulate `key` an fun print() { for (kv in pairSet()) { val key = kv.key - val value = kv.value - println("${key} -> ${value}") + val _val = kv._val + println("${key} -> ${_val}") } } } diff --git a/en/docs/chapter_heap/build_heap.md b/en/docs/chapter_heap/build_heap.md index a0c3173f9..83be45162 100644 --- a/en/docs/chapter_heap/build_heap.md +++ b/en/docs/chapter_heap/build_heap.md @@ -240,9 +240,9 @@ It's worth mentioning that **since leaf nodes have no children, they naturally f } /* 元素入堆 */ - fun push(value: Int) { + fun push(_val: Int) { // 添加节点 - maxHeap.add(value) + maxHeap.add(_val) // 从底至顶堆化 siftUp(size() - 1) } @@ -270,11 +270,11 @@ It's worth mentioning that **since leaf nodes have no children, they naturally f // 交换根节点与最右叶节点(交换首元素与尾元素) swap(0, size() - 1) // 删除节点 - val value = maxHeap.removeAt(size() - 1) + val _val = maxHeap.removeAt(size() - 1) // 从顶至底堆化 siftDown(0) // 返回堆顶元素 - return value + return _val } /* 从节点 i 开始,从顶至底堆化 */ diff --git a/en/docs/chapter_heap/heap.md b/en/docs/chapter_heap/heap.md index 658b3817d..27f2c0f79 100644 --- a/en/docs/chapter_heap/heap.md +++ b/en/docs/chapter_heap/heap.md @@ -1183,9 +1183,9 @@ Given a total of $n$ nodes, the height of the tree is $O(\log n)$. Hence, the lo ```kotlin title="my_heap.kt" /* 元素入堆 */ - fun push(value: Int) { + fun push(_val: Int) { // 添加节点 - maxHeap.add(value) + maxHeap.add(_val) // 从底至顶堆化 siftUp(size() - 1) } @@ -1735,11 +1735,11 @@ Similar to the element insertion operation, the time complexity of the top eleme // 交换根节点与最右叶节点(交换首元素与尾元素) swap(0, size() - 1) // 删除节点 - val value = maxHeap.removeAt(size() - 1) + val _val = maxHeap.removeAt(size() - 1) // 从顶至底堆化 siftDown(0) // 返回堆顶元素 - return value + return _val } /* 从节点 i 开始,从顶至底堆化 */ diff --git a/en/docs/chapter_stack_and_queue/deque.md b/en/docs/chapter_stack_and_queue/deque.md index e6da380a8..48621087e 100644 --- a/en/docs/chapter_stack_and_queue/deque.md +++ b/en/docs/chapter_stack_and_queue/deque.md @@ -1904,10 +1904,10 @@ The implementation code is as follows: fun pop(isFront: Boolean): Int { if (isEmpty()) throw IndexOutOfBoundsException() - val value: Int + val _val: Int // 队首出队操作 if (isFront) { - value = front!!._val // 暂存头节点值 + _val = front!!._val // 暂存头节点值 // 删除头节点 val fNext = front!!.next if (fNext != null) { @@ -1917,7 +1917,7 @@ The implementation code is as follows: front = fNext // 更新头节点 // 队尾出队操作 } else { - value = rear!!._val // 暂存尾节点值 + _val = rear!!._val // 暂存尾节点值 // 删除尾节点 val rPrev = rear!!.prev if (rPrev != null) { @@ -1927,7 +1927,7 @@ The implementation code is as follows: rear = rPrev // 更新尾节点 } queSize-- // 更新队列长度 - return value + return _val } /* 队首出队 */ diff --git a/en/docs/chapter_tree/array_representation_of_tree.md b/en/docs/chapter_tree/array_representation_of_tree.md index 10770f1ec..e2e6d59c7 100644 --- a/en/docs/chapter_tree/array_representation_of_tree.md +++ b/en/docs/chapter_tree/array_representation_of_tree.md @@ -1180,7 +1180,7 @@ The following code implements a binary tree based on array representation, inclu } /* 获取索引为 i 节点的值 */ - fun value(i: Int): Int? { + fun _val(i: Int): Int? { // 若索引越界,则返回 null ,代表空位 if (i < 0 || i >= size()) return null return tree[i] @@ -1206,8 +1206,8 @@ The following code implements a binary tree based on array representation, inclu val res = mutableListOf() // 直接遍历数组 for (i in 0..) { // 若为空位,则返回 - if (value(i) == null) + if (_val(i) == null) return // 前序遍历 if ("pre" == order) - res.add(value(i)) + res.add(_val(i)) dfs(left(i), order, res) // 中序遍历 if ("in" == order) - res.add(value(i)) + res.add(_val(i)) dfs(right(i), order, res) // 后序遍历 if ("post" == order) - res.add(value(i)) + res.add(_val(i)) } /* 前序遍历 */ diff --git a/en/docs/chapter_tree/avl_tree.md b/en/docs/chapter_tree/avl_tree.md index 5644a8daa..fbe7eec51 100644 --- a/en/docs/chapter_tree/avl_tree.md +++ b/en/docs/chapter_tree/avl_tree.md @@ -2012,20 +2012,20 @@ The node insertion operation in AVL trees is similar to that in binary search tr ```kotlin title="avl_tree.kt" /* 插入节点 */ - fun insert(value: Int) { - root = insertHelper(root, value) + fun insert(_val: Int) { + root = insertHelper(root, _val) } /* 递归插入节点(辅助方法) */ - fun insertHelper(n: TreeNode?, value: Int): TreeNode { + fun insertHelper(n: TreeNode?, _val: Int): TreeNode { if (n == null) - return TreeNode(value) + return TreeNode(_val) var node = n /* 1. 查找插入位置并插入节点 */ - if (value < node.value) - node.left = insertHelper(node.left, value) - else if (value > node.value) - node.right = insertHelper(node.right, value) + if (_val < node._val) + node.left = insertHelper(node.left, _val) + else if (_val > node._val) + node.right = insertHelper(node.right, _val) else return node // 重复节点不插入,直接返回 updateHeight(node) // 更新节点高度 @@ -2595,18 +2595,18 @@ Similarly, based on the method of removing nodes in binary search trees, rotatio ```kotlin title="avl_tree.kt" /* 删除节点 */ - fun remove(value: Int) { - root = removeHelper(root, value) + fun remove(_val: Int) { + root = removeHelper(root, _val) } /* 递归删除节点(辅助方法) */ - fun removeHelper(n: TreeNode?, value: Int): TreeNode? { + fun removeHelper(n: TreeNode?, _val: Int): TreeNode? { var node = n ?: return null /* 1. 查找节点并删除 */ - if (value < node.value) - node.left = removeHelper(node.left, value) - else if (value > node.value) - node.right = removeHelper(node.right, value) + if (_val < node._val) + node.left = removeHelper(node.left, _val) + else if (_val > node._val) + node.right = removeHelper(node.right, _val) else { if (node.left == null || node.right == null) { val child = if (node.left != null) @@ -2625,8 +2625,8 @@ Similarly, based on the method of removing nodes in binary search trees, rotatio while (temp!!.left != null) { temp = temp.left } - node.right = removeHelper(node.right, temp.value) - node.value = temp.value + node.right = removeHelper(node.right, temp._val) + node._val = temp._val } } updateHeight(node) // 更新节点高度 diff --git a/en/docs/chapter_tree/binary_search_tree.md b/en/docs/chapter_tree/binary_search_tree.md index 11bb5d104..9739a24d4 100755 --- a/en/docs/chapter_tree/binary_search_tree.md +++ b/en/docs/chapter_tree/binary_search_tree.md @@ -299,10 +299,10 @@ The search operation in a binary search tree works on the same principle as the // 循环查找,越过叶节点后跳出 while (cur != null) { // 目标节点在 cur 的右子树中 - cur = if (cur.value < num) + cur = if (cur._val < num) cur.right // 目标节点在 cur 的左子树中 - else if (cur.value > num) + else if (cur._val > num) cur.left // 找到目标节点,跳出循环 else @@ -751,11 +751,11 @@ In the code implementation, note the following two points. // 循环查找,越过叶节点后跳出 while (cur != null) { // 找到重复节点,直接返回 - if (cur.value == num) + if (cur._val == num) return pre = cur // 插入位置在 cur 的右子树中 - cur = if (cur.value < num) + cur = if (cur._val < num) cur.right // 插入位置在 cur 的左子树中 else @@ -763,7 +763,7 @@ In the code implementation, note the following two points. } // 插入节点 val node = TreeNode(num) - if (pre?.value!! < num) + if (pre?._val!! < num) pre.right = node else pre.left = node @@ -1497,11 +1497,11 @@ The operation of removing a node also uses $O(\log n)$ time, where finding the n // 循环查找,越过叶节点后跳出 while (cur != null) { // 找到待删除节点,跳出循环 - if (cur.value == num) + if (cur._val == num) break pre = cur // 待删除节点在 cur 的右子树中 - cur = if (cur.value < num) + cur = if (cur._val < num) cur.right // 待删除节点在 cur 的左子树中 else @@ -1535,9 +1535,9 @@ The operation of removing a node also uses $O(\log n)$ time, where finding the n tmp = tmp.left } // 递归删除节点 tmp - remove(tmp.value) + remove(tmp._val) // 用 tmp 覆盖 cur - cur.value = tmp.value + cur._val = tmp._val } } ``` diff --git a/en/docs/chapter_tree/binary_tree_traversal.md b/en/docs/chapter_tree/binary_tree_traversal.md index d08e46673..adf6ce22f 100755 --- a/en/docs/chapter_tree/binary_tree_traversal.md +++ b/en/docs/chapter_tree/binary_tree_traversal.md @@ -305,7 +305,7 @@ Breadth-first traversal is usually implemented with the help of a "queue". The q val list = mutableListOf() while (queue.isNotEmpty()) { val node = queue.poll() // 队列出队 - list.add(node?.value!!) // 保存节点值 + list.add(node?._val!!) // 保存节点值 if (node.left != null) queue.offer(node.left) // 左子节点入队 if (node.right != null) @@ -764,7 +764,7 @@ Depth-first search is usually implemented based on recursion: fun preOrder(root: TreeNode?) { if (root == null) return // 访问优先级:根节点 -> 左子树 -> 右子树 - list.add(root.value) + list.add(root._val) preOrder(root.left) preOrder(root.right) } @@ -774,7 +774,7 @@ Depth-first search is usually implemented based on recursion: if (root == null) return // 访问优先级:左子树 -> 根节点 -> 右子树 inOrder(root.left) - list.add(root.value) + list.add(root._val) inOrder(root.right) } @@ -784,7 +784,7 @@ Depth-first search is usually implemented based on recursion: // 访问优先级:左子树 -> 右子树 -> 根节点 postOrder(root.left) postOrder(root.right) - list.add(root.value) + list.add(root._val) } ``` diff --git a/zh-Hant/docs/chapter_array_and_linkedlist/array.md b/zh-Hant/docs/chapter_array_and_linkedlist/array.md index 5147d4729..a0cb4a560 100755 --- a/zh-Hant/docs/chapter_array_and_linkedlist/array.md +++ b/zh-Hant/docs/chapter_array_and_linkedlist/array.md @@ -137,8 +137,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   訪問元素 @@ -336,8 +336,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 3.   插入元素 @@ -547,8 +547,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 4.   刪除元素 @@ -709,8 +709,8 @@ comments: true ### 刪除索引 index 處的元素 ### def remove(nums, index) # 把索引 index 之後的所有元素向前移動一位 - for i in index...nums.length - nums[i] = nums[i + 1] || 0 + for i in index...(nums.length - 1) + nums[i] = nums[i + 1] end end ``` @@ -730,8 +730,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 總的來看,陣列的插入與刪除操作有以下缺點。 @@ -949,7 +949,7 @@ comments: true count += nums[i] } // 直接走訪陣列元素 - for (j: Int in nums) { + for (j in nums) { count += j } } @@ -995,8 +995,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 6.   查詢元素 @@ -1155,7 +1155,8 @@ comments: true /* 在陣列中查詢指定元素 */ fun find(nums: IntArray, target: Int): Int { for (i in nums.indices) { - if (nums[i] == target) return i + if (nums[i] == target) + return i } return -1 } @@ -1188,8 +1189,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 7.   擴容陣列 @@ -1434,8 +1435,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 4.1.2   陣列的優點與侷限性 diff --git a/zh-Hant/docs/chapter_array_and_linkedlist/linked_list.md b/zh-Hant/docs/chapter_array_and_linkedlist/linked_list.md index aae4bb749..cd08c4005 100755 --- a/zh-Hant/docs/chapter_array_and_linkedlist/linked_list.md +++ b/zh-Hant/docs/chapter_array_and_linkedlist/linked_list.md @@ -458,8 +458,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 陣列整體是一個變數,比如陣列 `nums` 包含元素 `nums[0]` 和 `nums[1]` 等,而鏈結串列是由多個獨立的節點物件組成的。**我們通常將頭節點當作鏈結串列的代稱**,比如以上程式碼中的鏈結串列可記作鏈結串列 `n0` 。 @@ -597,7 +597,7 @@ comments: true === "Kotlin" ```kotlin title="linked_list.kt" - /* 在鏈結串列的節點 n0 之後插入節點p */ + /* 在鏈結串列的節點 n0 之後插入節點 P */ fun insert(n0: ListNode?, p: ListNode?) { val n1 = n0?.next p?.next = n1 @@ -630,8 +630,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 3.   刪除節點 @@ -811,9 +811,11 @@ comments: true ```kotlin title="linked_list.kt" /* 刪除鏈結串列的節點 n0 之後的首個節點 */ fun remove(n0: ListNode?) { - val p = n0?.next + if (n0?.next == null) + return + val p = n0.next val n1 = p?.next - n0?.next = n1 + n0.next = n1 } ``` @@ -846,8 +848,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 4.   訪問節點 @@ -1018,7 +1020,9 @@ comments: true fun access(head: ListNode?, index: Int): ListNode? { var h = head for (i in 0.. - +
+ ### 5.   查詢節點 @@ -1249,7 +1253,8 @@ comments: true var index = 0 var h = head while (h != null) { - if (h.value == target) return index + if (h._val == target) + return index h = h.next index++ } @@ -1291,8 +1296,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 4.2.2   陣列 vs. 鏈結串列 diff --git a/zh-Hant/docs/chapter_array_and_linkedlist/list.md b/zh-Hant/docs/chapter_array_and_linkedlist/list.md index 4bdaa41dc..44d5dfdcd 100755 --- a/zh-Hant/docs/chapter_array_and_linkedlist/list.md +++ b/zh-Hant/docs/chapter_array_and_linkedlist/list.md @@ -162,8 +162,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   訪問元素 @@ -304,8 +304,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 3.   插入與刪除元素 @@ -579,8 +579,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 4.   走訪串列 @@ -798,8 +798,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 5.   拼接串列 @@ -920,8 +920,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 6.   排序串列 @@ -1026,8 +1026,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 4.3.2   串列實現 @@ -2181,9 +2181,9 @@ comments: true /* 串列類別 */ class MyList { private var arr: IntArray = intArrayOf() // 陣列(儲存串列元素) - private var capacity = 10 // 串列容量 - private var size = 0 // 串列長度(當前元素數量) - private var extendRatio = 2 // 每次串列擴容的倍數 + private var capacity: Int = 10 // 串列容量 + private var size: Int = 0 // 串列長度(當前元素數量) + private var extendRatio: Int = 2 // 每次串列擴容的倍數 /* 建構子 */ init { @@ -2204,7 +2204,7 @@ comments: true fun get(index: Int): Int { // 索引如果越界,則丟擲異常,下同 if (index < 0 || index >= size) - throw IndexOutOfBoundsException() + throw IndexOutOfBoundsException("索引越界") return arr[index] } @@ -2244,7 +2244,7 @@ comments: true fun remove(index: Int): Int { if (index < 0 || index >= size) throw IndexOutOfBoundsException("索引越界") - val num: Int = arr[index] + val num = arr[index] // 將將索引 index 之後的元素都向前移動一位 for (j in index.. - +
+ diff --git a/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md b/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md index 5fa8b4850..69e4f5b8b 100644 --- a/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md +++ b/zh-Hant/docs/chapter_backtracking/backtracking_algorithm.md @@ -208,7 +208,7 @@ comments: true if (root == null) { return } - if (root.value == 7) { + if (root._val == 7) { // 記錄解 res!!.add(root) } @@ -231,8 +231,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ![在前序走訪中搜索節點](backtracking_algorithm.assets/preorder_find_nodes.png){ class="animation-figure" } @@ -508,9 +508,9 @@ comments: true } // 嘗試 path!!.add(root) - if (root.value == 7) { + if (root._val == 7) { // 記錄解 - res!!.add(ArrayList(path!!)) + res!!.add(path!!.toMutableList()) } preOrder(root.left) preOrder(root.right) @@ -533,8 +533,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 在每次“嘗試”中,我們透過將當前節點新增進 `path` 來記錄路徑;而在“回退”前,我們需要將該節點從 `path` 中彈出,**以恢復本次嘗試之前的狀態**。 @@ -847,14 +847,14 @@ comments: true /* 前序走訪:例題三 */ fun preOrder(root: TreeNode?) { // 剪枝 - if (root == null || root.value == 3) { + if (root == null || root._val == 3) { return } // 嘗試 path!!.add(root) - if (root.value == 7) { + if (root._val == 7) { // 記錄解 - res!!.add(ArrayList(path!!)) + res!!.add(path!!.toMutableList()) } preOrder(root.left) preOrder(root.right) @@ -877,8 +877,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ “剪枝”是一個非常形象的名詞。如圖 13-3 所示,在搜尋過程中,**我們“剪掉”了不滿足約束條件的搜尋分支**,避免許多無意義的嘗試,從而提高了搜尋效率。 @@ -1790,18 +1790,18 @@ comments: true ```kotlin title="preorder_traversal_iii_template.kt" /* 判斷當前狀態是否為解 */ - fun isSolution(state: List): Boolean { - return state.isNotEmpty() && state[state.size - 1]?.value == 7 + fun isSolution(state: MutableList): Boolean { + return state.isNotEmpty() && state[state.size - 1]?._val == 7 } /* 記錄解 */ - fun recordSolution(state: MutableList?, res: MutableList?>) { - res.add(state?.let { ArrayList(it) }) + fun recordSolution(state: MutableList?, res: MutableList?>) { + res.add(state!!.toMutableList()) } /* 判斷在當前狀態下,該選擇是否合法 */ - fun isValid(state: List?, choice: TreeNode?): Boolean { - return choice != null && choice.value != 3 + fun isValid(state: MutableList?, choice: TreeNode?): Boolean { + return choice != null && choice._val != 3 } /* 更新狀態 */ @@ -1817,8 +1817,8 @@ comments: true /* 回溯演算法:例題三 */ fun backtrack( state: MutableList, - choices: List, - res: MutableList?> + choices: MutableList, + res: MutableList?> ) { // 檢查是否為解 if (isSolution(state)) { @@ -1832,7 +1832,7 @@ comments: true // 嘗試:做出選擇,更新狀態 makeChoice(state, choice) // 進行下一輪選擇 - backtrack(state, listOf(choice!!.left, choice.right), res) + backtrack(state, mutableListOf(choice!!.left, choice.right), res) // 回退:撤銷選擇,恢復到之前的狀態 undoChoice(state, choice) } @@ -1874,8 +1874,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 根據題意,我們在找到值為 $7$ 的節點後應該繼續搜尋,**因此需要將記錄解之後的 `return` 語句刪除**。圖 13-4 對比了保留或刪除 `return` 語句的搜尋過程。 diff --git a/zh-Hant/docs/chapter_backtracking/n_queens_problem.md b/zh-Hant/docs/chapter_backtracking/n_queens_problem.md index 4ae1cba5b..52112597e 100644 --- a/zh-Hant/docs/chapter_backtracking/n_queens_problem.md +++ b/zh-Hant/docs/chapter_backtracking/n_queens_problem.md @@ -646,17 +646,17 @@ comments: true fun backtrack( row: Int, n: Int, - state: List>, - res: MutableList>?>, + state: MutableList>, + res: MutableList>?>, cols: BooleanArray, diags1: BooleanArray, diags2: BooleanArray ) { // 當放置完所有行時,記錄解 if (row == n) { - val copyState: MutableList> = ArrayList() + val copyState = mutableListOf>() for (sRow in state) { - copyState.add(ArrayList(sRow)) + copyState.add(sRow.toMutableList()) } res.add(copyState) return @@ -685,11 +685,11 @@ comments: true } /* 求解 n 皇后 */ - fun nQueens(n: Int): List>?> { + fun nQueens(n: Int): MutableList>?> { // 初始化 n*n 大小的棋盤,其中 'Q' 代表皇后,'#' 代表空位 - val state: MutableList> = ArrayList() + val state = mutableListOf>() for (i in 0.. = ArrayList() + val row = mutableListOf() for (j in 0..>?> = ArrayList() + val res = mutableListOf>?>() backtrack(0, n, state, res, cols, diags1, diags2) @@ -724,8 +724,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 逐行放置 $n$ 次,考慮列約束,則從第一行到最後一行分別有 $n$、$n-1$、$\dots$、$2$、$1$ 個選擇,使用 $O(n!)$ 時間。當記錄解時,需要複製矩陣 `state` 並新增進 `res` ,複製操作使用 $O(n^2)$ 時間。因此,**總體時間複雜度為 $O(n! \cdot n^2)$** 。實際上,根據對角線約束的剪枝也能夠大幅縮小搜尋空間,因而搜尋效率往往優於以上時間複雜度。 diff --git a/zh-Hant/docs/chapter_backtracking/permutations_problem.md b/zh-Hant/docs/chapter_backtracking/permutations_problem.md index d3a835003..b76070f24 100644 --- a/zh-Hant/docs/chapter_backtracking/permutations_problem.md +++ b/zh-Hant/docs/chapter_backtracking/permutations_problem.md @@ -471,11 +471,11 @@ comments: true state: MutableList, choices: IntArray, selected: BooleanArray, - res: MutableList?> + res: MutableList?> ) { // 當狀態長度等於元素數量時,記錄解 if (state.size == choices.size) { - res.add(ArrayList(state)) + res.add(state.toMutableList()) return } // 走訪所有選擇 @@ -496,9 +496,9 @@ comments: true } /* 全排列 I */ - fun permutationsI(nums: IntArray): List?> { - val res: MutableList?> = ArrayList() - backtrack(ArrayList(), nums, BooleanArray(nums.size), res) + fun permutationsI(nums: IntArray): MutableList?> { + val res = mutableListOf?>() + backtrack(mutableListOf(), nums, BooleanArray(nums.size), res) return res } ``` @@ -521,8 +521,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 13.2.2   考慮相等元素的情況 @@ -999,11 +999,11 @@ comments: true ) { // 當狀態長度等於元素數量時,記錄解 if (state.size == choices.size) { - res.add(ArrayList(state)) + res.add(state.toMutableList()) return } // 走訪所有選擇 - val duplicated: MutableSet = HashSet() + val duplicated = HashSet() for (i in choices.indices) { val choice = choices[i] // 剪枝:不允許重複選擇元素 且 不允許重複選擇相等元素 @@ -1023,8 +1023,8 @@ comments: true /* 全排列 II */ fun permutationsII(nums: IntArray): MutableList?> { - val res: MutableList?> = ArrayList() - backtrack(ArrayList(), nums, BooleanArray(nums.size), res) + val res = mutableListOf?>() + backtrack(mutableListOf(), nums, BooleanArray(nums.size), res) return res } ``` @@ -1047,8 +1047,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 假設元素兩兩之間互不相同,則 $n$ 個元素共有 $n!$ 種排列(階乘);在記錄結果時,需要複製長度為 $n$ 的串列,使用 $O(n)$ 時間。**因此時間複雜度為 $O(n!n)$** 。 diff --git a/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md b/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md index 896c67041..2aa5218d8 100644 --- a/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md +++ b/zh-Hant/docs/chapter_backtracking/subset_sum_problem.md @@ -435,11 +435,11 @@ comments: true target: Int, total: Int, choices: IntArray, - res: MutableList?> + res: MutableList?> ) { // 子集和等於 target 時,記錄解 if (total == target) { - res.add(ArrayList(state)) + res.add(state.toMutableList()) return } // 走訪所有選擇 @@ -458,10 +458,10 @@ comments: true } /* 求解子集和 I(包含重複子集) */ - fun subsetSumINaive(nums: IntArray, target: Int): List?> { - val state: MutableList = ArrayList() // 狀態(子集) + fun subsetSumINaive(nums: IntArray, target: Int): MutableList?> { + val state = mutableListOf() // 狀態(子集) val total = 0 // 子集和 - val res: MutableList?> = ArrayList() // 結果串列(子集串列) + val res = mutableListOf?>() // 結果串列(子集串列) backtrack(state, target, total, nums, res) return res } @@ -485,8 +485,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 向以上程式碼輸入陣列 $[3, 4, 5]$ 和目標元素 $9$ ,輸出結果為 $[3, 3, 3], [4, 5], [5, 4]$ 。**雖然成功找出了所有和為 $9$ 的子集,但其中存在重複的子集 $[4, 5]$ 和 $[5, 4]$** 。 @@ -973,11 +973,11 @@ comments: true target: Int, choices: IntArray, start: Int, - res: MutableList?> + res: MutableList?> ) { // 子集和等於 target 時,記錄解 if (target == 0) { - res.add(ArrayList(state)) + res.add(state.toMutableList()) return } // 走訪所有選擇 @@ -998,11 +998,11 @@ comments: true } /* 求解子集和 I */ - fun subsetSumI(nums: IntArray, target: Int): List?> { - val state: MutableList = ArrayList() // 狀態(子集) - Arrays.sort(nums) // 對 nums 進行排序 + fun subsetSumI(nums: IntArray, target: Int): MutableList?> { + val state = mutableListOf() // 狀態(子集) + nums.sort() // 對 nums 進行排序 val start = 0 // 走訪起始點 - val res: MutableList?> = ArrayList() // 結果串列(子集串列) + val res = mutableListOf?>() // 結果串列(子集串列) backtrack(state, target, nums, start, res) return res } @@ -1026,8 +1026,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 圖 13-12 所示為將陣列 $[3, 4, 5]$ 和目標元素 $9$ 輸入以上程式碼後的整體回溯過程。 @@ -1555,11 +1555,11 @@ comments: true target: Int, choices: IntArray, start: Int, - res: MutableList?> + res: MutableList?> ) { // 子集和等於 target 時,記錄解 if (target == 0) { - res.add(ArrayList(state)) + res.add(state.toMutableList()) return } // 走訪所有選擇 @@ -1585,11 +1585,11 @@ comments: true } /* 求解子集和 II */ - fun subsetSumII(nums: IntArray, target: Int): List?> { - val state: MutableList = ArrayList() // 狀態(子集) - Arrays.sort(nums) // 對 nums 進行排序 + fun subsetSumII(nums: IntArray, target: Int): MutableList?> { + val state = mutableListOf() // 狀態(子集) + nums.sort() // 對 nums 進行排序 val start = 0 // 走訪起始點 - val res: MutableList?> = ArrayList() // 結果串列(子集串列) + val res = mutableListOf?>() // 結果串列(子集串列) backtrack(state, target, nums, start, res) return res } @@ -1613,8 +1613,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 圖 13-14 展示了陣列 $[4, 4, 5]$ 和目標元素 $9$ 的回溯過程,共包含四種剪枝操作。請你將圖示與程式碼註釋相結合,理解整個搜尋過程,以及每種剪枝操作是如何工作的。 diff --git a/zh-Hant/docs/chapter_computational_complexity/iteration_and_recursion.md b/zh-Hant/docs/chapter_computational_complexity/iteration_and_recursion.md index ad21651ee..709db7c6c 100644 --- a/zh-Hant/docs/chapter_computational_complexity/iteration_and_recursion.md +++ b/zh-Hant/docs/chapter_computational_complexity/iteration_and_recursion.md @@ -214,8 +214,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 圖 2-1 是該求和函式的流程框圖。 @@ -460,8 +460,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ **`while` 迴圈比 `for` 迴圈的自由度更高**。在 `while` 迴圈中,我們可以自由地設計條件變數的初始化和更新步驟。 @@ -723,8 +723,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 總的來說,**`for` 迴圈的程式碼更加緊湊,`while` 迴圈更加靈活**,兩者都可以實現迭代結構。選擇使用哪一個應該根據特定問題的需求來決定。 @@ -978,8 +978,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 圖 2-2 是該巢狀迴圈的流程框圖。 @@ -1217,8 +1217,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 圖 2-3 展示了該函式的遞迴過程。 @@ -1444,8 +1444,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 尾遞迴的執行過程如圖 2-5 所示。對比普通遞迴和尾遞迴,兩者的求和操作的執行點是不同的。 @@ -1686,8 +1686,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 觀察以上程式碼,我們在函式內遞迴呼叫了兩個函式,**這意味著從一個呼叫產生了兩個呼叫分支**。如圖 2-6 所示,這樣不斷遞迴呼叫下去,最終將產生一棵層數為 $n$ 的遞迴樹(recursion tree)。 @@ -2055,8 +2055,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 觀察以上程式碼,當遞迴轉化為迭代後,程式碼變得更加複雜了。儘管迭代和遞迴在很多情況下可以互相轉化,但不一定值得這樣做,有以下兩點原因。 diff --git a/zh-Hant/docs/chapter_computational_complexity/space_complexity.md b/zh-Hant/docs/chapter_computational_complexity/space_complexity.md index e8782be80..6eeba1606 100755 --- a/zh-Hant/docs/chapter_computational_complexity/space_complexity.md +++ b/zh-Hant/docs/chapter_computational_complexity/space_complexity.md @@ -1231,8 +1231,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ### 2.   線性階 $O(n)$ {data-toc-label="2.   線性階"} @@ -1536,8 +1536,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 如圖 2-17 所示,此函式的遞迴深度為 $n$ ,即同時存在 $n$ 個未返回的 `linear_recur()` 函式,使用 $O(n)$ 大小的堆疊幀空間: @@ -1707,8 +1707,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ![遞迴函式產生的線性階空間複雜度](space_complexity.assets/space_complexity_recursive_linear.png){ class="animation-figure" } @@ -1915,9 +1915,9 @@ $$ /* 平方階 */ fun quadratic(n: Int) { // 矩陣佔用 O(n^2) 空間 - val numMatrix: Array?> = arrayOfNulls(n) + val numMatrix = arrayOfNulls?>(n) // 二維串列佔用 O(n^2) 空間 - val numList: MutableList> = arrayListOf() + val numList = mutableListOf>() for (i in 0..() for (j in 0.. - +
+ 如圖 2-18 所示,該函式的遞迴深度為 $n$ ,在每個遞迴函式中都初始化了一個陣列,長度分別為 $n$、$n-1$、$\dots$、$2$、$1$ ,平均長度為 $n / 2$ ,因此總體佔用 $O(n^2)$ 空間: @@ -2154,8 +2154,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ![遞迴函式產生的平方階空間複雜度](space_complexity.assets/space_complexity_recursive_quadratic.png){ class="animation-figure" } @@ -2362,8 +2362,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ![滿二元樹產生的指數階空間複雜度](space_complexity.assets/space_complexity_exponential.png){ class="animation-figure" } diff --git a/zh-Hant/docs/chapter_computational_complexity/time_complexity.md b/zh-Hant/docs/chapter_computational_complexity/time_complexity.md index 087bc9752..c749fe5f3 100755 --- a/zh-Hant/docs/chapter_computational_complexity/time_complexity.md +++ b/zh-Hant/docs/chapter_computational_complexity/time_complexity.md @@ -195,11 +195,11 @@ comments: true ```ruby title="" # 在某執行平臺下 def algorithm(n) - a = 2 # 1 ns + a = 2 # 1 ns a = a + 1 # 1 ns a = a * 2 # 10 ns # 迴圈 n 次 - (n...0).each do # 1 ns + (0...n).each do # 1 ns puts 0 # 5 ns end end @@ -520,7 +520,7 @@ $$ // 演算法 C 的時間複雜度:常數階 fn algorithm_C(n: i32) void { _ = n; - for (0..1000000) |_| { + for (0..1000000) |_| { std.debug.print("{}\n", .{0}); } } @@ -696,7 +696,7 @@ $$ for (int i = 0; i < n; i++) { // +1(每輪都執行 i ++) printf("%d", 0); // +1 } - } + } ``` === "Kotlin" @@ -1029,13 +1029,13 @@ $T(n)$ 是一次函式,說明其執行時間的增長趨勢是線性的,因 // +n(技巧 2) for(0..(5 * n + 1)) |_| { - std.debug.print("{}\n", .{0}); + std.debug.print("{}\n", .{0}); } // +n*n(技巧 3) for(0..(2 * n)) |_| { for(0..(n + 1)) |_| { - std.debug.print("{}\n", .{0}); + std.debug.print("{}\n", .{0}); } } } @@ -1245,7 +1245,7 @@ $$ /* 常數階 */ fun constant(n: Int): Int { var count = 0 - val size = 10_0000 + val size = 100000 for (i in 0.. - +
+ ### 2.   線性階 $O(n)$ {data-toc-label="2.   線性階"} @@ -1465,8 +1465,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 走訪陣列和走訪鏈結串列等操作的時間複雜度均為 $O(n)$ ,其中 $n$ 為陣列或鏈結串列的長度: @@ -1668,8 +1668,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 值得注意的是,**輸入資料大小 $n$ 需根據輸入資料的型別來具體確定**。比如在第一個示例中,變數 $n$ 為輸入資料大小;在第二個示例中,陣列長度 $n$ 為資料大小。 @@ -1904,8 +1904,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 圖 2-10 對比了常數階、線性階和平方階三種時間複雜度。 @@ -2168,7 +2168,7 @@ $$ ```kotlin title="time_complexity.kt" /* 平方階(泡沫排序) */ fun bubbleSort(nums: IntArray): Int { - var count = 0 + var count = 0 // 計數器 // 外迴圈:未排序區間為 [0, i] for (i in nums.size - 1 downTo 1) { // 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端 @@ -2236,8 +2236,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ### 4.   指數階 $O(2^n)$ {data-toc-label="4.   指數階"} @@ -2506,8 +2506,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ![指數階的時間複雜度](time_complexity.assets/time_complexity_exponential.png){ class="animation-figure" } @@ -2668,8 +2668,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 指數階增長非常迅速,在窮舉法(暴力搜尋、回溯等)中比較常見。對於資料規模較大的問題,指數階是不可接受的,通常需要使用動態規劃或貪婪演算法等來解決。 @@ -2881,8 +2881,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ![對數階的時間複雜度](time_complexity.assets/time_complexity_logarithmic.png){ class="animation-figure" } @@ -3042,8 +3042,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 對數階常出現於基於分治策略的演算法中,體現了“一分為多”和“化繁為簡”的演算法思想。它增長緩慢,是僅次於常數階的理想的時間複雜度。 @@ -3231,7 +3231,7 @@ $$ if (n <= 1) return 1 var count = linearLogRecur(n / 2) + linearLogRecur(n / 2) - for (i in 0.. - +
+ 圖 2-13 展示了線性對數階的生成方式。二元樹的每一層的操作總數都為 $n$ ,樹共有 $\log_2 n + 1$ 層,因此時間複雜度為 $O(n \log n)$ 。 @@ -3511,8 +3511,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ![階乘階的時間複雜度](time_complexity.assets/time_complexity_factorial.png){ class="animation-figure" } @@ -3859,10 +3859,9 @@ $$ for (i in 0.. int[] val res = arrayOfNulls(n) for (i in 0.. - +
+ 值得說明的是,我們在實際中很少使用最佳時間複雜度,因為通常只有在很小機率下才能達到,可能會帶來一定的誤導性。**而最差時間複雜度更為實用,因為它給出了一個效率安全值**,讓我們可以放心地使用演算法。 diff --git a/zh-Hant/docs/chapter_data_structure/basic_data_types.md b/zh-Hant/docs/chapter_data_structure/basic_data_types.md index 70e34f432..e91202193 100644 --- a/zh-Hant/docs/chapter_data_structure/basic_data_types.md +++ b/zh-Hant/docs/chapter_data_structure/basic_data_types.md @@ -174,16 +174,17 @@ comments: true === "Ruby" ```ruby title="" - + # Ruby 的串列可以自由儲存各種基本資料型別和物件引用 + data = [0, 0.0, 'a', false, ListNode(0)] ``` === "Zig" ```zig title="" - + ``` ??? pythontutor "視覺化執行" -
- +
+ diff --git a/zh-Hant/docs/chapter_data_structure/number_encoding.md b/zh-Hant/docs/chapter_data_structure/number_encoding.md index ee8e1945c..813b373a4 100644 --- a/zh-Hant/docs/chapter_data_structure/number_encoding.md +++ b/zh-Hant/docs/chapter_data_structure/number_encoding.md @@ -143,7 +143,7 @@ $$ **儘管浮點數 `float` 擴展了取值範圍,但其副作用是犧牲了精度**。整數型別 `int` 將全部 32 位元用於表示數字,數字是均勻分佈的;而由於指數位的存在,浮點數 `float` 的數值越大,相鄰兩個數字之間的差值就會趨向越大。 -如表 3-2 所示,指數位 $E = 0$ 和 $E = 255$ 具有特殊含義,**用於表示零、無窮大、$\mathrm{NaN}$ 等**。 +如表 3-2 所示,指數位 $\mathrm{E} = 0$ 和 $\mathrm{E} = 255$ 具有特殊含義,**用於表示零、無窮大、$\mathrm{NaN}$ 等**。

表 3-2   指數位含義

diff --git a/zh-Hant/docs/chapter_data_structure/summary.md b/zh-Hant/docs/chapter_data_structure/summary.md index 98f674b9d..f0f201bbc 100644 --- a/zh-Hant/docs/chapter_data_structure/summary.md +++ b/zh-Hant/docs/chapter_data_structure/summary.md @@ -36,3 +36,35 @@ comments: true **Q**:在構建堆疊(佇列)的時候,未指定它的大小,為什麼它們是“靜態資料結構”呢? 在高階程式語言中,我們無須人工指定堆疊(佇列)的初始容量,這個工作由類別內部自動完成。例如,Java 的 `ArrayList` 的初始容量通常為 10。另外,擴容操作也是自動實現的。詳見後續的“串列”章節。 + +**Q**:原碼轉二補數的方法是“先取反後加 1”,那麼二補數轉原碼應該是逆運算“先減 1 後取反”,而二補數轉原碼也一樣可以透過“先取反後加 1”得到,這是為什麼呢? + +**A**:這是因為原碼和二補數的相互轉換實際上是計算“補數”的過程。我們先給出補數的定義:假設 $a + b = c$ ,那麼我們稱 $a$ 是 $b$ 到 $c$ 的補數,反之也稱 $b$ 是 $a$ 到 $c$ 的補數。 + +給定一個 $n = 4$ 位長度的二進位制數 $0010$ ,如果將這個數字看作原碼(不考慮符號位),那麼它的二補數需透過“先取反後加 1”得到: + +$$ +0010 \rightarrow 1101 \rightarrow 1110 +$$ + +我們會發現,原碼和二補數的和是 $0010 + 1110 = 10000$ ,也就是說,二補數 $1110$ 是原碼 $0010$ 到 $10000$ 的“補數”。**這意味著上述“先取反後加 1”實際上是計算到 $10000$ 的補數的過程**。 + +那麼,二補數 $1110$ 到 $10000$ 的“補數”是多少呢?我們依然可以用“先取反後加 1”得到它: + +$$ +1110 \rightarrow 0001 \rightarrow 0010 +$$ + +換句話說,原碼和二補數互為對方到 $10000$ 的“補數”,因此“原碼轉二補數”和“二補數轉原碼”可以用相同的操作(先取反後加 1 )實現。 + +當然,我們也可以用逆運算來求二補數 $1110$ 的原碼,即“先減 1 後取反”: + +$$ +1110 \rightarrow 1101 \rightarrow 0010 +$$ + +總結來看,“先取反後加 1”和“先減 1 後取反”這兩種運算都是在計算到 $10000$ 的補數,它們是等價的。 + +本質上看,“取反”操作實際上是求到 $1111$ 的補數(因為恆有 `原碼 + 一補數 = 1111`);而在一補數基礎上再加 1 得到的二補數,就是到 $10000$ 的補數。 + +上述 $n = 4$ 為例,其可推廣至任意位數的二進位制數。 diff --git a/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md b/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md index f7425d84f..433315ef8 100644 --- a/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md +++ b/zh-Hant/docs/chapter_divide_and_conquer/binary_search_recur.md @@ -437,5 +437,5 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ diff --git a/zh-Hant/docs/chapter_divide_and_conquer/build_binary_tree_problem.md b/zh-Hant/docs/chapter_divide_and_conquer/build_binary_tree_problem.md index a52e4d6b3..7276dde74 100644 --- a/zh-Hant/docs/chapter_divide_and_conquer/build_binary_tree_problem.md +++ b/zh-Hant/docs/chapter_divide_and_conquer/build_binary_tree_problem.md @@ -449,7 +449,13 @@ comments: true ```kotlin title="build_tree.kt" /* 構建二元樹:分治 */ - fun dfs(preorder: IntArray, inorderMap: Map, i: Int, l: Int, r: Int): TreeNode? { + fun dfs( + preorder: IntArray, + inorderMap: Map, + i: Int, + l: Int, + r: Int + ): TreeNode? { // 子樹區間為空時終止 if (r - l < 0) return null // 初始化根節點 @@ -467,7 +473,7 @@ comments: true /* 構建二元樹 */ fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? { // 初始化雜湊表,儲存 inorder 元素到索引的對映 - val inorderMap: MutableMap = HashMap() + val inorderMap = HashMap() for (i in inorder.indices) { inorderMap[inorder[i]] = i } @@ -494,8 +500,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 圖 12-8 展示了構建二元樹的遞迴過程,各個節點是在向下“遞”的過程中建立的,而各條邊(引用)是在向上“迴”的過程中建立的。 diff --git a/zh-Hant/docs/chapter_divide_and_conquer/hanota_problem.md b/zh-Hant/docs/chapter_divide_and_conquer/hanota_problem.md index ae7b498c6..70d530c0a 100644 --- a/zh-Hant/docs/chapter_divide_and_conquer/hanota_problem.md +++ b/zh-Hant/docs/chapter_divide_and_conquer/hanota_problem.md @@ -479,7 +479,7 @@ comments: true /* 移動一個圓盤 */ fun move(src: MutableList, tar: MutableList) { // 從 src 頂部拿出一個圓盤 - val pan: Int = src.removeAt(src.size - 1) + val pan = src.removeAt(src.size - 1) // 將圓盤放入 tar 頂部 tar.add(pan) } @@ -529,8 +529,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 如圖 12-15 所示,河內塔問題形成一棵高度為 $n$ 的遞迴樹,每個節點代表一個子問題,對應一個開啟的 `dfs()` 函式,**因此時間複雜度為 $O(2^n)$ ,空間複雜度為 $O(n)$** 。 diff --git a/zh-Hant/docs/chapter_dynamic_programming/dp_problem_features.md b/zh-Hant/docs/chapter_dynamic_programming/dp_problem_features.md index 2a0e15ec8..b1a9a3173 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/dp_problem_features.md +++ b/zh-Hant/docs/chapter_dynamic_programming/dp_problem_features.md @@ -295,7 +295,7 @@ $$ dp[2] = cost[2] // 狀態轉移:從較小子問題逐步求解較大子問題 for (i in 3..n) { - dp[i] = (min(dp[i - 1].toDouble(), dp[i - 2].toDouble()) + cost[i]).toInt() + dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i] } return dp[n] } @@ -331,8 +331,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 圖 14-7 展示了以上程式碼的動態規劃過程。 @@ -559,7 +559,7 @@ $$ var b = cost[2] for (i in 3..n) { val tmp = b - b = (min(a.toDouble(), tmp.toDouble()) + cost[i]).toInt() + b = min(a, tmp) + cost[i] a = tmp } return b @@ -595,8 +595,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ## 14.2.2   無後效性 @@ -964,8 +964,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 在上面的案例中,由於僅需多考慮前面一個狀態,因此我們仍然可以透過擴展狀態定義,使得問題重新滿足無後效性。然而,某些問題具有非常嚴重的“有後效性”。 diff --git a/zh-Hant/docs/chapter_dynamic_programming/dp_solution_pipeline.md b/zh-Hant/docs/chapter_dynamic_programming/dp_solution_pipeline.md index d85cc7475..82b1fa3c8 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/dp_solution_pipeline.md +++ b/zh-Hant/docs/chapter_dynamic_programming/dp_solution_pipeline.md @@ -349,11 +349,7 @@ $$ ```kotlin title="min_path_sum.kt" /* 最小路徑和:暴力搜尋 */ - fun minPathSumDFS( - grid: Array>, - i: Int, - j: Int - ): Int { + fun minPathSumDFS(grid: Array, i: Int, j: Int): Int { // 若為左上角單元格,則終止搜尋 if (i == 0 && j == 0) { return grid[0][0] @@ -366,7 +362,7 @@ $$ val up = minPathSumDFS(grid, i - 1, j) val left = minPathSumDFS(grid, i, j - 1) // 返回從左上角到 (i, j) 的最小路徑代價 - return (min(left.toDouble(), up.toDouble()) + grid[i][j]).toInt() + return min(left, up) + grid[i][j] } ``` @@ -399,8 +395,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 圖 14-14 給出了以 $dp[2, 1]$ 為根節點的遞迴樹,其中包含一些重疊子問題,其數量會隨著網格 `grid` 的尺寸變大而急劇增多。 @@ -711,8 +707,8 @@ $$ ```kotlin title="min_path_sum.kt" /* 最小路徑和:記憶化搜尋 */ fun minPathSumDFSMem( - grid: Array>, - mem: Array>, + grid: Array, + mem: Array, i: Int, j: Int ): Int { @@ -732,7 +728,7 @@ $$ val up = minPathSumDFSMem(grid, mem, i - 1, j) val left = minPathSumDFSMem(grid, mem, i, j - 1) // 記錄並返回左上角到 (i, j) 的最小路徑代價 - mem[i][j] = (min(left.toDouble(), up.toDouble()) + grid[i][j]).toInt() + mem[i][j] = min(left, up) + grid[i][j] return mem[i][j] } ``` @@ -772,8 +768,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 如圖 14-15 所示,在引入記憶化後,所有子問題的解只需計算一次,因此時間複雜度取決於狀態總數,即網格尺寸 $O(nm)$ 。 @@ -1098,7 +1094,7 @@ $$ ```kotlin title="min_path_sum.kt" /* 最小路徑和:動態規劃 */ - fun minPathSumDP(grid: Array>): Int { + fun minPathSumDP(grid: Array): Int { val n = grid.size val m = grid[0].size // 初始化 dp 表 @@ -1115,8 +1111,7 @@ $$ // 狀態轉移:其餘行和列 for (i in 1.. - +
+ 圖 14-16 展示了最小路徑和的狀態轉移過程,其走訪了整個網格,**因此時間複雜度為 $O(nm)$** 。 @@ -1500,7 +1495,7 @@ $$ ```kotlin title="min_path_sum.kt" /* 最小路徑和:空間最佳化後的動態規劃 */ - fun minPathSumDPComp(grid: Array>): Int { + fun minPathSumDPComp(grid: Array): Int { val n = grid.size val m = grid[0].size // 初始化 dp 表 @@ -1516,7 +1511,7 @@ $$ dp[0] = dp[0] + grid[i][0] // 狀態轉移:其餘列 for (j in 1.. - +
+ diff --git a/zh-Hant/docs/chapter_dynamic_programming/edit_distance_problem.md b/zh-Hant/docs/chapter_dynamic_programming/edit_distance_problem.md index 0c0298850..21353b30b 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/edit_distance_problem.md +++ b/zh-Hant/docs/chapter_dynamic_programming/edit_distance_problem.md @@ -443,11 +443,7 @@ $$ dp[i][j] = dp[i - 1][j - 1] } else { // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1 - dp[i][j] = - (min( - min(dp[i][j - 1].toDouble(), dp[i - 1][j].toDouble()), - dp[i - 1][j - 1].toDouble() - ) + 1).toInt() + dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1 } } } @@ -494,8 +490,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 如圖 14-30 所示,編輯距離問題的狀態轉移過程與背包問題非常類似,都可以看作填寫一個二維網格的過程。 @@ -941,7 +937,7 @@ $$ dp[j] = leftup } else { // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1 - dp[j] = (min(min(dp[j - 1].toDouble(), dp[j].toDouble()), leftup.toDouble()) + 1).toInt() + dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1 } leftup = temp // 更新為下一輪的 dp[i-1, j-1] } @@ -992,5 +988,5 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ diff --git a/zh-Hant/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md b/zh-Hant/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md index 1b2c87484..235009e5a 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md +++ b/zh-Hant/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md @@ -361,13 +361,14 @@ comments: true ```kotlin title="climbing_stairs_backtrack.kt" /* 回溯 */ fun backtrack( - choices: List, + choices: MutableList, state: Int, n: Int, res: MutableList ) { // 當爬到第 n 階時,方案數量加 1 - if (state == n) res[0] = res[0] + 1 + if (state == n) + res[0] = res[0] + 1 // 走訪所有選擇 for (choice in choices) { // 剪枝:不允許越過第 n 階 @@ -382,7 +383,7 @@ comments: true fun climbingStairsBacktrack(n: Int): Int { val choices = mutableListOf(1, 2) // 可選擇向上爬 1 階或 2 階 val state = 0 // 從第 0 階開始爬 - val res = ArrayList() + val res = mutableListOf() res.add(0) // 使用 res[0] 記錄方案數量 backtrack(choices, state, n, res) return res[0] @@ -432,8 +433,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 14.1.1   方法一:暴力搜尋 @@ -718,8 +719,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 圖 14-3 展示了暴力搜尋形成的遞迴樹。對於問題 $dp[n]$ ,其遞迴樹的深度為 $n$ ,時間複雜度為 $O(2^n)$ 。指數階屬於爆炸式增長,如果我們輸入一個比較大的 $n$ ,則會陷入漫長的等待之中。 @@ -1054,7 +1055,7 @@ $$ fun climbingStairsDFSMem(n: Int): Int { // mem[i] 記錄爬到第 i 階的方案總數,-1 代表無記錄 val mem = IntArray(n + 1) - Arrays.fill(mem, -1) + mem.fill(-1) return dfs(n, mem) } ``` @@ -1097,8 +1098,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 觀察圖 14-4 ,**經過記憶化處理後,所有重疊子問題都只需計算一次,時間複雜度最佳化至 $O(n)$** ,這是一個巨大的飛躍。 @@ -1383,8 +1384,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 圖 14-5 模擬了以上程式碼的執行過程。 @@ -1596,9 +1597,7 @@ $$ var a = 1 var b = 2 for (i in 3..n) { - val tmp = b - b += a - a = tmp + b += a.also { a = b } } return b } @@ -1631,8 +1630,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 觀察以上程式碼,由於省去了陣列 `dp` 佔用的空間,因此空間複雜度從 $O(n)$ 降至 $O(1)$ 。 diff --git a/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md b/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md index 6ff7f7c2b..faf4e4626 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md +++ b/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md @@ -301,7 +301,7 @@ $$ /* 0-1 背包:暴力搜尋 */ fun knapsackDFS( wgt: IntArray, - value: IntArray, + _val: IntArray, i: Int, c: Int ): Int { @@ -311,13 +311,13 @@ $$ } // 若超過背包容量,則只能選擇不放入背包 if (wgt[i - 1] > c) { - return knapsackDFS(wgt, value, i - 1, c) + return knapsackDFS(wgt, _val, i - 1, c) } // 計算不放入和放入物品 i 的最大價值 - val no = knapsackDFS(wgt, value, i - 1, c) - val yes = knapsackDFS(wgt, value, i - 1, c - wgt[i - 1]) + value[i - 1] + val no = knapsackDFS(wgt, _val, i - 1, c) + val yes = knapsackDFS(wgt, _val, i - 1, c - wgt[i - 1]) + _val[i - 1] // 返回兩種方案中價值更大的那一個 - return max(no.toDouble(), yes.toDouble()).toInt() + return max(no, yes) } ``` @@ -350,8 +350,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 如圖 14-18 所示,由於每個物品都會產生不選和選兩條搜尋分支,因此時間複雜度為 $O(2^n)$ 。 @@ -671,7 +671,7 @@ $$ /* 0-1 背包:記憶化搜尋 */ fun knapsackDFSMem( wgt: IntArray, - value: IntArray, + _val: IntArray, mem: Array, i: Int, c: Int @@ -686,13 +686,13 @@ $$ } // 若超過背包容量,則只能選擇不放入背包 if (wgt[i - 1] > c) { - return knapsackDFSMem(wgt, value, mem, i - 1, c) + return knapsackDFSMem(wgt, _val, mem, i - 1, c) } // 計算不放入和放入物品 i 的最大價值 - val no = knapsackDFSMem(wgt, value, mem, i - 1, c) - val yes = knapsackDFSMem(wgt, value, mem, i - 1, c - wgt[i - 1]) + value[i - 1] + val no = knapsackDFSMem(wgt, _val, mem, i - 1, c) + val yes = knapsackDFSMem(wgt, _val, mem, i - 1, c - wgt[i - 1]) + _val[i - 1] // 記錄並返回兩種方案中價值更大的那一個 - mem[i][c] = max(no.toDouble(), yes.toDouble()).toInt() + mem[i][c] = max(no, yes) return mem[i][c] } ``` @@ -731,8 +731,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 圖 14-19 展示了在記憶化搜尋中被剪掉的搜尋分支。 @@ -1038,7 +1038,7 @@ $$ /* 0-1 背包:動態規劃 */ fun knapsackDP( wgt: IntArray, - value: IntArray, + _val: IntArray, cap: Int ): Int { val n = wgt.size @@ -1052,8 +1052,7 @@ $$ dp[i][c] = dp[i - 1][c] } else { // 不選和選物品 i 這兩種方案的較大值 - dp[i][c] = max(dp[i - 1][c].toDouble(), (dp[i - 1][c - wgt[i - 1]] + value[i - 1]).toDouble()) - .toInt() + dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + _val[i - 1]) } } } @@ -1093,8 +1092,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 如圖 14-20 所示,時間複雜度和空間複雜度都由陣列 `dp` 大小決定,即 $O(n \times cap)$ 。 @@ -1432,7 +1431,7 @@ $$ /* 0-1 背包:空間最佳化後的動態規劃 */ fun knapsackDPComp( wgt: IntArray, - value: IntArray, + _val: IntArray, cap: Int ): Int { val n = wgt.size @@ -1445,7 +1444,7 @@ $$ if (wgt[i - 1] <= c) { // 不選和選物品 i 這兩種方案的較大值 dp[c] = - max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt() + max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1]) } } } @@ -1484,5 +1483,5 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ diff --git a/zh-Hant/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md b/zh-Hant/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md index 18ba4226b..fe200cdbc 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md +++ b/zh-Hant/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md @@ -327,11 +327,7 @@ $$ ```kotlin title="unbounded_knapsack.kt" /* 完全背包:動態規劃 */ - fun unboundedKnapsackDP( - wgt: IntArray, - value: IntArray, - cap: Int - ): Int { + fun unboundedKnapsackDP(wgt: IntArray, _val: IntArray, cap: Int): Int { val n = wgt.size // 初始化 dp 表 val dp = Array(n + 1) { IntArray(cap + 1) } @@ -343,8 +339,7 @@ $$ dp[i][c] = dp[i - 1][c] } else { // 不選和選物品 i 這兩種方案的較大值 - dp[i][c] = max(dp[i - 1][c].toDouble(), (dp[i][c - wgt[i - 1]] + value[i - 1]).toDouble()) - .toInt() + dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + _val[i - 1]) } } } @@ -384,8 +379,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ### 3.   空間最佳化 @@ -689,7 +684,7 @@ $$ /* 完全背包:空間最佳化後的動態規劃 */ fun unboundedKnapsackDPComp( wgt: IntArray, - value: IntArray, + _val: IntArray, cap: Int ): Int { val n = wgt.size @@ -703,8 +698,7 @@ $$ dp[c] = dp[c] } else { // 不選和選物品 i 這兩種方案的較大值 - dp[c] = - max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt() + dp[c] = max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1]) } } } @@ -744,8 +738,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ## 14.5.2   零錢兌換問題 @@ -1154,8 +1148,7 @@ $$ dp[i][a] = dp[i - 1][a] } else { // 不選和選硬幣 i 這兩種方案的較小值 - dp[i][a] = min(dp[i - 1][a].toDouble(), (dp[i][a - coins[i - 1]] + 1).toDouble()) - .toInt() + dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1) } } } @@ -1204,8 +1197,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 圖 14-25 展示了零錢兌換的動態規劃過程,和完全背包問題非常相似。 @@ -1377,7 +1370,7 @@ $$ } // 狀態轉移 for i := 1; i <= n; i++ { - // 倒序走訪 + // 正序走訪 for a := 1; a <= amt; a++ { if coins[i-1] > a { // 若超過目標金額,則不選硬幣 i @@ -1568,7 +1561,7 @@ $$ val MAX = amt + 1 // 初始化 dp 表 val dp = IntArray(amt + 1) - Arrays.fill(dp, MAX) + dp.fill(MAX) dp[0] = 0 // 狀態轉移 for (i in 1..n) { @@ -1578,7 +1571,7 @@ $$ dp[a] = dp[a] } else { // 不選和選硬幣 i 這兩種方案的較小值 - dp[a] = min(dp[a].toDouble(), (dp[a - coins[i - 1]] + 1).toDouble()).toInt() + dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1) } } } @@ -1625,8 +1618,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ## 14.5.3   零錢兌換問題 II @@ -2035,8 +2028,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ### 3.   空間最佳化 @@ -2150,7 +2143,7 @@ $$ dp[0] = 1 // 狀態轉移 for i := 1; i <= n; i++ { - // 倒序走訪 + // 正序走訪 for a := 1; a <= amt; a++ { if coins[i-1] > a { // 若超過目標金額,則不選硬幣 i @@ -2376,5 +2369,5 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ diff --git a/zh-Hant/docs/chapter_graph/graph_operations.md b/zh-Hant/docs/chapter_graph/graph_operations.md index 39fe82a77..7a1de2233 100644 --- a/zh-Hant/docs/chapter_graph/graph_operations.md +++ b/zh-Hant/docs/chapter_graph/graph_operations.md @@ -1044,8 +1044,8 @@ comments: true ```kotlin title="graph_adjacency_matrix.kt" /* 基於鄰接矩陣實現的無向圖類別 */ class GraphAdjMat(vertices: IntArray, edges: Array) { - val vertices: MutableList = ArrayList() // 頂點串列,元素代表“頂點值”,索引代表“頂點索引” - val adjMat: MutableList> = ArrayList() // 鄰接矩陣,行列索引對應“頂點索引” + val vertices = mutableListOf() // 頂點串列,元素代表“頂點值”,索引代表“頂點索引” + val adjMat = mutableListOf>() // 鄰接矩陣,行列索引對應“頂點索引” /* 建構子 */ init { @@ -1066,12 +1066,12 @@ comments: true } /* 新增頂點 */ - fun addVertex(value: Int) { + fun addVertex(_val: Int) { val n = size() // 向頂點串列中新增新頂點的值 - vertices.add(value) + vertices.add(_val) // 在鄰接矩陣中新增一行 - val newRow: MutableList = mutableListOf() + val newRow = mutableListOf() for (j in 0..= size()) throw IndexOutOfBoundsException() + if (index >= size()) + throw IndexOutOfBoundsException() // 在頂點串列中移除索引 index 的頂點 vertices.removeAt(index) // 在鄰接矩陣中刪除索引 index 的行 @@ -1099,7 +1100,8 @@ comments: true // 參數 i, j 對應 vertices 元素索引 fun addEdge(i: Int, j: Int) { // 索引越界與相等處理 - if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException() + if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) + throw IndexOutOfBoundsException() // 在無向圖中,鄰接矩陣關於主對角線對稱,即滿足 (i, j) == (j, i) adjMat[i][j] = 1; adjMat[j][i] = 1; @@ -1109,7 +1111,8 @@ comments: true // 參數 i, j 對應 vertices 元素索引 fun removeEdge(i: Int, j: Int) { // 索引越界與相等處理 - if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException() + if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) + throw IndexOutOfBoundsException() adjMat[i][j] = 0; adjMat[j][i] = 0; } @@ -1138,8 +1141,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 9.2.2   基於鄰接表的實現 @@ -2158,7 +2161,7 @@ comments: true /* 基於鄰接表實現的無向圖類別 */ class GraphAdjList(edges: Array>) { // 鄰接表,key:頂點,value:該頂點的所有鄰接頂點 - val adjList: MutableMap> = HashMap() + val adjList = HashMap>() /* 建構子 */ init { @@ -2217,11 +2220,11 @@ comments: true fun print() { println("鄰接表 =") for (pair in adjList.entries) { - val tmp = ArrayList() + val tmp = mutableListOf() for (vertex in pair.value) { - tmp.add(vertex.value) + tmp.add(vertex._val) } - println("${pair.key.value}: $tmp,") + println("${pair.key._val}: $tmp,") } } } @@ -2241,8 +2244,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 9.2.3   效率對比 diff --git a/zh-Hant/docs/chapter_graph/graph_traversal.md b/zh-Hant/docs/chapter_graph/graph_traversal.md index 27b51c314..66c1caf3e 100644 --- a/zh-Hant/docs/chapter_graph/graph_traversal.md +++ b/zh-Hant/docs/chapter_graph/graph_traversal.md @@ -418,24 +418,24 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入 ```kotlin title="graph_bfs.kt" /* 廣度優先走訪 */ // 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點 - fun graphBFS(graph: GraphAdjList, startVet: Vertex): List { + fun graphBFS(graph: GraphAdjList, startVet: Vertex): MutableList { // 頂點走訪序列 - val res: MutableList = ArrayList() + val res = mutableListOf() // 雜湊表,用於記錄已被訪問過的頂點 - val visited: MutableSet = HashSet() + val visited = HashSet() visited.add(startVet) // 佇列用於實現 BFS - val que: Queue = LinkedList() + val que = LinkedList() que.offer(startVet) // 以頂點 vet 為起點,迴圈直至訪問完所有頂點 while (!que.isEmpty()) { val vet = que.poll() // 佇列首頂點出隊 - res.add(vet) // 記錄訪問頂點 + res.add(vet) // 記錄訪問頂點 // 走訪該頂點的所有鄰接頂點 for (adjVet in graph.adjList[vet]!!) { - if (visited.contains(adjVet)) continue // 跳過已被訪問的頂點 - - que.offer(adjVet) // 只入列未訪問的頂點 + if (visited.contains(adjVet)) + continue // 跳過已被訪問的頂點 + que.offer(adjVet) // 只入列未訪問的頂點 visited.add(adjVet) // 標記該頂點已被訪問 } } @@ -458,8 +458,8 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入 ??? pythontutor "視覺化執行" -
- +
+ 程式碼相對抽象,建議對照圖 9-10 來加深理解。 @@ -866,11 +866,12 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入 res: MutableList, vet: Vertex? ) { - res.add(vet) // 記錄訪問頂點 + res.add(vet) // 記錄訪問頂點 visited.add(vet) // 標記該頂點已被訪問 // 走訪該頂點的所有鄰接頂點 for (adjVet in graph.adjList[vet]!!) { - if (visited.contains(adjVet)) continue // 跳過已被訪問的頂點 + if (visited.contains(adjVet)) + continue // 跳過已被訪問的頂點 // 遞迴訪問鄰接頂點 dfs(graph, visited, res, adjVet) } @@ -878,14 +879,11 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入 /* 深度優先走訪 */ // 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點 - fun graphDFS( - graph: GraphAdjList, - startVet: Vertex? - ): List { + fun graphDFS(graph: GraphAdjList, startVet: Vertex?): MutableList { // 頂點走訪序列 - val res: MutableList = ArrayList() + val res = mutableListOf() // 雜湊表,用於記錄已被訪問過的頂點 - val visited: MutableSet = HashSet() + val visited = HashSet() dfs(graph, visited, res, startVet) return res } @@ -909,8 +907,8 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入 ??? pythontutor "視覺化執行" -
- +
+ 深度優先走訪的演算法流程如圖 9-12 所示。 diff --git a/zh-Hant/docs/chapter_greedy/fractional_knapsack_problem.md b/zh-Hant/docs/chapter_greedy/fractional_knapsack_problem.md index 060e4fd5f..85d0b8306 100644 --- a/zh-Hant/docs/chapter_greedy/fractional_knapsack_problem.md +++ b/zh-Hant/docs/chapter_greedy/fractional_knapsack_problem.md @@ -462,29 +462,25 @@ comments: true /* 物品 */ class Item( val w: Int, // 物品 - val v: Int // 物品價值 + val v: Int // 物品價值 ) /* 分數背包:貪婪 */ - fun fractionalKnapsack( - wgt: IntArray, - value: IntArray, - c: Int - ): Double { + fun fractionalKnapsack(wgt: IntArray, _val: IntArray, c: Int): Double { // 建立物品串列,包含兩個屬性:重量、價值 var cap = c val items = arrayOfNulls(wgt.size) for (i in wgt.indices) { - items[i] = Item(wgt[i], value[i]) + items[i] = Item(wgt[i], _val[i]) } // 按照單位價值 item.v / item.w 從高到低進行排序 - Arrays.sort(items, Comparator.comparingDouble { item: Item -> -(item.v.toDouble() / item.w) }) + items.sortBy { item: Item? -> -(item!!.v.toDouble() / item.w) } // 迴圈貪婪選擇 var res = 0.0 for (item in items) { if (item!!.w <= cap) { // 若剩餘容量充足,則將當前物品整個裝進背包 - res += item.v.toDouble() + res += item.v cap -= item.w } else { // 若剩餘容量不足,則將當前物品的一部分裝進背包 @@ -497,25 +493,21 @@ comments: true } /* 分數背包:貪婪 */ - fun fractionalKnapsack( - wgt: IntArray, - value: IntArray, - c: Int - ): Double { + fun fractionalKnapsack(wgt: IntArray, _val: IntArray, c: Int): Double { // 建立物品串列,包含兩個屬性:重量、價值 var cap = c val items = arrayOfNulls(wgt.size) for (i in wgt.indices) { - items[i] = Item(wgt[i], value[i]) + items[i] = Item(wgt[i], _val[i]) } // 按照單位價值 item.v / item.w 從高到低進行排序 - Arrays.sort(items, Comparator.comparingDouble { item: Item -> -(item.v.toDouble() / item.w) }) + items.sortBy { item: Item? -> -(item!!.v.toDouble() / item.w) } // 迴圈貪婪選擇 var res = 0.0 for (item in items) { if (item!!.w <= cap) { // 若剩餘容量充足,則將當前物品整個裝進背包 - res += item.v.toDouble() + res += item.v cap -= item.w } else { // 若剩餘容量不足,則將當前物品的一部分裝進背包 @@ -546,8 +538,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 除排序之外,在最差情況下,需要走訪整個物品串列,**因此時間複雜度為 $O(n)$** ,其中 $n$ 為物品數量。 diff --git a/zh-Hant/docs/chapter_greedy/greedy_algorithm.md b/zh-Hant/docs/chapter_greedy/greedy_algorithm.md index 5aab16b48..ce8b7cabc 100644 --- a/zh-Hant/docs/chapter_greedy/greedy_algorithm.md +++ b/zh-Hant/docs/chapter_greedy/greedy_algorithm.md @@ -321,8 +321,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 你可能會不由地發出感嘆:So clean !貪婪演算法僅用約十行程式碼就解決了零錢兌換問題。 diff --git a/zh-Hant/docs/chapter_greedy/max_capacity_problem.md b/zh-Hant/docs/chapter_greedy/max_capacity_problem.md index 920923bcf..f48b8e9a5 100644 --- a/zh-Hant/docs/chapter_greedy/max_capacity_problem.md +++ b/zh-Hant/docs/chapter_greedy/max_capacity_problem.md @@ -381,8 +381,8 @@ $$ // 迴圈貪婪選擇,直至兩板相遇 while (i < j) { // 更新最大容量 - val cap = (min(ht[i].toDouble(), ht[j].toDouble()) * (j - i)).toInt() - res = max(res.toDouble(), cap.toDouble()).toInt() + val cap = min(ht[i], ht[j]) * (j - i) + res = max(res, cap) // 向內移動短板 if (ht[i] < ht[j]) { i++ @@ -408,8 +408,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ### 3.   正確性證明 diff --git a/zh-Hant/docs/chapter_greedy/max_product_cutting_problem.md b/zh-Hant/docs/chapter_greedy/max_product_cutting_problem.md index c42808d09..79e5b114d 100644 --- a/zh-Hant/docs/chapter_greedy/max_product_cutting_problem.md +++ b/zh-Hant/docs/chapter_greedy/max_product_cutting_problem.md @@ -357,14 +357,14 @@ $$ val b = n % 3 if (b == 1) { // 當餘數為 1 時,將一對 1 * 3 轉化為 2 * 2 - return 3.0.pow((a - 1).toDouble()).toInt() * 2 * 2 + return 3.0.pow((a - 1)).toInt() * 2 * 2 } if (b == 2) { // 當餘數為 2 時,不做處理 - return 3.0.pow(a.toDouble()).toInt() * 2 * 2 + return 3.0.pow(a).toInt() * 2 * 2 } // 當餘數為 0 時,不做處理 - return 3.0.pow(a.toDouble()).toInt() + return 3.0.pow(a).toInt() } ``` @@ -382,8 +382,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ![最大切分乘積的計算方法](max_product_cutting_problem.assets/max_product_cutting_greedy_calculation.png){ class="animation-figure" } diff --git a/zh-Hant/docs/chapter_hashing/hash_algorithm.md b/zh-Hant/docs/chapter_hashing/hash_algorithm.md index 9a34a5350..8286a9791 100644 --- a/zh-Hant/docs/chapter_hashing/hash_algorithm.md +++ b/zh-Hant/docs/chapter_hashing/hash_algorithm.md @@ -620,8 +620,8 @@ index = hash(key) % capacity ??? pythontutor "視覺化執行" -
- +
+ 觀察發現,每種雜湊演算法的最後一步都是對大質數 $1000000007$ 取模,以確保雜湊值在合適的範圍內。值得思考的是,為什麼要強調對質數取模,或者說對合數取模的弊端是什麼?這是一個有趣的問題。 @@ -962,8 +962,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ 在許多程式語言中,**只有不可變物件才可作為雜湊表的 `key`** 。假如我們將串列(動態陣列)作為 `key` ,當串列的內容發生變化時,它的雜湊值也隨之改變,我們就無法在雜湊表中查詢到原先的 `value` 了。 diff --git a/zh-Hant/docs/chapter_hashing/hash_collision.md b/zh-Hant/docs/chapter_hashing/hash_collision.md index b2a6d09d6..1a05aa856 100644 --- a/zh-Hant/docs/chapter_hashing/hash_collision.md +++ b/zh-Hant/docs/chapter_hashing/hash_collision.md @@ -1114,17 +1114,14 @@ comments: true // 走訪桶,若遇到指定 key ,則更新對應 val 並返回 for pair in bucket { if pair.key == key { - pair.val = val.clone(); + pair.val = val; return; } } let bucket = &mut self.buckets[index]; // 若無該 key ,則將鍵值對新增至尾部 - let pair = Pair { - key, - val: val.clone(), - }; + let pair = Pair { key, val }; bucket.push(pair); self.size += 1; } @@ -1328,7 +1325,7 @@ comments: true capacity = 4 loadThres = 2.0 / 3.0 extendRatio = 2 - buckets = ArrayList(capacity) + buckets = mutableListOf() for (i in 0.. loadThres) { extend() @@ -1367,12 +1364,12 @@ comments: true // 走訪桶,若遇到指定 key ,則更新對應 val 並返回 for (pair in bucket) { if (pair.key == key) { - pair.value = value + pair._val = _val return } } // 若無該 key ,則將鍵值對新增至尾部 - val pair = Pair(key, value) + val pair = Pair(key, _val) bucket.add(pair) size++ } @@ -1406,7 +1403,7 @@ comments: true // 將鍵值對從原雜湊表搬運至新雜湊表 for (bucket in bucketsTmp) { for (pair in bucket) { - put(pair.key, pair.value) + put(pair.key, pair._val) } } } @@ -1417,7 +1414,7 @@ comments: true val res = mutableListOf() for (pair in bucket) { val k = pair.key - val v = pair.value + val v = pair._val res.add("$k -> $v") } println(res) @@ -1440,8 +1437,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 值得注意的是,當鏈結串列很長時,查詢效率 $O(n)$ 很差。**此時可以將鏈結串列轉換為“AVL 樹”或“紅黑樹”**,從而將查詢操作的時間複雜度最佳化至 $O(\log n)$ 。 @@ -2824,6 +2821,9 @@ comments: true free(pair); } } + free(hashMap->buckets); + free(hashMap->TOMBSTONE); + free(hashMap); } /* 雜湊函式 */ @@ -2957,16 +2957,21 @@ comments: true ```kotlin title="hash_map_open_addressing.kt" /* 開放定址雜湊表 */ class HashMapOpenAddressing { - private var size: Int = 0 // 鍵值對數量 - private var capacity = 4 // 雜湊表容量 - private val loadThres: Double = 2.0 / 3.0 // 觸發擴容的負載因子閾值 - private val extendRatio = 2 // 擴容倍數 - private var buckets: Array // 桶陣列 - private val TOMBSTONE = Pair(-1, "-1") // 刪除標記 + private var size: Int // 鍵值對數量 + private var capacity: Int // 雜湊表容量 + private val loadThres: Double // 觸發擴容的負載因子閾值 + private val extendRatio: Int // 擴容倍數 + private var buckets: Array // 桶陣列 + private val TOMBSTONE: Pair // 刪除標記 /* 建構子 */ init { + size = 0 + capacity = 4 + loadThres = 2.0 / 3.0 + extendRatio = 2 buckets = arrayOfNulls(capacity) + TOMBSTONE = Pair(-1, "-1") } /* 雜湊函式 */ @@ -3012,14 +3017,14 @@ comments: true val index = findBucket(key) // 若找到鍵值對,則返回對應 val if (buckets[index] != null && buckets[index] != TOMBSTONE) { - return buckets[index]?.value + return buckets[index]?._val } // 若鍵值對不存在,則返回 null return null } /* 新增操作 */ - fun put(key: Int, value: String) { + fun put(key: Int, _val: String) { // 當負載因子超過閾值時,執行擴容 if (loadFactor() > loadThres) { extend() @@ -3028,11 +3033,11 @@ comments: true val index = findBucket(key) // 若找到鍵值對,則覆蓋 val 並返回 if (buckets[index] != null && buckets[index] != TOMBSTONE) { - buckets[index]!!.value = value + buckets[index]!!._val = _val return } // 若鍵值對不存在,則新增該鍵值對 - buckets[index] = Pair(key, value) + buckets[index] = Pair(key, _val) size++ } @@ -3058,7 +3063,7 @@ comments: true // 將鍵值對從原雜湊表搬運至新雜湊表 for (pair in bucketsTmp) { if (pair != null && pair != TOMBSTONE) { - put(pair.key, pair.value) + put(pair.key, pair._val) } } } @@ -3071,7 +3076,7 @@ comments: true } else if (pair == TOMBSTONE) { println("TOMESTOME") } else { - println("${pair.key} -> ${pair.value}") + println("${pair.key} -> ${pair._val}") } } } diff --git a/zh-Hant/docs/chapter_hashing/hash_map.md b/zh-Hant/docs/chapter_hashing/hash_map.md index 70b61fc0c..74c49dc9e 100755 --- a/zh-Hant/docs/chapter_hashing/hash_map.md +++ b/zh-Hant/docs/chapter_hashing/hash_map.md @@ -314,8 +314,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 雜湊表有三種常用的走訪方式:走訪鍵值對、走訪鍵和走訪值。示例程式碼如下: @@ -534,8 +534,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 6.1.2   雜湊表簡單實現 @@ -1584,20 +1584,14 @@ index = hash(key) % capacity /* 鍵值對 */ class Pair( var key: Int, - var value: String + var _val: String ) /* 基於陣列實現的雜湊表 */ class ArrayHashMap { + // 初始化陣列,包含 100 個桶 private val buckets = arrayOfNulls(100) - init { - // 初始化陣列,包含 100 個桶 - for (i in 0..<100) { - buckets[i] = null - } - } - /* 雜湊函式 */ fun hashFunc(key: Int): Int { val index = key % 100 @@ -1608,12 +1602,12 @@ index = hash(key) % capacity fun get(key: Int): String? { val index = hashFunc(key) val pair = buckets[index] ?: return null - return pair.value + return pair._val } /* 新增操作 */ - fun put(key: Int, value: String) { - val pair = Pair(key, value) + fun put(key: Int, _val: String) { + val pair = Pair(key, _val) val index = hashFunc(key) buckets[index] = pair } @@ -1627,27 +1621,29 @@ index = hash(key) % capacity /* 獲取所有鍵值對 */ fun pairSet(): MutableList { - val pairSet = ArrayList() + val pairSet = mutableListOf() for (pair in buckets) { - if (pair != null) pairSet.add(pair) + if (pair != null) + pairSet.add(pair) } return pairSet } /* 獲取所有鍵 */ fun keySet(): MutableList { - val keySet = ArrayList() + val keySet = mutableListOf() for (pair in buckets) { - if (pair != null) keySet.add(pair.key) + if (pair != null) + keySet.add(pair.key) } return keySet } /* 獲取所有值 */ fun valueSet(): MutableList { - val valueSet = ArrayList() + val valueSet = mutableListOf() for (pair in buckets) { - pair?.let { valueSet.add(it.value) } + pair?.let { valueSet.add(it._val) } } return valueSet } @@ -1656,23 +1652,17 @@ index = hash(key) % capacity fun print() { for (kv in pairSet()) { val key = kv.key - val value = kv.value - println("${key}->${value}") + val _val = kv._val + println("${key} -> ${_val}") } } } /* 基於陣列實現的雜湊表 */ class ArrayHashMap { + // 初始化陣列,包含 100 個桶 private val buckets = arrayOfNulls(100) - init { - // 初始化陣列,包含 100 個桶 - for (i in 0..<100) { - buckets[i] = null - } - } - /* 雜湊函式 */ fun hashFunc(key: Int): Int { val index = key % 100 @@ -1683,12 +1673,12 @@ index = hash(key) % capacity fun get(key: Int): String? { val index = hashFunc(key) val pair = buckets[index] ?: return null - return pair.value + return pair._val } /* 新增操作 */ - fun put(key: Int, value: String) { - val pair = Pair(key, value) + fun put(key: Int, _val: String) { + val pair = Pair(key, _val) val index = hashFunc(key) buckets[index] = pair } @@ -1702,27 +1692,29 @@ index = hash(key) % capacity /* 獲取所有鍵值對 */ fun pairSet(): MutableList { - val pairSet = ArrayList() + val pairSet = mutableListOf() for (pair in buckets) { - if (pair != null) pairSet.add(pair) + if (pair != null) + pairSet.add(pair) } return pairSet } /* 獲取所有鍵 */ fun keySet(): MutableList { - val keySet = ArrayList() + val keySet = mutableListOf() for (pair in buckets) { - if (pair != null) keySet.add(pair.key) + if (pair != null) + keySet.add(pair.key) } return keySet } /* 獲取所有值 */ fun valueSet(): MutableList { - val valueSet = ArrayList() + val valueSet = mutableListOf() for (pair in buckets) { - pair?.let { valueSet.add(it.value) } + pair?.let { valueSet.add(it._val) } } return valueSet } @@ -1731,8 +1723,8 @@ index = hash(key) % capacity fun print() { for (kv in pairSet()) { val key = kv.key - val value = kv.value - println("${key}->${value}") + val _val = kv._val + println("${key} -> ${_val}") } } } @@ -1857,8 +1849,8 @@ index = hash(key) % capacity ??? pythontutor "視覺化執行" -
- +
+ ## 6.1.3   雜湊衝突與擴容 diff --git a/zh-Hant/docs/chapter_heap/build_heap.md b/zh-Hant/docs/chapter_heap/build_heap.md index fbbf647a9..42c765b5a 100644 --- a/zh-Hant/docs/chapter_heap/build_heap.md +++ b/zh-Hant/docs/chapter_heap/build_heap.md @@ -189,13 +189,14 @@ comments: true ```kotlin title="my_heap.kt" /* 大頂堆積 */ - class MaxHeap(nums: List?) { + class MaxHeap(nums: MutableList?) { // 使用串列而非陣列,這樣無須考慮擴容問題 - // 將串列元素原封不動新增進堆積 - private val maxHeap = ArrayList(nums!!) + private val maxHeap = mutableListOf() /* 建構子,根據輸入串列建堆積 */ init { + // 將串列元素原封不動新增進堆積 + maxHeap.addAll(nums!!) // 堆積化除葉節點以外的其他所有節點 for (i in parent(size() - 1) downTo 0) { siftDown(i) @@ -239,9 +240,9 @@ comments: true } /* 元素入堆積 */ - fun push(value: Int) { + fun push(_val: Int) { // 新增節點 - maxHeap.add(value) + maxHeap.add(_val) // 從底至頂堆積化 siftUp(size() - 1) } @@ -269,11 +270,11 @@ comments: true // 交換根節點與最右葉節點(交換首元素與尾元素) swap(0, size() - 1) // 刪除節點 - val value = maxHeap.removeAt(size() - 1) + val _val = maxHeap.removeAt(size() - 1) // 從頂至底堆積化 siftDown(0) // 返回堆積頂元素 - return value + return _val } /* 從節點 i 開始,從頂至底堆積化 */ @@ -330,8 +331,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 8.2.3   複雜度分析 diff --git a/zh-Hant/docs/chapter_heap/heap.md b/zh-Hant/docs/chapter_heap/heap.md index 91d71b220..037509ce2 100644 --- a/zh-Hant/docs/chapter_heap/heap.md +++ b/zh-Hant/docs/chapter_heap/heap.md @@ -426,8 +426,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 8.1.2   堆積的實現 @@ -831,8 +831,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 3.   元素入堆積 @@ -1184,9 +1184,9 @@ comments: true ```kotlin title="my_heap.kt" /* 元素入堆積 */ - fun push(value: Int) { + fun push(_val: Int) { // 新增節點 - maxHeap.add(value) + maxHeap.add(_val) // 從底至頂堆積化 siftUp(size() - 1) } @@ -1245,8 +1245,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 4.   堆積頂元素出堆積 @@ -1736,11 +1736,11 @@ comments: true // 交換根節點與最右葉節點(交換首元素與尾元素) swap(0, size() - 1) // 刪除節點 - val value = maxHeap.removeAt(size() - 1) + val _val = maxHeap.removeAt(size() - 1) // 從頂至底堆積化 siftDown(0) // 返回堆積頂元素 - return value + return _val } /* 從節點 i 開始,從頂至底堆積化 */ @@ -1811,8 +1811,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 8.1.3   堆積的常見應用 diff --git a/zh-Hant/docs/chapter_heap/top_k.md b/zh-Hant/docs/chapter_heap/top_k.md index bb3e07ebb..cca446e63 100644 --- a/zh-Hant/docs/chapter_heap/top_k.md +++ b/zh-Hant/docs/chapter_heap/top_k.md @@ -448,8 +448,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 總共執行了 $n$ 輪入堆積和出堆積,堆積的最大長度為 $k$ ,因此時間複雜度為 $O(n \log k)$ 。該方法的效率很高,當 $k$ 較小時,時間複雜度趨向 $O(n)$ ;當 $k$ 較大時,時間複雜度不會超過 $O(n \log n)$ 。 diff --git a/zh-Hant/docs/chapter_preface/suggestions.md b/zh-Hant/docs/chapter_preface/suggestions.md index f9e8b8f75..02aee4e8d 100644 --- a/zh-Hant/docs/chapter_preface/suggestions.md +++ b/zh-Hant/docs/chapter_preface/suggestions.md @@ -176,7 +176,12 @@ comments: true === "Ruby" ```ruby title="" + ### 標題註釋,用於標註函式、類別、測試樣例等 ### + # 內容註釋,用於詳解程式碼 + + # 多行 + # 註釋 ``` === "Zig" diff --git a/zh-Hant/docs/chapter_searching/binary_search.md b/zh-Hant/docs/chapter_searching/binary_search.md index 286acaf73..9657dcfe7 100755 --- a/zh-Hant/docs/chapter_searching/binary_search.md +++ b/zh-Hant/docs/chapter_searching/binary_search.md @@ -368,8 +368,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ **時間複雜度為 $O(\log n)$** :在二分迴圈中,區間每輪縮小一半,因此迴圈次數為 $\log_2 n$ 。 @@ -696,8 +696,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 如圖 10-3 所示,在兩種區間表示下,二分搜尋演算法的初始化、迴圈條件和縮小區間操作皆有所不同。 diff --git a/zh-Hant/docs/chapter_searching/binary_search_edge.md b/zh-Hant/docs/chapter_searching/binary_search_edge.md index ae1af133a..e8bf1747f 100644 --- a/zh-Hant/docs/chapter_searching/binary_search_edge.md +++ b/zh-Hant/docs/chapter_searching/binary_search_edge.md @@ -223,8 +223,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 10.3.2   查詢右邊界 @@ -472,8 +472,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   轉化為查詢元素 diff --git a/zh-Hant/docs/chapter_searching/binary_search_insertion.md b/zh-Hant/docs/chapter_searching/binary_search_insertion.md index c49bce901..29a84ed34 100644 --- a/zh-Hant/docs/chapter_searching/binary_search_insertion.md +++ b/zh-Hant/docs/chapter_searching/binary_search_insertion.md @@ -304,8 +304,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 10.2.2   存在重複元素的情況 @@ -636,8 +636,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ !!! tip 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 765048d87..02725ddbf 100755 --- a/zh-Hant/docs/chapter_searching/replace_linear_by_hashing.md +++ b/zh-Hant/docs/chapter_searching/replace_linear_by_hashing.md @@ -253,8 +253,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 此方法的時間複雜度為 $O(n^2)$ ,空間複雜度為 $O(1)$ ,在大資料量下非常耗時。 @@ -557,8 +557,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 此方法透過雜湊查詢將時間複雜度從 $O(n^2)$ 降至 $O(n)$ ,大幅提升執行效率。 diff --git a/zh-Hant/docs/chapter_sorting/bubble_sort.md b/zh-Hant/docs/chapter_sorting/bubble_sort.md index b413fffdf..bda406f4e 100755 --- a/zh-Hant/docs/chapter_sorting/bubble_sort.md +++ b/zh-Hant/docs/chapter_sorting/bubble_sort.md @@ -264,7 +264,7 @@ comments: true for (j in 0.. nums[j + 1]) { // 交換 nums[j] 與 nums[j + 1] - nums[j] = nums[j+1].also { nums[j+1] = nums[j] } + nums[j] = nums[j + 1].also { nums[j + 1] = nums[j] } } } } @@ -301,8 +301,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.3.2   效率最佳化 @@ -613,8 +613,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.3.3   演算法特性 diff --git a/zh-Hant/docs/chapter_sorting/bucket_sort.md b/zh-Hant/docs/chapter_sorting/bucket_sort.md index 3cf8a9615..bd49cc67f 100644 --- a/zh-Hant/docs/chapter_sorting/bucket_sort.md +++ b/zh-Hant/docs/chapter_sorting/bucket_sort.md @@ -395,9 +395,9 @@ comments: true fun bucketSort(nums: FloatArray) { // 初始化 k = n/2 個桶,預期向每個桶分配 2 個元素 val k = nums.size / 2 - val buckets = ArrayList>() + val buckets = mutableListOf>() for (i in 0.. - +
+ ## 11.8.2   演算法特性 diff --git a/zh-Hant/docs/chapter_sorting/counting_sort.md b/zh-Hant/docs/chapter_sorting/counting_sort.md index 83665b8ea..177a3f637 100644 --- a/zh-Hant/docs/chapter_sorting/counting_sort.md +++ b/zh-Hant/docs/chapter_sorting/counting_sort.md @@ -324,7 +324,7 @@ comments: true // 1. 統計陣列最大元素 m var m = 0 for (num in nums) { - m = max(m.toDouble(), num.toDouble()).toInt() + m = max(m, num) } // 2. 統計各數字的出現次數 // counter[num] 代表 num 的出現次數 @@ -359,8 +359,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ !!! note "計數排序與桶排序的關聯" @@ -822,7 +822,7 @@ $$ // 1. 統計陣列最大元素 m var m = 0 for (num in nums) { - m = max(m.toDouble(), num.toDouble()).toInt() + m = max(m, num) } // 2. 統計各數字的出現次數 // counter[num] 代表 num 的出現次數 @@ -865,8 +865,8 @@ $$ ??? pythontutor "視覺化執行" -
- +
+ ## 11.9.3   演算法特性 diff --git a/zh-Hant/docs/chapter_sorting/heap_sort.md b/zh-Hant/docs/chapter_sorting/heap_sort.md index 920293948..5e98f1688 100644 --- a/zh-Hant/docs/chapter_sorting/heap_sort.md +++ b/zh-Hant/docs/chapter_sorting/heap_sort.md @@ -545,10 +545,13 @@ comments: true val l = 2 * i + 1 val r = 2 * i + 2 var ma = i - if (l < n && nums[l] > nums[ma]) ma = l - if (r < n && nums[r] > nums[ma]) ma = r + if (l < n && nums[l] > nums[ma]) + ma = l + if (r < n && nums[r] > nums[ma]) + ma = r // 若節點 i 最大或索引 l, r 越界,則無須繼續堆積化,跳出 - if (ma == i) break + if (ma == i) + break // 交換兩節點 nums[i] = nums[ma].also { nums[ma] = nums[i] } // 迴圈向下堆積化 @@ -590,8 +593,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.7.2   演算法特性 diff --git a/zh-Hant/docs/chapter_sorting/insertion_sort.md b/zh-Hant/docs/chapter_sorting/insertion_sort.md index e1981665b..36495f0da 100755 --- a/zh-Hant/docs/chapter_sorting/insertion_sort.md +++ b/zh-Hant/docs/chapter_sorting/insertion_sort.md @@ -240,7 +240,7 @@ comments: true for (i in nums.indices) { val base = nums[i] var j = i - 1 - // 內迴圈: 將 base 插入到已排序部分的正確位置 + // 內迴圈:將 base 插入到已排序區間 [0, i-1] 中的正確位置 while (j >= 0 && nums[j] > base) { nums[j + 1] = nums[j] // 將 nums[j] 向右移動一位 j-- @@ -277,8 +277,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.4.2   演算法特性 diff --git a/zh-Hant/docs/chapter_sorting/merge_sort.md b/zh-Hant/docs/chapter_sorting/merge_sort.md index 3d059745a..1f1e4d21a 100755 --- a/zh-Hant/docs/chapter_sorting/merge_sort.md +++ b/zh-Hant/docs/chapter_sorting/merge_sort.md @@ -596,8 +596,10 @@ comments: true var k = 0 // 當左右子陣列都還有元素時,進行比較並將較小的元素複製到臨時陣列中 while (i <= mid && j <= right) { - if (nums[i] <= nums[j]) tmp[k++] = nums[i++] - else tmp[k++] = nums[j++] + if (nums[i] <= nums[j]) + tmp[k++] = nums[i++] + else + tmp[k++] = nums[j++] } // 將左子陣列和右子陣列的剩餘元素複製到臨時陣列中 while (i <= mid) { @@ -689,8 +691,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.6.2   演算法特性 diff --git a/zh-Hant/docs/chapter_sorting/quick_sort.md b/zh-Hant/docs/chapter_sorting/quick_sort.md index 05c2178d2..c137f4962 100755 --- a/zh-Hant/docs/chapter_sorting/quick_sort.md +++ b/zh-Hant/docs/chapter_sorting/quick_sort.md @@ -384,8 +384,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.5.1   演算法流程 @@ -638,8 +638,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.5.2   演算法特性 @@ -1129,8 +1129,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 11.5.5   尾遞迴最佳化 @@ -1415,5 +1415,5 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ diff --git a/zh-Hant/docs/chapter_sorting/radix_sort.md b/zh-Hant/docs/chapter_sorting/radix_sort.md index 8be8251ad..2f9a424e9 100644 --- a/zh-Hant/docs/chapter_sorting/radix_sort.md +++ b/zh-Hant/docs/chapter_sorting/radix_sort.md @@ -170,12 +170,13 @@ $$ if (num > m) m = num; // 按照從低位到高位的順序走訪 - for (int exp = 1; exp <= m; exp *= 10) + for (int exp = 1; exp <= m; exp *= 10) { // 對陣列元素的第 k 位執行計數排序 // k = 1 -> exp = 1 // k = 2 -> exp = 10 // 即 exp = 10^(k-1) countingSortDigit(nums, exp); + } } ``` @@ -636,7 +637,7 @@ $$ // 統計 0~9 各數字的出現次數 for (i in 0.. - +
+ !!! question "為什麼從最低位開始排序?" diff --git a/zh-Hant/docs/chapter_sorting/selection_sort.md b/zh-Hant/docs/chapter_sorting/selection_sort.md index f9749f39f..89c465eec 100644 --- a/zh-Hant/docs/chapter_sorting/selection_sort.md +++ b/zh-Hant/docs/chapter_sorting/selection_sort.md @@ -292,7 +292,8 @@ comments: true var k = i // 內迴圈:找到未排序區間內的最小元素 for (j in i + 1.. - +
+ ## 11.2.1   演算法特性 diff --git a/zh-Hant/docs/chapter_stack_and_queue/deque.md b/zh-Hant/docs/chapter_stack_and_queue/deque.md index c99f0a538..f246ef132 100644 --- a/zh-Hant/docs/chapter_stack_and_queue/deque.md +++ b/zh-Hant/docs/chapter_stack_and_queue/deque.md @@ -38,25 +38,25 @@ comments: true # 初始化雙向佇列 deque: deque[int] = deque() - + # 元素入列 deque.append(2) # 新增至佇列尾 deque.append(5) deque.append(4) deque.appendleft(3) # 新增至佇列首 deque.appendleft(1) - + # 訪問元素 front: int = deque[0] # 佇列首元素 rear: int = deque[-1] # 佇列尾元素 - + # 元素出列 pop_front: int = deque.popleft() # 佇列首元素出列 pop_rear: int = deque.pop() # 佇列尾元素出列 - + # 獲取雙向佇列的長度 size: int = len(deque) - + # 判斷雙向佇列是否為空 is_empty: bool = len(deque) == 0 ``` @@ -66,25 +66,25 @@ comments: true ```cpp title="deque.cpp" /* 初始化雙向佇列 */ deque deque; - + /* 元素入列 */ deque.push_back(2); // 新增至佇列尾 deque.push_back(5); deque.push_back(4); deque.push_front(3); // 新增至佇列首 deque.push_front(1); - + /* 訪問元素 */ int front = deque.front(); // 佇列首元素 int back = deque.back(); // 佇列尾元素 - + /* 元素出列 */ deque.pop_front(); // 佇列首元素出列 deque.pop_back(); // 佇列尾元素出列 - + /* 獲取雙向佇列的長度 */ int size = deque.size(); - + /* 判斷雙向佇列是否為空 */ bool empty = deque.empty(); ``` @@ -94,25 +94,25 @@ comments: true ```java title="deque.java" /* 初始化雙向佇列 */ Deque deque = new LinkedList<>(); - + /* 元素入列 */ deque.offerLast(2); // 新增至佇列尾 deque.offerLast(5); deque.offerLast(4); deque.offerFirst(3); // 新增至佇列首 deque.offerFirst(1); - + /* 訪問元素 */ int peekFirst = deque.peekFirst(); // 佇列首元素 int peekLast = deque.peekLast(); // 佇列尾元素 - + /* 元素出列 */ int popFirst = deque.pollFirst(); // 佇列首元素出列 int popLast = deque.pollLast(); // 佇列尾元素出列 - + /* 獲取雙向佇列的長度 */ int size = deque.size(); - + /* 判斷雙向佇列是否為空 */ boolean isEmpty = deque.isEmpty(); ``` @@ -123,25 +123,25 @@ comments: true /* 初始化雙向佇列 */ // 在 C# 中,將鏈結串列 LinkedList 看作雙向佇列來使用 LinkedList deque = new(); - + /* 元素入列 */ deque.AddLast(2); // 新增至佇列尾 deque.AddLast(5); deque.AddLast(4); deque.AddFirst(3); // 新增至佇列首 deque.AddFirst(1); - + /* 訪問元素 */ int peekFirst = deque.First.Value; // 佇列首元素 int peekLast = deque.Last.Value; // 佇列尾元素 - + /* 元素出列 */ deque.RemoveFirst(); // 佇列首元素出列 deque.RemoveLast(); // 佇列尾元素出列 - + /* 獲取雙向佇列的長度 */ int size = deque.Count; - + /* 判斷雙向佇列是否為空 */ bool isEmpty = deque.Count == 0; ``` @@ -152,25 +152,25 @@ comments: true /* 初始化雙向佇列 */ // 在 Go 中,將 list 作為雙向佇列使用 deque := list.New() - + /* 元素入列 */ deque.PushBack(2) // 新增至佇列尾 deque.PushBack(5) deque.PushBack(4) deque.PushFront(3) // 新增至佇列首 deque.PushFront(1) - + /* 訪問元素 */ front := deque.Front() // 佇列首元素 rear := deque.Back() // 佇列尾元素 - + /* 元素出列 */ deque.Remove(front) // 佇列首元素出列 deque.Remove(rear) // 佇列尾元素出列 - + /* 獲取雙向佇列的長度 */ size := deque.Len() - + /* 判斷雙向佇列是否為空 */ isEmpty := deque.Len() == 0 ``` @@ -339,25 +339,25 @@ comments: true ```kotlin title="deque.kt" /* 初始化雙向佇列 */ val deque = LinkedList() - + /* 元素入列 */ deque.offerLast(2) // 新增至佇列尾 deque.offerLast(5) deque.offerLast(4) deque.offerFirst(3) // 新增至佇列首 deque.offerFirst(1) - + /* 訪問元素 */ val peekFirst = deque.peekFirst() // 佇列首元素 val peekLast = deque.peekLast() // 佇列尾元素 - + /* 元素出列 */ val popFirst = deque.pollFirst() // 佇列首元素出列 val popLast = deque.pollLast() // 佇列尾元素出列 - + /* 獲取雙向佇列的長度 */ val size = deque.size - + /* 判斷雙向佇列是否為空 */ val isEmpty = deque.isEmpty() ``` @@ -365,7 +365,32 @@ comments: true === "Ruby" ```ruby title="deque.rb" + # 初始化雙向佇列 + # Ruby 沒有內直的雙端佇列,只能把 Array 當作雙端佇列來使用 + deque = [] + # 元素如隊 + deque << 2 + deque << 5 + deque << 4 + # 請注意,由於是陣列,Array#unshift 方法的時間複雜度為 O(n) + deque.unshift(3) + deque.unshift(1) + + # 訪問元素 + peek_first = deque.first + peek_last = deque.last + + # 元素出列 + # 請注意,由於是陣列, Array#shift 方法的時間複雜度為 O(n) + pop_front = deque.shift + pop_back = deque.pop + + # 獲取雙向佇列的長度 + size = deque.length + + # 判斷雙向佇列是否為空 + is_empty = size.zero? ``` === "Zig" @@ -376,8 +401,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 5.3.2   雙向佇列實現 * @@ -1826,8 +1851,8 @@ comments: true if (fNext) { fNext->prev = NULL; deque->front->next = NULL; - delDoublyListNode(deque->front); } + delDoublyListNode(deque->front); deque->front = fNext; // 更新頭節點 } // 佇列尾出列操作 @@ -1837,8 +1862,8 @@ comments: true if (rPrev) { rPrev->next = NULL; deque->rear->prev = NULL; - delDoublyListNode(deque->rear); } + delDoublyListNode(deque->rear); deque->rear = rPrev; // 更新尾節點 } deque->queSize--; // 更新佇列長度 @@ -1874,7 +1899,7 @@ comments: true ```kotlin title="linkedlist_deque.kt" /* 雙向鏈結串列節點 */ - class ListNode(var value: Int) { + class ListNode(var _val: Int) { // 節點值 var next: ListNode? = null // 後繼節點引用 var prev: ListNode? = null // 前驅節點引用 @@ -1882,9 +1907,9 @@ comments: true /* 基於雙向鏈結串列實現的雙向佇列 */ class LinkedListDeque { - private var front: ListNode? = null // 頭節點 front ,尾節點 rear - private var rear: ListNode? = null - private var queSize = 0 // 雙向佇列的長度 + private var front: ListNode? = null // 頭節點 front + private var rear: ListNode? = null // 尾節點 rear + private var queSize: Int = 0 // 雙向佇列的長度 /* 獲取雙向佇列的長度 */ fun size(): Int { @@ -1931,12 +1956,12 @@ comments: true /* 出列操作 */ fun pop(isFront: Boolean): Int { - if (isEmpty()) throw IndexOutOfBoundsException() - - val value: Int + if (isEmpty()) + throw IndexOutOfBoundsException() + val _val: Int // 佇列首出列操作 if (isFront) { - value = front!!.value // 暫存頭節點值 + _val = front!!._val // 暫存頭節點值 // 刪除頭節點 val fNext = front!!.next if (fNext != null) { @@ -1946,7 +1971,7 @@ comments: true front = fNext // 更新頭節點 // 佇列尾出列操作 } else { - value = rear!!.value // 暫存尾節點值 + _val = rear!!._val // 暫存尾節點值 // 刪除尾節點 val rPrev = rear!!.prev if (rPrev != null) { @@ -1956,7 +1981,7 @@ comments: true rear = rPrev // 更新尾節點 } queSize-- // 更新佇列長度 - return value + return _val } /* 佇列首出列 */ @@ -1971,17 +1996,14 @@ comments: true /* 訪問佇列首元素 */ fun peekFirst(): Int { - if (isEmpty()) { - throw IndexOutOfBoundsException() - - } - return front!!.value + if (isEmpty()) throw IndexOutOfBoundsException() + return front!!._val } /* 訪問佇列尾元素 */ fun peekLast(): Int { if (isEmpty()) throw IndexOutOfBoundsException() - return rear!!.value + return rear!!._val } /* 返回陣列用於列印 */ @@ -1989,7 +2011,7 @@ comments: true var node = front val res = IntArray(size()) for (i in res.indices) { - res[i] = node!!.value + res[i] = node!!._val node = node.next } return res @@ -2000,9 +2022,138 @@ comments: true === "Ruby" ```ruby title="linkedlist_deque.rb" - [class]{ListNode}-[func]{} + =begin + File: linkedlist_deque.rb + Created Time: 2024-04-06 + Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) + =end - [class]{LinkedListDeque}-[func]{} + ### 雙向鏈結串列節點 + class ListNode + attr_accessor :val + attr_accessor :next # 後繼節點引用 + attr_accessor :prev # 前軀節點引用 + + ### 建構子 ### + def initialize(val) + @val = val + end + end + + ### 基於雙向鏈結串列實現的雙向佇列 ### + class LinkedListDeque + ### 獲取雙向佇列的長度 ### + attr_reader :size + + ### 建構子 ### + def initialize + @front = nil # 頭節點 front + @rear = nil # 尾節點 rear + @size = 0 # 雙向佇列的長度 + end + + ### 判斷雙向佇列是否為空 ### + def is_empty? + size.zero? + end + + ### 入列操作 ### + def push(num, is_front) + node = ListNode.new(num) + # 若鏈結串列為空, 則令 front 和 rear 都指向 node + if is_empty? + @front = @rear = node + # 佇列首入列操作 + elsif is_front + # 將 node 新增至鏈結串列頭部 + @front.prev = node + node.next = @front + @front = node # 更新頭節點 + # 佇列尾入列操作 + else + # 將 node 新增至鏈結串列尾部 + @rear.next = node + node.prev = @rear + @rear = node # 更新尾節點 + end + @size += 1 # 更新佇列長度 + end + + ### 佇列首入列 ### + def push_first(num) + push(num, true) + end + + ### 佇列尾入列 ### + def push_last(num) + push(num, false) + end + + ### 出列操作 ### + def pop(is_front) + raise IndexError, '雙向佇列為空' if is_empty? + + # 佇列首出列操作 + if is_front + val = @front.val # 暫存頭節點值 + # 刪除頭節點 + fnext = @front.next + unless fnext.nil? + fnext.prev = nil + @front.next = nil + end + @front = fnext # 更新頭節點 + # 佇列尾出列操作 + else + val = @rear.val # 暫存尾節點值 + # 刪除尾節點 + rprev = @rear.prev + unless rprev.nil? + rprev.next = nil + @rear.prev = nil + end + @rear = rprev # 更新尾節點 + end + @size -= 1 # 更新佇列長度 + + val + end + + ### 佇列首出列 ### + def pop_first + pop(true) + end + + ### 佇列首出列 ### + def pop_last + pop(false) + end + + ### 訪問佇列首元素 ### + def peek_first + raise IndexError, '雙向佇列為空' if is_empty? + + @front.val + end + + ### 訪問佇列尾元素 ### + def peek_last + raise IndexError, '雙向佇列為空' if is_empty? + + @rear.val + end + + ### 返回陣列用於列印 ### + def to_array + node = @front + res = Array.new(size, 0) + for i in 0...size + res[i] = node.val + node = node.next + end + res + end + end ``` === "Zig" @@ -3385,11 +3536,11 @@ comments: true === "Kotlin" ```kotlin title="array_deque.kt" - /* 基於環形陣列實現的雙向佇列 */ + /* 建構子 */ class ArrayDeque(capacity: Int) { - private var nums = IntArray(capacity) // 用於儲存雙向佇列元素的陣列 - private var front = 0 // 佇列首指標,指向佇列首元素 - private var queSize = 0 // 雙向佇列長度 + private var nums: IntArray = IntArray(capacity) // 用於儲存雙向佇列元素的陣列 + private var front: Int = 0 // 佇列首指標,指向佇列首元素 + private var queSize: Int = 0 // 雙向佇列長度 /* 獲取雙向佇列的容量 */ fun capacity(): Int { @@ -3450,7 +3601,7 @@ comments: true return num } - /* 訪問佇列尾元素 */ + /* 佇列尾出列 */ fun popLast(): Int { val num = peekLast() queSize-- @@ -3490,7 +3641,109 @@ comments: true === "Ruby" ```ruby title="array_deque.rb" - [class]{ArrayDeque}-[func]{} + ### 基於環形陣列實現的雙向佇列 ### + class ArrayDeque + ### 獲取雙向佇列的長度 ### + attr_reader :size + + ### 建構子 ### + def initialize(capacity) + @nums = Array.new(capacity, 0) + @front = 0 + @size = 0 + end + + ### 獲取雙向佇列的容量 ### + def capacity + @nums.length + end + + ### 判斷雙向佇列是否為空 ### + def is_empty? + size.zero? + end + + ### 佇列首入列 ### + def push_first(num) + if size == capacity + puts '雙向佇列已滿' + return + end + + # 佇列首指標向左移動一位 + # 透過取餘操作實現 front 越過陣列頭部後回到尾部 + @front = index(@front - 1) + # 將 num 新增至佇列首 + @nums[@front] = num + @size += 1 + end + + ### 佇列尾入列 ### + def push_last(num) + if size == capacity + puts '雙向佇列已滿' + return + end + + # 計算佇列尾指標,指向佇列尾索引 + 1 + rear = index(@front + size) + # 將 num 新增至佇列尾 + @nums[rear] = num + @size += 1 + end + + ### 佇列首出列 ### + def pop_first + num = peek_first + # 佇列首指標向後移動一位 + @front = index(@front + 1) + @size -= 1 + num + end + + ### 佇列尾出列 ### + def pop_last + num = peek_last + @size -= 1 + num + end + + ### 訪問佇列首元素 ### + def peek_first + raise IndexError, '雙向佇列為空' if is_empty? + + @nums[@front] + end + + ### 訪問佇列尾元素 ### + def peek_last + raise IndexError, '雙向佇列為空' if is_empty? + + # 計算尾元素索引 + last = index(@front + size - 1) + @nums[last] + end + + ### 返回陣列用於列印 ### + def to_array + # 僅轉換有效長度範圍內的串列元素 + res = [] + for i in 0...size + res << @nums[index(@front + i)] + end + res + end + + private + + ### 計算環形陣列索引 ### + def index(i) + # 透過取餘操作實現陣列首尾相連 + # 當 i 越過陣列尾部後,回到頭部 + # 當 i 越過陣列頭部後,回到尾部 + (i + capacity) % capacity + end + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_stack_and_queue/queue.md b/zh-Hant/docs/chapter_stack_and_queue/queue.md index af3248c05..0d94f81a2 100755 --- a/zh-Hant/docs/chapter_stack_and_queue/queue.md +++ b/zh-Hant/docs/chapter_stack_and_queue/queue.md @@ -39,23 +39,23 @@ comments: true # 在 Python 中,我們一般將雙向佇列類別 deque 當作佇列使用 # 雖然 queue.Queue() 是純正的佇列類別,但不太好用,因此不推薦 que: deque[int] = deque() - + # 元素入列 que.append(1) que.append(3) que.append(2) que.append(5) que.append(4) - + # 訪問佇列首元素 front: int = que[0] - + # 元素出列 pop: int = que.popleft() - + # 獲取佇列的長度 size: int = len(que) - + # 判斷佇列是否為空 is_empty: bool = len(que) == 0 ``` @@ -65,23 +65,23 @@ comments: true ```cpp title="queue.cpp" /* 初始化佇列 */ queue queue; - + /* 元素入列 */ queue.push(1); queue.push(3); queue.push(2); queue.push(5); queue.push(4); - + /* 訪問佇列首元素 */ int front = queue.front(); - + /* 元素出列 */ queue.pop(); - + /* 獲取佇列的長度 */ int size = queue.size(); - + /* 判斷佇列是否為空 */ bool empty = queue.empty(); ``` @@ -91,23 +91,23 @@ comments: true ```java title="queue.java" /* 初始化佇列 */ Queue queue = new LinkedList<>(); - + /* 元素入列 */ queue.offer(1); queue.offer(3); queue.offer(2); queue.offer(5); queue.offer(4); - + /* 訪問佇列首元素 */ int peek = queue.peek(); - + /* 元素出列 */ int pop = queue.poll(); - + /* 獲取佇列的長度 */ int size = queue.size(); - + /* 判斷佇列是否為空 */ boolean isEmpty = queue.isEmpty(); ``` @@ -117,23 +117,23 @@ comments: true ```csharp title="queue.cs" /* 初始化佇列 */ Queue queue = new(); - + /* 元素入列 */ queue.Enqueue(1); queue.Enqueue(3); queue.Enqueue(2); queue.Enqueue(5); queue.Enqueue(4); - + /* 訪問佇列首元素 */ int peek = queue.Peek(); - + /* 元素出列 */ int pop = queue.Dequeue(); - + /* 獲取佇列的長度 */ int size = queue.Count; - + /* 判斷佇列是否為空 */ bool isEmpty = queue.Count == 0; ``` @@ -144,24 +144,24 @@ comments: true /* 初始化佇列 */ // 在 Go 中,將 list 作為佇列來使用 queue := list.New() - + /* 元素入列 */ queue.PushBack(1) queue.PushBack(3) queue.PushBack(2) queue.PushBack(5) queue.PushBack(4) - + /* 訪問佇列首元素 */ peek := queue.Front() - + /* 元素出列 */ pop := queue.Front() queue.Remove(pop) - + /* 獲取佇列的長度 */ size := queue.Len() - + /* 判斷佇列是否為空 */ isEmpty := queue.Len() == 0 ``` @@ -172,24 +172,24 @@ comments: true /* 初始化佇列 */ // Swift 沒有內建的佇列類別,可以把 Array 當作佇列來使用 var queue: [Int] = [] - + /* 元素入列 */ queue.append(1) queue.append(3) queue.append(2) queue.append(5) queue.append(4) - + /* 訪問佇列首元素 */ let peek = queue.first! - + /* 元素出列 */ // 由於是陣列,因此 removeFirst 的複雜度為 O(n) let pool = queue.removeFirst() - + /* 獲取佇列的長度 */ let size = queue.count - + /* 判斷佇列是否為空 */ let isEmpty = queue.isEmpty ``` @@ -200,24 +200,24 @@ comments: true /* 初始化佇列 */ // JavaScript 沒有內建的佇列,可以把 Array 當作佇列來使用 const queue = []; - + /* 元素入列 */ queue.push(1); queue.push(3); queue.push(2); queue.push(5); queue.push(4); - + /* 訪問佇列首元素 */ const peek = queue[0]; - + /* 元素出列 */ // 底層是陣列,因此 shift() 方法的時間複雜度為 O(n) const pop = queue.shift(); - + /* 獲取佇列的長度 */ const size = queue.length; - + /* 判斷佇列是否為空 */ const empty = queue.length === 0; ``` @@ -226,26 +226,26 @@ comments: true ```typescript title="queue.ts" /* 初始化佇列 */ - // TypeScript 沒有內建的佇列,可以把 Array 當作佇列來使用 + // TypeScript 沒有內建的佇列,可以把 Array 當作佇列來使用 const queue: number[] = []; - + /* 元素入列 */ queue.push(1); queue.push(3); queue.push(2); queue.push(5); queue.push(4); - + /* 訪問佇列首元素 */ const peek = queue[0]; - + /* 元素出列 */ // 底層是陣列,因此 shift() 方法的時間複雜度為 O(n) const pop = queue.shift(); - + /* 獲取佇列的長度 */ const size = queue.length; - + /* 判斷佇列是否為空 */ const empty = queue.length === 0; ``` @@ -317,23 +317,23 @@ comments: true ```kotlin title="queue.kt" /* 初始化佇列 */ val queue = LinkedList() - + /* 元素入列 */ queue.offer(1) queue.offer(3) queue.offer(2) queue.offer(5) queue.offer(4) - + /* 訪問佇列首元素 */ val peek = queue.peek() - + /* 元素出列 */ val pop = queue.poll() - + /* 獲取佇列的長度 */ val size = queue.size - + /* 判斷佇列是否為空 */ val isEmpty = queue.isEmpty() ``` @@ -341,7 +341,29 @@ comments: true === "Ruby" ```ruby title="queue.rb" + # 初始化佇列 + # Ruby 內建的佇列(Thread::Queue) 沒有 peek 和走訪方法,可以把 Array 當作佇列來使用 + queue = [] + # 元素入列 + queue.push(1) + queue.push(3) + queue.push(2) + queue.push(5) + queue.push(4) + + # 訪問佇列元素 + peek = queue.first + + # 元素出列 + # 清注意,由於是陣列,Array#shift 方法時間複雜度為 O(n) + pop = queue.shift + + # 獲取佇列的長度 + size = queue.length + + # 判斷佇列是否為空 + is_empty = queue.empty? ``` === "Zig" @@ -352,8 +374,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 5.2.2   佇列實現 @@ -1206,7 +1228,7 @@ comments: true /* 訪問佇列首元素 */ fun peek(): Int { if (isEmpty()) throw IndexOutOfBoundsException() - return front!!.value + return front!!._val } /* 將鏈結串列轉化為 Array 並返回 */ @@ -1214,7 +1236,7 @@ comments: true var node = front val res = IntArray(size()) for (i in res.indices) { - res[i] = node!!.value + res[i] = node!!._val node = node.next } return res @@ -1225,7 +1247,68 @@ comments: true === "Ruby" ```ruby title="linkedlist_queue.rb" - [class]{LinkedListQueue}-[func]{} + ### 基於鏈結串列頭現的佇列 ### + class LinkedListQueue + ### 獲取佇列的長度 ### + attr_reader :size + + ### 建構子 ### + def initialize + @front = nil # 頭節點 front + @rear = nil # 尾節點 rear + @size = 0 + end + + ### 判斷佇列是否為空 ### + def is_empty? + @front.nil? + end + + ### 入列 ### + def push(num) + # 在尾節點後新增 num + node = ListNode.new(num) + + # 如果佇列為空,則令頭,尾節點都指向該節點 + if @front.nil? + @front = node + @rear = node + # 如果佇列不為空,則令該節點新增到尾節點後 + else + @rear.next = node + @rear = node + end + + @size += 1 + end + + ### 出列 ### + def pop + num = peek + # 刪除頭節點 + @front = @front.next + @size -= 1 + num + end + + ### 訪問佇列首元素 ### + def peek + raise IndexError, '佇列為空' if is_empty? + + @front.val + end + + ### 將鏈結串列為 Array 並返回 ### + def to_array + queue = [] + temp = @front + while temp + queue << temp.val + temp = temp.next + end + queue + end + end ``` === "Zig" @@ -1319,8 +1402,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   基於陣列的實現 @@ -2144,9 +2227,9 @@ comments: true ```kotlin title="array_queue.kt" /* 基於環形陣列實現的佇列 */ class ArrayQueue(capacity: Int) { - private val nums = IntArray(capacity) // 用於儲存佇列元素的陣列 - private var front = 0 // 佇列首指標,指向佇列首元素 - private var queSize = 0 // 佇列長度 + private val nums: IntArray = IntArray(capacity) // 用於儲存佇列元素的陣列 + private var front: Int = 0 // 佇列首指標,指向佇列首元素 + private var queSize: Int = 0 // 佇列長度 /* 獲取佇列的容量 */ fun capacity(): Int { @@ -2211,7 +2294,69 @@ comments: true === "Ruby" ```ruby title="array_queue.rb" - [class]{ArrayQueue}-[func]{} + ### 基於環形陣列實現的佇列 ### + class ArrayQueue + ### 獲取佇列的長度 ### + attr_reader :size + + ### 建構子 ### + def initialize(size) + @nums = Array.new(size, 0) # 用於儲存佇列元素的陣列 + @front = 0 # 佇列首指標,指向佇列首元素 + @size = 0 # 佇列長度 + end + + ### 獲取佇列的容量 ### + def capacity + @nums.length + end + + ### 判斷佇列是否為空 ### + def is_empty? + size.zero? + end + + ### 入列 ### + def push(num) + raise IndexError, '佇列已滿' if size == capacity + + # 計算佇列尾指標,指向佇列尾索引 + 1 + # 透過取餘操作實現 rear 越過陣列尾部後回到頭部 + rear = (@front + size) % capacity + # 將 num 新增至佇列尾 + @nums[rear] = num + @size += 1 + end + + ### 出列 ### + def pop + num = peek + # 佇列首指標向後移動一位,若越過尾部,則返回到陣列頭部 + @front = (@front + 1) % capacity + @size -= 1 + num + end + + ### 訪問佇列首元素 ### + def peek + raise IndexError, '佇列為空' if is_empty? + + @nums[@front] + end + + ### 返回串列用於列印 ### + def to_array + res = Array.new(size, 0) + j = @front + + for i in 0...size + res[i] = @nums[j % capacity] + j += 1 + end + + res + end + end ``` === "Zig" @@ -2308,8 +2453,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 以上實現的佇列仍然具有侷限性:其長度不可變。然而,這個問題不難解決,我們可以將陣列替換為動態陣列,從而引入擴容機制。有興趣的讀者可以嘗試自行實現。 diff --git a/zh-Hant/docs/chapter_stack_and_queue/stack.md b/zh-Hant/docs/chapter_stack_and_queue/stack.md index dc723fb99..87f2c58d4 100755 --- a/zh-Hant/docs/chapter_stack_and_queue/stack.md +++ b/zh-Hant/docs/chapter_stack_and_queue/stack.md @@ -36,25 +36,25 @@ comments: true ```python title="stack.py" # 初始化堆疊 - # Python 沒有內建的堆疊類別,可以把 list 當作堆疊來使用 + # Python 沒有內建的堆疊類別,可以把 list 當作堆疊來使用 stack: list[int] = [] - + # 元素入堆疊 stack.append(1) stack.append(3) stack.append(2) stack.append(5) stack.append(4) - + # 訪問堆疊頂元素 peek: int = stack[-1] - + # 元素出堆疊 pop: int = stack.pop() - + # 獲取堆疊的長度 size: int = len(stack) - + # 判斷是否為空 is_empty: bool = len(stack) == 0 ``` @@ -64,23 +64,23 @@ comments: true ```cpp title="stack.cpp" /* 初始化堆疊 */ stack stack; - + /* 元素入堆疊 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); - + /* 訪問堆疊頂元素 */ int top = stack.top(); - + /* 元素出堆疊 */ stack.pop(); // 無返回值 - + /* 獲取堆疊的長度 */ int size = stack.size(); - + /* 判斷是否為空 */ bool empty = stack.empty(); ``` @@ -116,23 +116,23 @@ comments: true ```csharp title="stack.cs" /* 初始化堆疊 */ Stack stack = new(); - + /* 元素入堆疊 */ stack.Push(1); stack.Push(3); stack.Push(2); stack.Push(5); stack.Push(4); - + /* 訪問堆疊頂元素 */ int peek = stack.Peek(); - + /* 元素出堆疊 */ int pop = stack.Pop(); - + /* 獲取堆疊的長度 */ int size = stack.Count; - + /* 判斷是否為空 */ bool isEmpty = stack.Count == 0; ``` @@ -143,24 +143,24 @@ comments: true /* 初始化堆疊 */ // 在 Go 中,推薦將 Slice 當作堆疊來使用 var stack []int - + /* 元素入堆疊 */ stack = append(stack, 1) stack = append(stack, 3) stack = append(stack, 2) stack = append(stack, 5) stack = append(stack, 4) - + /* 訪問堆疊頂元素 */ peek := stack[len(stack)-1] - + /* 元素出堆疊 */ pop := stack[len(stack)-1] stack = stack[:len(stack)-1] - + /* 獲取堆疊的長度 */ size := len(stack) - + /* 判斷是否為空 */ isEmpty := len(stack) == 0 ``` @@ -171,23 +171,23 @@ comments: true /* 初始化堆疊 */ // Swift 沒有內建的堆疊類別,可以把 Array 當作堆疊來使用 var stack: [Int] = [] - + /* 元素入堆疊 */ stack.append(1) stack.append(3) stack.append(2) stack.append(5) stack.append(4) - + /* 訪問堆疊頂元素 */ let peek = stack.last! - + /* 元素出堆疊 */ let pop = stack.removeLast() - + /* 獲取堆疊的長度 */ let size = stack.count - + /* 判斷是否為空 */ let isEmpty = stack.isEmpty ``` @@ -196,25 +196,25 @@ comments: true ```javascript title="stack.js" /* 初始化堆疊 */ - // JavaScript 沒有內建的堆疊類別,可以把 Array 當作堆疊來使用 + // JavaScript 沒有內建的堆疊類別,可以把 Array 當作堆疊來使用 const stack = []; - + /* 元素入堆疊 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); - + /* 訪問堆疊頂元素 */ const peek = stack[stack.length-1]; - + /* 元素出堆疊 */ const pop = stack.pop(); - + /* 獲取堆疊的長度 */ const size = stack.length; - + /* 判斷是否為空 */ const is_empty = stack.length === 0; ``` @@ -223,25 +223,25 @@ comments: true ```typescript title="stack.ts" /* 初始化堆疊 */ - // TypeScript 沒有內建的堆疊類別,可以把 Array 當作堆疊來使用 + // TypeScript 沒有內建的堆疊類別,可以把 Array 當作堆疊來使用 const stack: number[] = []; - + /* 元素入堆疊 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); - + /* 訪問堆疊頂元素 */ const peek = stack[stack.length - 1]; - + /* 元素出堆疊 */ const pop = stack.pop(); - + /* 獲取堆疊的長度 */ const size = stack.length; - + /* 判斷是否為空 */ const is_empty = stack.length === 0; ``` @@ -311,23 +311,23 @@ comments: true ```kotlin title="stack.kt" /* 初始化堆疊 */ val stack = Stack() - + /* 元素入堆疊 */ stack.push(1) stack.push(3) stack.push(2) stack.push(5) stack.push(4) - + /* 訪問堆疊頂元素 */ val peek = stack.peek() - + /* 元素出堆疊 */ val pop = stack.pop() - + /* 獲取堆疊的長度 */ val size = stack.size - + /* 判斷是否為空 */ val isEmpty = stack.isEmpty() ``` @@ -335,7 +335,28 @@ comments: true === "Ruby" ```ruby title="stack.rb" + # 初始化堆疊 + # Ruby 沒有內建的堆疊類別,可以把 Array 當作堆疊來使用 + stack = [] + # 元素入堆疊 + stack << 1 + stack << 3 + stack << 2 + stack << 5 + stack << 4 + + # 訪問堆疊頂元素 + peek = stack.last + + # 元素出堆疊 + pop = stack.pop + + # 獲取堆疊的長度 + size = stack.length + + # 判斷是否為空 + is_empty = stack.empty? ``` === "Zig" @@ -346,8 +367,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 5.1.2   堆疊的實現 @@ -1078,7 +1099,7 @@ comments: true /* 訪問堆疊頂元素 */ fun peek(): Int? { if (isEmpty()) throw IndexOutOfBoundsException() - return stackPeek?.value + return stackPeek?._val } /* 將 List 轉化為 Array 並返回 */ @@ -1086,7 +1107,7 @@ comments: true var node = stackPeek val res = IntArray(size()) for (i in res.size - 1 downTo 0) { - res[i] = node?.value!! + res[i] = node?._val!! node = node.next } return res @@ -1097,7 +1118,54 @@ comments: true === "Ruby" ```ruby title="linkedlist_stack.rb" - [class]{LinkedListStack}-[func]{} + ### 基於鏈結串列實現的堆疊 ### + class LinkedListStack + attr_reader :size + + ### 建構子 ### + def initialize + @size = 0 + end + + ### 判斷堆疊是否為空 ### + def is_empty? + @peek.nil? + end + + ### 入堆疊 ### + def push(val) + node = ListNode.new(val) + node.next = @peek + @peek = node + @size += 1 + end + + ### 出堆疊 ### + def pop + num = peek + @peek = @peek.next + @size -= 1 + num + end + + ### 訪問堆疊頂元素 ### + def peek + raise IndexError, '堆疊為空' if is_empty? + + @peek.val + end + + ### 將鏈結串列轉化為 Array 並反回 ### + def to_array + arr = [] + node = @peek + while node + arr << node.val + node = node.next + end + arr.reverse + end + end ``` === "Zig" @@ -1180,8 +1248,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   基於陣列的實現 @@ -1738,7 +1806,7 @@ comments: true /* 基於陣列實現的堆疊 */ class ArrayStack { // 初始化串列(動態陣列) - private val stack = ArrayList() + private val stack = mutableListOf() /* 獲取堆疊的長度 */ fun size(): Int { @@ -1769,7 +1837,7 @@ comments: true /* 將 List 轉化為 Array 並返回 */ fun toArray(): Array { - return stack.toArray() + return stack.toTypedArray() } } ``` @@ -1777,7 +1845,47 @@ comments: true === "Ruby" ```ruby title="array_stack.rb" - [class]{ArrayStack}-[func]{} + ### 基於陣列實現的堆疊 ### + class ArrayStack + ### 建構子 ### + def initialize + @stack = [] + end + + ### 獲取堆疊的長度 ### + def size + @stack.length + end + + ### 判斷堆疊是否為空 ### + def is_empty? + @stack.empty? + end + + ### 入堆疊 ### + def push(item) + @stack << item + end + + ### 出堆疊 ### + def pop + raise IndexError, '堆疊為空' if is_empty? + + @stack.pop + end + + ### 訪問堆疊頂元素 ### + def peek + raise IndexError, '堆疊為空' if is_empty? + + @stack.last + end + + ### 返回串列用於列印 ### + def to_array + @stack + end + end ``` === "Zig" @@ -1840,8 +1948,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 5.1.3   兩種實現對比 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 02a94980f..acb158e5e 100644 --- a/zh-Hant/docs/chapter_tree/array_representation_of_tree.md +++ b/zh-Hant/docs/chapter_tree/array_representation_of_tree.md @@ -1172,15 +1172,15 @@ comments: true === "Kotlin" ```kotlin title="array_binary_tree.kt" - /* 陣列表示下的二元樹類別 */ - class ArrayBinaryTree(val tree: List) { + /* 建構子 */ + class ArrayBinaryTree(val tree: MutableList) { /* 串列容量 */ fun size(): Int { return tree.size } /* 獲取索引為 i 節點的值 */ - fun value(i: Int): Int? { + fun _val(i: Int): Int? { // 若索引越界,則返回 null ,代表空位 if (i < 0 || i >= size()) return null return tree[i] @@ -1202,11 +1202,12 @@ comments: true } /* 層序走訪 */ - fun levelOrder(): List { - val res = ArrayList() + fun levelOrder(): MutableList { + val res = mutableListOf() // 直接走訪陣列 for (i in 0..) { // 若為空位,則返回 - if (value(i) == null) return + if (_val(i) == null) + return // 前序走訪 - if ("pre" == order) res.add(value(i)) + if ("pre" == order) + res.add(_val(i)) dfs(left(i), order, res) // 中序走訪 - if ("in" == order) res.add(value(i)) + if ("in" == order) + res.add(_val(i)) dfs(right(i), order, res) // 後序走訪 - if ("post" == order) res.add(value(i)) + if ("post" == order) + res.add(_val(i)) } /* 前序走訪 */ - fun preOrder(): List { - val res = ArrayList() + fun preOrder(): MutableList { + val res = mutableListOf() dfs(0, "pre", res) return res } /* 中序走訪 */ - fun inOrder(): List { - val res = ArrayList() + fun inOrder(): MutableList { + val res = mutableListOf() dfs(0, "in", res) return res } /* 後序走訪 */ - fun postOrder(): List { - val res = ArrayList() + fun postOrder(): MutableList { + val res = mutableListOf() dfs(0, "post", res) return res } @@ -1262,8 +1267,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ## 7.3.3   優點與侷限性 diff --git a/zh-Hant/docs/chapter_tree/avl_tree.md b/zh-Hant/docs/chapter_tree/avl_tree.md index 9adb6432c..707f45d56 100644 --- a/zh-Hant/docs/chapter_tree/avl_tree.md +++ b/zh-Hant/docs/chapter_tree/avl_tree.md @@ -448,7 +448,7 @@ AVL 樹既是二元搜尋樹,也是平衡二元樹,同時滿足這兩類二 /* 更新節點高度 */ fun updateHeight(node: TreeNode?) { // 節點高度等於最高子樹高度 + 1 - node?.height = (max(height(node?.left).toDouble(), height(node?.right).toDouble()) + 1).toInt() + node?.height = max(height(node?.left), height(node?.right)) + 1 } ``` @@ -2012,20 +2012,22 @@ AVL 樹的節點插入操作與二元搜尋樹在主體上類似。唯一的區 ```kotlin title="avl_tree.kt" /* 插入節點 */ - fun insert(value: Int) { - root = insertHelper(root, value) + fun insert(_val: Int) { + root = insertHelper(root, _val) } /* 遞迴插入節點(輔助方法) */ - fun insertHelper(n: TreeNode?, value: Int): TreeNode { + fun insertHelper(n: TreeNode?, _val: Int): TreeNode { if (n == null) - return TreeNode(value) + return TreeNode(_val) var node = n /* 1. 查詢插入位置並插入節點 */ - if (value < node.value) node.left = insertHelper(node.left, value) - else if (value > node.value) node.right = insertHelper(node.right, value) - else return node // 重複節點不插入,直接返回 - + if (_val < node._val) + node.left = insertHelper(node.left, _val) + else if (_val > node._val) + node.right = insertHelper(node.right, _val) + else + return node // 重複節點不插入,直接返回 updateHeight(node) // 更新節點高度 /* 2. 執行旋轉操作,使該子樹重新恢復平衡 */ node = rotate(node) @@ -2593,30 +2595,38 @@ AVL 樹的節點插入操作與二元搜尋樹在主體上類似。唯一的區 ```kotlin title="avl_tree.kt" /* 刪除節點 */ - fun remove(value: Int) { - root = removeHelper(root, value) + fun remove(_val: Int) { + root = removeHelper(root, _val) } /* 遞迴刪除節點(輔助方法) */ - fun removeHelper(n: TreeNode?, value: Int): TreeNode? { + fun removeHelper(n: TreeNode?, _val: Int): TreeNode? { var node = n ?: return null /* 1. 查詢節點並刪除 */ - if (value < node.value) node.left = removeHelper(node.left, value) - else if (value > node.value) node.right = removeHelper(node.right, value) + if (_val < node._val) + node.left = removeHelper(node.left, _val) + else if (_val > node._val) + node.right = removeHelper(node.right, _val) else { if (node.left == null || node.right == null) { - val child = if (node.left != null) node.left else node.right + val child = if (node.left != null) + node.left + else + node.right // 子節點數量 = 0 ,直接刪除 node 並返回 - if (child == null) return null - else node = child + if (child == null) + return null + // 子節點數量 = 1 ,直接刪除 node + else + node = child } else { // 子節點數量 = 2 ,則將中序走訪的下個節點刪除,並用該節點替換當前節點 var temp = node.right while (temp!!.left != null) { temp = temp.left } - node.right = removeHelper(node.right, temp.value) - node.value = temp.value + node.right = removeHelper(node.right, temp._val) + node._val = temp._val } } updateHeight(node) // 更新節點高度 diff --git a/zh-Hant/docs/chapter_tree/binary_search_tree.md b/zh-Hant/docs/chapter_tree/binary_search_tree.md index 1f1a9ba3f..2ca6c70cf 100755 --- a/zh-Hant/docs/chapter_tree/binary_search_tree.md +++ b/zh-Hant/docs/chapter_tree/binary_search_tree.md @@ -299,11 +299,14 @@ comments: true // 迴圈查詢,越過葉節點後跳出 while (cur != null) { // 目標節點在 cur 的右子樹中 - cur = if (cur.value < num) cur.right + cur = if (cur._val < num) + cur.right // 目標節點在 cur 的左子樹中 - else if (cur.value > num) cur.left + else if (cur._val > num) + cur.left // 找到目標節點,跳出迴圈 - else break + else + break } // 返回目標節點 return cur @@ -342,8 +345,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   插入節點 @@ -748,17 +751,22 @@ comments: true // 迴圈查詢,越過葉節點後跳出 while (cur != null) { // 找到重複節點,直接返回 - if (cur.value == num) return + if (cur._val == num) + return pre = cur // 插入位置在 cur 的右子樹中 - cur = if (cur.value < num) cur.right + cur = if (cur._val < num) + cur.right // 插入位置在 cur 的左子樹中 - else cur.left + else + cur.left } // 插入節點 val node = TreeNode(num) - if (pre?.value!! < num) pre.right = node - else pre.left = node + if (pre?._val!! < num) + pre.right = node + else + pre.left = node } ``` @@ -806,8 +814,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ 與查詢節點相同,插入節點使用 $O(\log n)$ 時間。 @@ -1482,29 +1490,39 @@ comments: true /* 刪除節點 */ fun remove(num: Int) { // 若樹為空,直接提前返回 - if (root == null) return + if (root == null) + return var cur = root var pre: TreeNode? = null // 迴圈查詢,越過葉節點後跳出 while (cur != null) { // 找到待刪除節點,跳出迴圈 - if (cur.value == num) break + if (cur._val == num) + break pre = cur // 待刪除節點在 cur 的右子樹中 - cur = if (cur.value < num) cur.right + cur = if (cur._val < num) + cur.right // 待刪除節點在 cur 的左子樹中 - else cur.left + else + cur.left } // 若無待刪除節點,則直接返回 - if (cur == null) return + if (cur == null) + return // 子節點數量 = 0 or 1 if (cur.left == null || cur.right == null) { // 當子節點數量 = 0 / 1 時, child = null / 該子節點 - val child = if (cur.left != null) cur.left else cur.right + val child = if (cur.left != null) + cur.left + else + cur.right // 刪除節點 cur if (cur != root) { - if (pre!!.left == cur) pre.left = child - else pre.right = child + if (pre!!.left == cur) + pre.left = child + else + pre.right = child } else { // 若刪除節點為根節點,則重新指定根節點 root = child @@ -1517,9 +1535,9 @@ comments: true tmp = tmp.left } // 遞迴刪除節點 tmp - remove(tmp.value) + remove(tmp._val) // 用 tmp 覆蓋 cur - cur.value = tmp.value + cur._val = tmp._val } } ``` @@ -1582,8 +1600,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 4.   中序走訪有序 diff --git a/zh-Hant/docs/chapter_tree/binary_tree.md b/zh-Hant/docs/chapter_tree/binary_tree.md index efb244f31..f7441717a 100644 --- a/zh-Hant/docs/chapter_tree/binary_tree.md +++ b/zh-Hant/docs/chapter_tree/binary_tree.md @@ -451,8 +451,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   插入與刪除節點 @@ -616,8 +616,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ !!! note diff --git a/zh-Hant/docs/chapter_tree/binary_tree_traversal.md b/zh-Hant/docs/chapter_tree/binary_tree_traversal.md index ca2cf11ad..dbd57e46f 100755 --- a/zh-Hant/docs/chapter_tree/binary_tree_traversal.md +++ b/zh-Hant/docs/chapter_tree/binary_tree_traversal.md @@ -229,7 +229,7 @@ comments: true fn level_order(root: &Rc>) -> Vec { // 初始化佇列,加入根節點 let mut que = VecDeque::new(); - que.push_back(Rc::clone(&root)); + que.push_back(root.clone()); // 初始化一個串列,用於儲存走訪序列 let mut vec = Vec::new(); @@ -237,10 +237,10 @@ comments: true // 隊列出隊 vec.push(node.borrow().val); // 儲存節點值 if let Some(left) = node.borrow().left.as_ref() { - que.push_back(Rc::clone(left)); // 左子節點入列 + que.push_back(left.clone()); // 左子節點入列 } if let Some(right) = node.borrow().right.as_ref() { - que.push_back(Rc::clone(right)); // 右子節點入列 + que.push_back(right.clone()); // 右子節點入列 }; } vec @@ -302,13 +302,14 @@ comments: true val queue = LinkedList() queue.add(root) // 初始化一個串列,用於儲存走訪序列 - val list = ArrayList() - while (!queue.isEmpty()) { - val node = queue.poll() // 隊列出隊 - list.add(node?.value!!) // 儲存節點值 - if (node.left != null) queue.offer(node.left) // 左子節點入列 - - if (node.right != null) queue.offer(node.right) // 右子節點入列 + val list = mutableListOf() + while (queue.isNotEmpty()) { + val node = queue.poll() // 隊列出隊 + list.add(node?._val!!) // 儲存節點值 + if (node.left != null) + queue.offer(node.left) // 左子節點入列 + if (node.right != null) + queue.offer(node.right) // 右子節點入列 } return list } @@ -354,8 +355,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ ### 2.   複雜度分析 @@ -689,8 +690,8 @@ comments: true if let Some(node) = root { // 訪問優先順序:根節點 -> 左子樹 -> 右子樹 result.push(node.borrow().val); - result.append(&mut pre_order(node.borrow().left.as_ref())); - result.append(&mut pre_order(node.borrow().right.as_ref())); + result.extend(pre_order(node.borrow().left.as_ref())); + result.extend(pre_order(node.borrow().right.as_ref())); } result } @@ -701,9 +702,9 @@ comments: true if let Some(node) = root { // 訪問優先順序:左子樹 -> 根節點 -> 右子樹 - result.append(&mut in_order(node.borrow().left.as_ref())); + result.extend(in_order(node.borrow().left.as_ref())); result.push(node.borrow().val); - result.append(&mut in_order(node.borrow().right.as_ref())); + result.extend(in_order(node.borrow().right.as_ref())); } result } @@ -714,8 +715,8 @@ comments: true if let Some(node) = root { // 訪問優先順序:左子樹 -> 右子樹 -> 根節點 - result.append(&mut post_order(node.borrow().left.as_ref())); - result.append(&mut post_order(node.borrow().right.as_ref())); + result.extend(post_order(node.borrow().left.as_ref())); + result.extend(post_order(node.borrow().right.as_ref())); result.push(node.borrow().val); } result @@ -763,7 +764,7 @@ comments: true fun preOrder(root: TreeNode?) { if (root == null) return // 訪問優先順序:根節點 -> 左子樹 -> 右子樹 - list.add(root.value) + list.add(root._val) preOrder(root.left) preOrder(root.right) } @@ -773,7 +774,7 @@ comments: true if (root == null) return // 訪問優先順序:左子樹 -> 根節點 -> 右子樹 inOrder(root.left) - list.add(root.value) + list.add(root._val) inOrder(root.right) } @@ -783,7 +784,7 @@ comments: true // 訪問優先順序:左子樹 -> 右子樹 -> 根節點 postOrder(root.left) postOrder(root.right) - list.add(root.value) + list.add(root._val) } ``` @@ -830,8 +831,8 @@ comments: true ??? pythontutor "視覺化執行" -
- +
+ !!! tip