diff --git a/.gitignore b/.gitignore index b7c6872d3..77473d34f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.png *.jpg *.gif +*.pdf \ No newline at end of file diff --git a/docs/chapter_appendix/installation.md b/docs/chapter_appendix/installation.md index 6f6c4497f..4c5fbe54b 100644 --- a/docs/chapter_appendix/installation.md +++ b/docs/chapter_appendix/installation.md @@ -56,16 +56,21 @@ VS Code 拥有强大的扩展包生态系统,支持大多数编程语言的运 ### 7.   JavaScript 环境 -1. 下载并安装 [node.js](https://nodejs.org/en/) 。 -2. 在 VS Code 的插件市场中搜索 `javascript` ,安装 JavaScript (ES6) code snippets 。 -3. (可选)在 VS Code 的插件市场中搜索 `Prettier` ,安装代码格式化工具。 +1. 下载并安装 [Node.js](https://nodejs.org/en/) 。 +2. (可选)在 VS Code 的插件市场中搜索 `Prettier` ,安装代码格式化工具。 -### 8.   Dart 环境 +### 8.   TypeScript 环境 + +1. 同 JavaScript 环境安装步骤。 +2. 安装 [TypeScript Execute (tsx)](https://github.com/privatenumber/tsx?tab=readme-ov-file#global-installation) 。 +3. 在 VS Code 的插件市场中搜索 `typescript` ,安装 [Pretty TypeScript Errors](https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors) 。 + +### 9.   Dart 环境 1. 下载并安装 [Dart](https://dart.dev/get-dart) 。 2. 在 VS Code 的插件市场中搜索 `dart` ,安装 [Dart](https://marketplace.visualstudio.com/items?itemName=Dart-Code.dart-code) 。 -### 9.   Rust 环境 +### 10.   Rust 环境 1. 下载并安装 [Rust](https://www.rust-lang.org/tools/install) 。 2. 在 VS Code 的插件市场中搜索 `rust` ,安装 [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) 。 diff --git a/docs/chapter_paperbook/index.md b/docs/chapter_paperbook/index.md index fe1ecd1ad..190c38e62 100644 --- a/docs/chapter_paperbook/index.md +++ b/docs/chapter_paperbook/index.md @@ -36,17 +36,18 @@ status: new - 采用全彩印刷,能够原汁原味地发挥出本书“动画图解”的优势。 - 考究纸张材质,既保证色彩高度还原,也保留纸质书特有的质感。 +- 纸质版比网页版的格式更加规范,例如图中的公式使用斜体。 - 在不提升定价的前提下,附赠思维导图折页、书签。 - 纸质书、网页版、PDF 版内容同步,随意切换阅读。 !!! tip - 由于纸质书和网页版的同步成本较大,因此可能会有一些细节上的不同,请您见谅! + 由于纸质书和网页版的同步难度较大,因此可能会有一些细节上的不同,请您见谅! 当然,纸质书也有一些值得大家入手前考虑的地方: -- 使用 Python 语言,可能不匹配你的主语言(也许可以趁此机会练习 Python)。 -- 全彩印刷虽然大幅提升了阅读体验,但价格会比黑白印刷高一些。 +- 使用 Python 语言,可能不匹配你的主语言(可以把 Python 看作伪代码,重在理解思路)。 +- 全彩印刷虽然大幅提升了图解和代码的阅读体验,但价格会比黑白印刷高一些。 !!! tip diff --git a/docs/chapter_tree/array_representation_of_tree.md b/docs/chapter_tree/array_representation_of_tree.md index d3bdf85a9..53db5c268 100644 --- a/docs/chapter_tree/array_representation_of_tree.md +++ b/docs/chapter_tree/array_representation_of_tree.md @@ -1256,7 +1256,87 @@ comments: true === "Ruby" ```ruby title="array_binary_tree.rb" - [class]{ArrayBinaryTree}-[func]{} + ### 数组表示下的二叉树类 ### + class ArrayBinaryTree + ### 构造方法 ### + def initialize(arr) + @tree = arr.to_a + end + + ### 列表容量 ### + def size + @tree.length + end + + ### 获取索引为 i 节点的值 ### + def val(i) + # 若索引越界,则返回 nil ,代表空位 + return if i < 0 || i >= size + + @tree[i] + end + + ### 获取索引为 i 节点的左子节点的索引 ### + def left(i) + 2 * i + 1 + end + + ### 获取索引为 i 节点的右子节点的索引 ### + def right(i) + 2 * i + 2 + end + + ### 获取索引为 i 节点的父节点的索引 ### + def parent(i) + (i - 1) / 2 + end + + ### 层序遍历 ### + def level_order + @res = [] + + # 直接遍历数组 + for i in 0...size + @res << val(i) unless val(i).nil? + end + + @res + end + + ### 深度优先遍历 ### + def dfs(i, order) + return if val(i).nil? + # 前序遍历 + @res << val(i) if order == :pre + dfs(left(i), order) + # 中序遍历 + @res << val(i) if order == :in + dfs(right(i), order) + # 后序遍历 + @res << val(i) if order == :post + end + + ### 前序遍历 ### + def pre_order + @res = [] + dfs(0, :pre) + @res + end + + ### 中序遍历 ### + def in_order + @res = [] + dfs(0, :in) + @res + end + + ### 后序遍历 ### + def post_order + @res = [] + dfs(0, :post) + @res + end + end ``` === "Zig" diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index 7ad343062..a2def6993 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -455,9 +455,19 @@ AVL 树既是二叉搜索树,也是平衡二叉树,同时满足这两类二 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{height} + ### 获取节点高度 ### + def height(node) + # 空节点高度为 -1 ,叶节点高度为 0 + return node.height unless node.nil? - [class]{AVLTree}-[func]{update_height} + -1 + end + + ### 更新节点高度 ### + def update_height(node) + # 节点高度等于最高子树高度 + 1 + node.height = [height(node.left), height(node.right)].max + 1 + end ``` === "Zig" @@ -638,7 +648,14 @@ AVL 树既是二叉搜索树,也是平衡二叉树,同时满足这两类二 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{balance_factor} + ### 获取平衡因子 ### + def balance_factor(node) + # 空节点平衡因子为 0 + return 0 if node.nil? + + # 节点平衡因子 = 左子树高度 - 右子树高度 + height(node.left) - height(node.right) + end ``` === "Zig" @@ -913,7 +930,19 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{right_rotate} + ### 右旋操作 ### + def right_rotate(node) + child = node.left + grand_child = child.right + # 以 child 为原点,将 node 向右旋转 + child.right = node + node.left = grand_child + # 更新节点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + child + end ``` === "Zig" @@ -1174,7 +1203,19 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{left_rotate} + ### 左旋操作 ### + def left_rotate(node) + child = node.right + grand_child = child.left + # 以 child 为原点,将 node 向左旋转 + child.left = node + node.right = grand_child + # 更新节点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + child + end ``` === "Zig" @@ -1648,7 +1689,34 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{rotate} + ### 执行旋转操作,使该子树重新恢复平衡 ### + def rotate(node) + # 获取节点 node 的平衡因子 + balance_factor = balance_factor(node) + # 左遍树 + if balance_factor > 1 + if balance_factor(node.left) >= 0 + # 右旋 + return right_rotate(node) + else + # 先左旋后右旋 + node.left = left_rotate(node.left) + return right_rotate(node) + end + # 右遍树 + elsif balance_factor < -1 + if balance_factor(node.right) <= 0 + # 左旋 + return left_rotate(node) + else + # 先右旋后左旋 + node.right = right_rotate(node.right) + return left_rotate(node) + end + end + # 平衡树,无须旋转,直接返回 + node + end ``` === "Zig" @@ -2039,9 +2107,28 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{insert} - - [class]{AVLTree}-[func]{insert_helper} + ### 插入节点 ### + def insert(val) + @root = insert_helper(@root, val) + end + + ### 递归插入节点(辅助方法)### + def insert_helper(node, val) + return TreeNode.new(val) if node.nil? + # 1. 查找插入位置并插入节点 + if val < node.val + node.left = insert_helper(node.left, val) + elsif val > node.val + node.right = insert_helper(node.right, val) + else + # 重复节点不插入,直接返回 + return node + end + # 更新节点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + rotate(node) + end ``` === "Zig" @@ -2640,9 +2727,41 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区 === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{remove} - - [class]{AVLTree}-[func]{remove_helper} + ### 删除节点 ### + def remove(val) + @root = remove_helper(@root, val) + end + + ### 递归删除节点(辅助方法)### + def remove_helper(node, val) + return if node.nil? + # 1. 查找节点并删除 + if val < node.val + node.left = remove_helper(node.left, val) + elsif val > node.val + node.right = remove_helper(node.right, val) + else + if node.left.nil? || node.right.nil? + child = node.left || node.right + # 子节点数量 = 0 ,直接删除 node 并返回 + return if child.nil? + # 子节点数量 = 1 ,直接删除 node + node = child + else + # 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节点 + temp = node.right + while !temp.left.nil? + temp = temp.left + end + node.right = remove_helper(node.right, temp.val) + node.val = temp.val + end + end + # 更新节点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + rotate(node) + end ``` === "Zig" diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 741a6e4f0..237c70b54 100755 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -316,7 +316,26 @@ comments: true === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{search} + ### 查找节点 ### + def search(num) + cur = @root + + # 循环查找,越过叶节点后跳出 + while !cur.nil? + # 目标节点在 cur 的右子树中 + if cur.val < num + cur = cur.right + # 目标节点在 cur 的左子树中 + elsif cur.val > num + cur = cur.left + # 找到目标节点,跳出循环 + else + break + end + end + + cur + end ``` === "Zig" @@ -773,7 +792,38 @@ comments: true === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{insert} + ### 插入节点 ### + def insert(num) + # 若树为空,则初始化根节点 + if @root.nil? + @root = TreeNode.new(num) + return + end + + # 循环查找,越过叶节点后跳出 + cur, pre = @root, nil + while !cur.nil? + # 找到重复节点,直接返回 + return if cur.val == num + + pre = cur + # 插入位置在 cur 的右子树中 + if cur.val < num + cur = cur.right + # 插入位置在 cur 的左子树中 + else + cur = cur.left + end + end + + # 插入节点 + node = TreeNode.new(num) + if pre.val < num + pre.right = node + else + pre.left = node + end + end ``` === "Zig" @@ -1545,7 +1595,57 @@ comments: true === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{remove} + ### 删除节点 ### + def remove(num) + # 若树为空,直接提前返回 + return if @root.nil? + + # 循环查找,越过叶节点后跳出 + cur, pre = @root, nil + while !cur.nil? + # 找到待删除节点,跳出循环 + break if cur.val == num + + pre = cur + # 待删除节点在 cur 的右子树中 + if cur.val < num + cur = cur.right + # 待删除节点在 cur 的左子树中 + else + cur = cur.left + end + end + # 若无待删除节点,则直接返回 + return if cur.nil? + + # 子节点数量 = 0 or 1 + if cur.left.nil? || cur.right.nil? + # 当子节点数量 = 0 / 1 时, child = null / 该子节点 + child = cur.left || cur.right + # 删除节点 cur + if cur != @root + if pre.left == cur + pre.left = child + else + pre.right = child + end + else + # 若删除节点为根节点,则重新指定根节点 + @root = child + end + # 子节点数量 = 2 + else + # 获取中序遍历中 cur 的下一个节点 + tmp = cur.right + while !tmp.left.nil? + tmp = tmp.left + end + # 递归删除节点 tmp + remove(tmp.val) + # 用 tmp 覆盖 cur + cur.val = tmp.val + end + end ``` === "Zig" diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index 41065ebd0..172a925dc 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -318,7 +318,20 @@ comments: true === "Ruby" ```ruby title="binary_tree_bfs.rb" - [class]{}-[func]{level_order} + ### 层序遍历 ### + def level_order(root) + # 初始化队列,加入根节点 + queue = [root] + # 初始化一个列表,用于保存遍历序列 + res = [] + while !queue.empty? + node = queue.shift # 队列出队 + res << node.val # 保存节点值 + queue << node.left unless node.left.nil? # 左子节点入队 + queue << node.right unless node.right.nil? # 右子节点入队 + end + res + end ``` === "Zig" @@ -793,9 +806,25 @@ comments: true ```ruby title="binary_tree_dfs.rb" [class]{}-[func]{pre_order} - [class]{}-[func]{in_order} - - [class]{}-[func]{post_order} + ### 中序遍历 ### + def in_order(root) + return if root.nil? + + # 访问优先级:左子树 -> 根节点 -> 右子树 + in_order(root.left) + $res << root.val + in_order(root.right) + end + + ### 后序遍历 ### + def post_order(root) + return if root.nil? + + # 访问优先级:左子树 -> 右子树 -> 根节点 + post_order(root.left) + post_order(root.right) + $res << root.val + end ``` === "Zig" diff --git a/en/docs/chapter_tree/array_representation_of_tree.md b/en/docs/chapter_tree/array_representation_of_tree.md index 90fd62156..4ccd7cc7f 100644 --- a/en/docs/chapter_tree/array_representation_of_tree.md +++ b/en/docs/chapter_tree/array_representation_of_tree.md @@ -1256,7 +1256,87 @@ The following code implements a binary tree based on array representation, inclu === "Ruby" ```ruby title="array_binary_tree.rb" - [class]{ArrayBinaryTree}-[func]{} + ### 数组表示下的二叉树类 ### + class ArrayBinaryTree + ### 构造方法 ### + def initialize(arr) + @tree = arr.to_a + end + + ### 列表容量 ### + def size + @tree.length + end + + ### 获取索引为 i 节点的值 ### + def val(i) + # 若索引越界,则返回 nil ,代表空位 + return if i < 0 || i >= size + + @tree[i] + end + + ### 获取索引为 i 节点的左子节点的索引 ### + def left(i) + 2 * i + 1 + end + + ### 获取索引为 i 节点的右子节点的索引 ### + def right(i) + 2 * i + 2 + end + + ### 获取索引为 i 节点的父节点的索引 ### + def parent(i) + (i - 1) / 2 + end + + ### 层序遍历 ### + def level_order + @res = [] + + # 直接遍历数组 + for i in 0...size + @res << val(i) unless val(i).nil? + end + + @res + end + + ### 深度优先遍历 ### + def dfs(i, order) + return if val(i).nil? + # 前序遍历 + @res << val(i) if order == :pre + dfs(left(i), order) + # 中序遍历 + @res << val(i) if order == :in + dfs(right(i), order) + # 后序遍历 + @res << val(i) if order == :post + end + + ### 前序遍历 ### + def pre_order + @res = [] + dfs(0, :pre) + @res + end + + ### 中序遍历 ### + def in_order + @res = [] + dfs(0, :in) + @res + end + + ### 后序遍历 ### + def post_order + @res = [] + dfs(0, :post) + @res + end + end ``` === "Zig" diff --git a/en/docs/chapter_tree/avl_tree.md b/en/docs/chapter_tree/avl_tree.md index fbe7eec51..384b6ee6b 100644 --- a/en/docs/chapter_tree/avl_tree.md +++ b/en/docs/chapter_tree/avl_tree.md @@ -455,9 +455,19 @@ The "node height" refers to the distance from that node to its farthest leaf nod === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{height} + ### 获取节点高度 ### + def height(node) + # 空节点高度为 -1 ,叶节点高度为 0 + return node.height unless node.nil? - [class]{AVLTree}-[func]{update_height} + -1 + end + + ### 更新节点高度 ### + def update_height(node) + # 节点高度等于最高子树高度 + 1 + node.height = [height(node.left), height(node.right)].max + 1 + end ``` === "Zig" @@ -638,7 +648,14 @@ The "balance factor" of a node is defined as the height of the node's left subtr === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{balance_factor} + ### 获取平衡因子 ### + def balance_factor(node) + # 空节点平衡因子为 0 + return 0 if node.nil? + + # 节点平衡因子 = 左子树高度 - 右子树高度 + height(node.left) - height(node.right) + end ``` === "Zig" @@ -913,7 +930,19 @@ As shown in the Figure 7-27 , when the `child` node has a right child (denoted a === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{right_rotate} + ### 右旋操作 ### + def right_rotate(node) + child = node.left + grand_child = child.right + # 以 child 为原点,将 node 向右旋转 + child.right = node + node.left = grand_child + # 更新节点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + child + end ``` === "Zig" @@ -1174,7 +1203,19 @@ It can be observed that **the right and left rotation operations are logically s === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{left_rotate} + ### 左旋操作 ### + def left_rotate(node) + child = node.right + grand_child = child.left + # 以 child 为原点,将 node 向左旋转 + child.left = node + node.right = grand_child + # 更新节点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + child + end ``` === "Zig" @@ -1648,7 +1689,34 @@ For convenience, we encapsulate the rotation operations into a function. **With === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{rotate} + ### 执行旋转操作,使该子树重新恢复平衡 ### + def rotate(node) + # 获取节点 node 的平衡因子 + balance_factor = balance_factor(node) + # 左遍树 + if balance_factor > 1 + if balance_factor(node.left) >= 0 + # 右旋 + return right_rotate(node) + else + # 先左旋后右旋 + node.left = left_rotate(node.left) + return right_rotate(node) + end + # 右遍树 + elsif balance_factor < -1 + if balance_factor(node.right) <= 0 + # 左旋 + return left_rotate(node) + else + # 先右旋后左旋 + node.right = right_rotate(node.right) + return left_rotate(node) + end + end + # 平衡树,无须旋转,直接返回 + node + end ``` === "Zig" @@ -2039,9 +2107,28 @@ The node insertion operation in AVL trees is similar to that in binary search tr === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{insert} - - [class]{AVLTree}-[func]{insert_helper} + ### 插入节点 ### + def insert(val) + @root = insert_helper(@root, val) + end + + ### 递归插入节点(辅助方法)### + def insert_helper(node, val) + return TreeNode.new(val) if node.nil? + # 1. 查找插入位置并插入节点 + if val < node.val + node.left = insert_helper(node.left, val) + elsif val > node.val + node.right = insert_helper(node.right, val) + else + # 重复节点不插入,直接返回 + return node + end + # 更新节点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + rotate(node) + end ``` === "Zig" @@ -2640,9 +2727,41 @@ Similarly, based on the method of removing nodes in binary search trees, rotatio === "Ruby" ```ruby title="avl_tree.rb" - [class]{AVLTree}-[func]{remove} - - [class]{AVLTree}-[func]{remove_helper} + ### 删除节点 ### + def remove(val) + @root = remove_helper(@root, val) + end + + ### 递归删除节点(辅助方法)### + def remove_helper(node, val) + return if node.nil? + # 1. 查找节点并删除 + if val < node.val + node.left = remove_helper(node.left, val) + elsif val > node.val + node.right = remove_helper(node.right, val) + else + if node.left.nil? || node.right.nil? + child = node.left || node.right + # 子节点数量 = 0 ,直接删除 node 并返回 + return if child.nil? + # 子节点数量 = 1 ,直接删除 node + node = child + else + # 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节点 + temp = node.right + while !temp.left.nil? + temp = temp.left + end + node.right = remove_helper(node.right, temp.val) + node.val = temp.val + end + end + # 更新节点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + rotate(node) + end ``` === "Zig" diff --git a/en/docs/chapter_tree/binary_search_tree.md b/en/docs/chapter_tree/binary_search_tree.md index 9739a24d4..ffb089167 100755 --- a/en/docs/chapter_tree/binary_search_tree.md +++ b/en/docs/chapter_tree/binary_search_tree.md @@ -316,7 +316,26 @@ The search operation in a binary search tree works on the same principle as the === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{search} + ### 查找节点 ### + def search(num) + cur = @root + + # 循环查找,越过叶节点后跳出 + while !cur.nil? + # 目标节点在 cur 的右子树中 + if cur.val < num + cur = cur.right + # 目标节点在 cur 的左子树中 + elsif cur.val > num + cur = cur.left + # 找到目标节点,跳出循环 + else + break + end + end + + cur + end ``` === "Zig" @@ -773,7 +792,38 @@ In the code implementation, note the following two points. === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{insert} + ### 插入节点 ### + def insert(num) + # 若树为空,则初始化根节点 + if @root.nil? + @root = TreeNode.new(num) + return + end + + # 循环查找,越过叶节点后跳出 + cur, pre = @root, nil + while !cur.nil? + # 找到重复节点,直接返回 + return if cur.val == num + + pre = cur + # 插入位置在 cur 的右子树中 + if cur.val < num + cur = cur.right + # 插入位置在 cur 的左子树中 + else + cur = cur.left + end + end + + # 插入节点 + node = TreeNode.new(num) + if pre.val < num + pre.right = node + else + pre.left = node + end + end ``` === "Zig" @@ -1545,7 +1595,57 @@ The operation of removing a node also uses $O(\log n)$ time, where finding the n === "Ruby" ```ruby title="binary_search_tree.rb" - [class]{BinarySearchTree}-[func]{remove} + ### 删除节点 ### + def remove(num) + # 若树为空,直接提前返回 + return if @root.nil? + + # 循环查找,越过叶节点后跳出 + cur, pre = @root, nil + while !cur.nil? + # 找到待删除节点,跳出循环 + break if cur.val == num + + pre = cur + # 待删除节点在 cur 的右子树中 + if cur.val < num + cur = cur.right + # 待删除节点在 cur 的左子树中 + else + cur = cur.left + end + end + # 若无待删除节点,则直接返回 + return if cur.nil? + + # 子节点数量 = 0 or 1 + if cur.left.nil? || cur.right.nil? + # 当子节点数量 = 0 / 1 时, child = null / 该子节点 + child = cur.left || cur.right + # 删除节点 cur + if cur != @root + if pre.left == cur + pre.left = child + else + pre.right = child + end + else + # 若删除节点为根节点,则重新指定根节点 + @root = child + end + # 子节点数量 = 2 + else + # 获取中序遍历中 cur 的下一个节点 + tmp = cur.right + while !tmp.left.nil? + tmp = tmp.left + end + # 递归删除节点 tmp + remove(tmp.val) + # 用 tmp 覆盖 cur + cur.val = tmp.val + end + end ``` === "Zig" diff --git a/en/docs/chapter_tree/binary_tree_traversal.md b/en/docs/chapter_tree/binary_tree_traversal.md index f1ce2a49d..68dd05a52 100755 --- a/en/docs/chapter_tree/binary_tree_traversal.md +++ b/en/docs/chapter_tree/binary_tree_traversal.md @@ -318,7 +318,20 @@ Breadth-first traversal is usually implemented with the help of a "queue". The q === "Ruby" ```ruby title="binary_tree_bfs.rb" - [class]{}-[func]{level_order} + ### 层序遍历 ### + def level_order(root) + # 初始化队列,加入根节点 + queue = [root] + # 初始化一个列表,用于保存遍历序列 + res = [] + while !queue.empty? + node = queue.shift # 队列出队 + res << node.val # 保存节点值 + queue << node.left unless node.left.nil? # 左子节点入队 + queue << node.right unless node.right.nil? # 右子节点入队 + end + res + end ``` === "Zig" @@ -793,9 +806,25 @@ Depth-first search is usually implemented based on recursion: ```ruby title="binary_tree_dfs.rb" [class]{}-[func]{pre_order} - [class]{}-[func]{in_order} - - [class]{}-[func]{post_order} + ### 中序遍历 ### + def in_order(root) + return if root.nil? + + # 访问优先级:左子树 -> 根节点 -> 右子树 + in_order(root.left) + $res << root.val + in_order(root.right) + end + + ### 后序遍历 ### + def post_order(root) + return if root.nil? + + # 访问优先级:左子树 -> 右子树 -> 根节点 + post_order(root.left) + post_order(root.right) + $res << root.val + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_appendix/installation.md b/zh-Hant/docs/chapter_appendix/installation.md index 1bfd028aa..b50ebbac5 100644 --- a/zh-Hant/docs/chapter_appendix/installation.md +++ b/zh-Hant/docs/chapter_appendix/installation.md @@ -56,16 +56,21 @@ VS Code 擁有強大的擴展包生態系統,支持大多數程式語言的執 ### 7.   JavaScript 環境 -1. 下載並安裝 [node.js](https://nodejs.org/en/) 。 -2. 在 VS Code 的擴充功能市場中搜索 `javascript` ,安裝 JavaScript (ES6) code snippets 。 -3. (可選)在 VS Code 的擴充功能市場中搜索 `Prettier` ,安裝程式碼格式化工具。 +1. 下載並安裝 [Node.js](https://nodejs.org/en/) 。 +2. (可選)在 VS Code 的擴充功能市場中搜索 `Prettier` ,安裝程式碼格式化工具。 -### 8.   Dart 環境 +### 8.   TypeScript 環境 + +1. 同 JavaScript 環境安裝步驟。 +2. 安裝 [TypeScript Execute (tsx)](https://github.com/privatenumber/tsx?tab=readme-ov-file#global-installation) 。 +3. 在 VS Code 的擴充功能市場中搜索 `typescript` ,安裝 [Pretty TypeScript Errors](https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors) 。 + +### 9.   Dart 環境 1. 下載並安裝 [Dart](https://dart.dev/get-dart) 。 2. 在 VS Code 的擴充功能市場中搜索 `dart` ,安裝 [Dart](https://marketplace.visualstudio.com/items?itemName=Dart-Code.dart-code) 。 -### 9.   Rust 環境 +### 10.   Rust 環境 1. 下載並安裝 [Rust](https://www.rust-lang.org/tools/install) 。 2. 在 VS Code 的擴充功能市場中搜索 `rust` ,安裝 [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) 。