From 48f666aff9afaa085814b90b58a38d386db1cddc Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 17:27:39 +0800 Subject: [PATCH 001/109] docs: add GUIDELINES.md --- codes/rust/GUIDELINES.md | 63 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 codes/rust/GUIDELINES.md diff --git a/codes/rust/GUIDELINES.md b/codes/rust/GUIDELINES.md new file mode 100644 index 0000000000..3960c392b4 --- /dev/null +++ b/codes/rust/GUIDELINES.md @@ -0,0 +1,63 @@ +# 维护指南 + +## 工具准备 + +[Clippy] 是 Rust 工具链中的可选组件,可以帮助我们发现和修复代码中的常见问题。请确保在提交代码之前运行 Clippy 并修复所有警告。 + +### 安装 + +```shell +rustup update +rustup component add clippy +``` + +### 使用 + +```shell +cargo clippy +``` + +或配合各编辑器的 rust-analyzer 插件使用。 + +## 术语 + +- **示例代码**:会被嵌入到《Hello 算法》中渲染输出的代码。 +- **非示例代码**:不会被嵌入到《Hello 算法》中渲染输出的代码,例如辅助函数、辅助类型、测试代码等。 + +## 代码风格 + +代码风格应遵循一致、清晰和可维护的原则。当这些原则存在冲突时,请按以下优先级处理: + +1. **示例代码**应与《Hello 算法》中的文本和图片保持一致,不宜改变其中出现的标识符和执行顺序,不得改变代码逻辑。例如,若书中使用 `i` 和 `p` 命名节点索引和父节点索引,避免重命名为 `index` 和 `parent`,如果实在影响阅读,应在函数签名或函数体内注释并重绑定;若书中使用递归实现,不得改为迭代实现。 + +2. 代码应满足 *[Rust Style Guide]* 和 Clippy 的建议。如果修复 lint 会导致与第一条冲突,则应使用属性 `allow(...)` 以显式地移除警告。外部属性(标柱跟随项)的语法为 `#[attr]`,内部属性(标注所在项)的语法为 `#![attr]`,除了以文件为单位的模块顶层以外,不应使用内部属性。属性的作用范围应该尽可能的小,但不得小到单独作用于语句和表达式上;允许的类型应该尽可能地精确,例如,未使用的函数、结构体等顶层项应使用 `allow(dead_code)`,未使用的变量应使用 `allow(unused_variables)`。避免使用 `allow(unused)`,如使用,应在提交代码前短暂地移除该属性并解决被意外忽略的警告。 + +3. 代码建议与其他语言的实现保持一致。因为不同语言的规范和惯例具有较大的差异,不应强求这种一致性。 + +## 常见情况的处理建议 + +- **公共项**:应作为本项目的同名库 crate `hello_algo_rust` 的公共接口,放在 `src` 目录下。项目内的其他所有代码均为二进制 crate,它们作为依赖链的最下游,不应作为依赖项被其他 crate「挂载」为模块。目前 Cargo 并没有阻止这种做法,甚至允许一个文件被多次「挂载」,但这是一种典型的反模式,应当避免。 + +- **可见性**:**示例代码**全部位于 bin crate,原则上不会被其他地方使用,最大可见性本应为 `pub(crate)`,在 crate 顶层无需被可见性修饰符修饰;然而,「实现某种数据结构或算法」暗示着代码将作为某种公开接口供下游使用,为了表达这种意图,以及区分公开接口和内部实现细节,**示例代码**中原则上是公开接口的部分应使用 `pub` 修饰符,是内部实现细节的部分不使用可见性修饰符。可见性修饰符中不得出现范围参数,例如 `pub(super)`、`pub(in some::path)` 等。 + +- **导入**:常量、静态量、类型别名、结构体、枚举、trait 等可直接导入,函数应导入上级模块并以其为前缀使用。 + +- **类型别名**:对于**示例代码**,如果类型别名不会被输出,不建议使用类型别名,例如 `type NodeRef = Rc>;`。 + +- **`val` 类型**:对于**示例代码**,数据结构的 `val` 字段类型应使用默认整型 `i32`,不建议使用泛型参数,不得使用复杂约束的泛型参数。 + +- **索引、长度及迭代计数类型**:对于可能不存在的索引,使用 `Option` 类型,其他所有关于索引、长度及迭代计数的代码都应该使用 `usize` 类型。这不是代码风格问题,而是代码正确性问题。永远不应该使用 `i32` 作为索引类型,因为即使在 32 位平台,`i32` 也有一半的合法位置无法索引。具体原因涉及指针偏移、内存分配以及零大小类型,详见 *[Rustonomicon]*。 + +- **非法值**:不得使用 `-1` 作为非法值,应该使用 `Option` 类型的 `None` 来标记非法值。 + +- **溢出**:对于**示例代码**,不检查因累加造成的最终结果溢出,因为这是类型表达能力的限制,应任其 panic 并终止程序;对于索引偏移等操作,应处理溢出行为,比如检查并提前返回、显式回绕等,因为这是算法正常运行必须处理的边界条件。不得将 usize 转换为 isize 甚至 i32 来避免减法溢出,可以但不鼓励将 usize 转换为 i128 来避免溢出。 + +- **未使用的变量**:对于**示例代码**,应使用 `allow(unused_variables)` 移除警告;对于**非示例代码**,应使用 `_` 为前缀重命名变量。 + +- **格式化输出**:对于**非示例代码**,应实现 `std::fmt::Display` trait 以提供自定义的格式化输出,避免自定义 `print` 等函数或方法。出现在**示例代码**中的 `print` 函数或方法应维持原状。 + +- **注释**:注释风格应遵循 *[Rust Style Guide]*,避免使用多行注释,应使用多行的单行注释。 + +[Clippy]: https://github.com/rust-lang/rust-clippy +[Rust Style Guide]: https://doc.rust-lang.org/style-guide/ +[Rustonomicon]: https://doc.rust-lang.org/stable/nomicon/vec/vec-alloc.html#allocating-memory From 56b2f499f5afc7d203c0fad4b47e86926429388c Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Wed, 21 Jan 2026 04:28:01 +0800 Subject: [PATCH 002/109] build: bump edition to `"2024"` --- codes/rust/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codes/rust/Cargo.toml b/codes/rust/Cargo.toml index 160f9134cf..a55797ac89 100644 --- a/codes/rust/Cargo.toml +++ b/codes/rust/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hello-algo-rust" version = "0.1.0" -edition = "2021" +edition = "2024" publish = false # Run Command: cargo run --bin time_complexity From a838f54a74463432cbeefd26b43a6fa321e9afd4 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Wed, 21 Jan 2026 04:28:24 +0800 Subject: [PATCH 003/109] build: update dependency --- codes/rust/Cargo.toml | 2 +- codes/rust/chapter_array_and_linkedlist/array.rs | 2 +- .../worst_best_time_complexity.rs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/codes/rust/Cargo.toml b/codes/rust/Cargo.toml index a55797ac89..8737c8cd2f 100644 --- a/codes/rust/Cargo.toml +++ b/codes/rust/Cargo.toml @@ -410,4 +410,4 @@ name = "max_product_cutting" path = "chapter_greedy/max_product_cutting.rs" [dependencies] -rand = "0.8.5" +rand = "0.9.2" diff --git a/codes/rust/chapter_array_and_linkedlist/array.rs b/codes/rust/chapter_array_and_linkedlist/array.rs index 29241d2ec2..448099f5d1 100644 --- a/codes/rust/chapter_array_and_linkedlist/array.rs +++ b/codes/rust/chapter_array_and_linkedlist/array.rs @@ -10,7 +10,7 @@ use rand::Rng; /* 随机访问元素 */ fn random_access(nums: &[i32]) -> i32 { // 在区间 [0, nums.len()) 中随机抽取一个数字 - let random_index = rand::thread_rng().gen_range(0..nums.len()); + let random_index = rand::rng().random_range(0..nums.len()); // 获取并返回随机元素 let random_num = nums[random_index]; random_num diff --git a/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs b/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs index df776625f8..1eb18fa105 100644 --- a/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs +++ b/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs @@ -6,14 +6,13 @@ use hello_algo_rust::include::print_util; use rand::seq::SliceRandom; -use rand::thread_rng; /* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */ fn random_numbers(n: i32) -> Vec { // 生成数组 nums = { 1, 2, 3, ..., n } let mut nums = (1..=n).collect::>(); // 随机打乱数组元素 - nums.shuffle(&mut thread_rng()); + nums.shuffle(&mut rand::rng()); nums } From 9077815b5138d1da7629d413e009bfbee6f8ace7 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 17:56:03 +0800 Subject: [PATCH 004/109] feat: add support modules --- codes/rust/src/binary_tree.rs | 419 ++++++++++++++++++ codes/rust/src/binary_tree/link_impl.rs | 175 ++++++++ codes/rust/src/binary_tree/traverse.rs | 9 + .../rust/src/binary_tree/traverse/in_order.rs | 77 ++++ .../src/binary_tree/traverse/level_order.rs | 81 ++++ .../src/binary_tree/traverse/post_order.rs | 61 +++ .../src/binary_tree/traverse/pre_order.rs | 30 ++ codes/rust/src/fmt.rs | 189 ++++++++ codes/rust/src/graph_adjacency_list.rs | 132 ++++++ codes/rust/src/heap.rs | 93 ++++ codes/rust/src/lib.rs | 5 + codes/rust/src/linked_list.rs | 115 +++++ codes/rust/src/linked_list/link_impl.rs | 149 +++++++ codes/rust/src/linked_list/node_impl.rs | 141 ++++++ 14 files changed, 1676 insertions(+) create mode 100644 codes/rust/src/binary_tree.rs create mode 100644 codes/rust/src/binary_tree/link_impl.rs create mode 100644 codes/rust/src/binary_tree/traverse.rs create mode 100644 codes/rust/src/binary_tree/traverse/in_order.rs create mode 100644 codes/rust/src/binary_tree/traverse/level_order.rs create mode 100644 codes/rust/src/binary_tree/traverse/post_order.rs create mode 100644 codes/rust/src/binary_tree/traverse/pre_order.rs create mode 100644 codes/rust/src/fmt.rs create mode 100644 codes/rust/src/graph_adjacency_list.rs create mode 100644 codes/rust/src/heap.rs create mode 100644 codes/rust/src/linked_list.rs create mode 100644 codes/rust/src/linked_list/link_impl.rs create mode 100644 codes/rust/src/linked_list/node_impl.rs diff --git a/codes/rust/src/binary_tree.rs b/codes/rust/src/binary_tree.rs new file mode 100644 index 0000000000..c1d03fc4f5 --- /dev/null +++ b/codes/rust/src/binary_tree.rs @@ -0,0 +1,419 @@ +//! 本模块仅用于示例代码,不建议在生产环境中使用。 +//! +//! 为了与示例代码中 `Rc>` 保持一致,本模块中的 [`TreeLink`] 是前者的 +//! 类型别名而非包装类型。由于孤儿法则,本模块额外定义了 [`BinaryTree`] trait 以为其实现关 +//! 联函数和方法,你不必为自己的链表类型定义或实现类似的 trait。为了方便示例代码的编写和阅读, +//! 在本模块中,实现了 [`BinaryTree`] 的类型有: +//! +//! - [`TreeLink`] +//! - `Option` +//! +//! 它们都被视为二叉树。参考实现时,以上类型作为实现细节不应暴露为公共接口,否则可能发生二叉树成环, +//! 这会导致内存泄露、迭代无法终止等系列问题。 +//! +//! # 二叉树的遍历 +//! +//! 本模块提供了二叉树四种遍历方式的迭代器实现,分别是: +//! +//! - `LevelOrder`(层序遍历) +//! - `PreOrder`(前序遍历) +//! - `InOrder`(中序遍历) +//! - `PostOrder`(后序遍历) +//! +//! 这些迭代器都是私有的,只可通过匿名类型使用它们。你可以通过 [`BinaryTree`] trait 提供的相关方法 +//! 来获取这些迭代器。 + +use std::cell::RefCell; +use std::fmt; +use std::rc::Rc; + +mod link_impl; +mod traverse; + +pub trait BinaryTree { + type Element; + type Error; + type TraverseItem; + + fn len(&self) -> usize; + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn height(&self) -> Option; + + fn update_height(&self); + + fn try_from_slice(slice: &[Option]) -> Result + where + Self: Sized, + Self::Element: Clone; + + fn try_from_array( + array: [Option; N], + ) -> Result + where + Self: Sized; + + fn try_from_vec(vec: Vec>) -> Result + where + Self: Sized; + + fn traverse_level_order(self) -> impl Iterator; + + fn traverse_pre_order(self) -> impl Iterator; + + fn traverse_in_order(self) -> impl Iterator; + + fn traverse_post_order(self) -> impl Iterator; + + fn display(&self) -> impl fmt::Display + where + Self::Element: fmt::Display; +} + +#[derive(Debug, Clone)] +pub struct TreeNode { + pub val: T, + pub height: usize, + pub parent: Option>, + pub left: Option>, + pub right: Option>, +} + +pub type TreeLink = Rc>>; + +impl TreeNode { + pub fn new(val: T) -> TreeLink { + TreeLink::from(Self { + val, + height: 0, + parent: None, + left: None, + right: None, + }) + } + + /// 注意:当前实现中,无法链接的节点会被忽略。 + fn try_from_iter(iter: I) -> Option> + where + I: IntoIterator>, + { + let mut links = Vec::new(); + + let mut level_empty = true; + let mut offset: usize = 0; + let mut width: usize = 1; + for val in iter { + match val { + None => { + // 元素数量超过 isize::MAX as usize / size_of::>>() + // 时恐慌。在此之前,程序更可能因为内存不足而崩溃。 + links.push(None); + } + Some(val) => { + level_empty = false; + let node = Self { + val, + height: 0, + parent: None, + left: None, + right: None, + }; + let link = TreeLink::from(node); + links.push(Some(link)); + } + } + if offset < width - 1 { + offset += 1; + } else { + if level_empty { + // 此实现会在层空时熔断,忽略后续无法链接的有效节点。 + break; + } + level_empty = true; + offset = 0; + // 深度达到 usize::BITS 时,层宽溢出;此状态不可达,因为此时至少需要 + // 分配 usize::MAX + 1 个元素。即使不考虑内存耗尽,links 会在分配 + // isize::MAX as usize / size_of::>>() + // 个元素后容量溢出并恐慌,这个数量远小于 usize::MAX + 1。此外,从类 + // 型上看,usize::MAX + 1 也无法被 Vec::len 的返回类型 usize 表达。 + width *= 2; + } + } + + for index in (0..links.len()).rev() { + let Some(Some(link)) = links.get(index) else { + continue; + }; + + let Some(left) = index.checked_mul(2).and_then(|x| x.checked_add(1)) else { + continue; + }; + if let Some(Some(left)) = links.get(left) { + let mut borrow_link = link.borrow_mut(); + let mut borrow_left = left.borrow_mut(); + borrow_link.height = borrow_left.height + 1; + borrow_link.left = Some(Rc::clone(left)); + borrow_left.parent = Some(Rc::clone(link)); + } + + let Some(right) = left.checked_add(1) else { + continue; + }; + if let Some(Some(right)) = links.get(right) { + let mut borrow_link = link.borrow_mut(); + let mut borrow_right = right.borrow_mut(); + borrow_link.height = borrow_link.height.max(borrow_right.height + 1); + borrow_link.right = Some(Rc::clone(right)); + borrow_right.parent = Some(Rc::clone(link)); + } + } + + links.into_iter().next().unwrap_or(None) + } +} + +impl From> for TreeLink { + fn from(value: TreeNode) -> Self { + Rc::new(RefCell::new(value)) + } +} + +#[cfg(test)] +mod tests { + use super::traverse::LevelOrderIncludeNulls; + use super::*; + use rand::Rng; + + // 样本二叉树: + // Some(0) + // ┌───────────────────┴───────────────────┐ + // Some(1) Some(2) + // ┌─────────┴─────────┐ ┌─────────┴─────────┐ + // Some(3) None Some(5) Some(6) + // ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ + // Some(7) Some(8) None None Some(11) None None Some(14) + const SAMPLE: [Option; 15] = [ + Some(0), + Some(1), + Some(2), + Some(3), + None, + Some(5), + Some(6), + Some(7), + Some(8), + None, + None, + Some(11), + None, + None, + Some(14), + ]; + + #[test] + fn test_update_height() { + // Some(0) + // ┌─────────────────┴─────────────────┐ + // Some(1) Some(2) + // ┌────────┴────────┐ ┌────────┴────────┐ + // Some(3) Some(4) None None + // ┌────┴───┐ ┌────┴───┐ ┌────┴───┐ ┌────┴───┐ + // Some(5) None None None None None None None + + let n0 = TreeNode::new(0); + let n1 = TreeNode::new(1); + let n2 = TreeNode::new(2); + let n3 = TreeNode::new(3); + let n4 = TreeNode::new(4); + let n5 = TreeNode::new(5); + + // 构建二叉树并随机设置节点高度。 + // 离开作用域后,所有 RefMut 全部 drop。 + { + let mut borrow_n0 = n0.borrow_mut(); + borrow_n0.height = rand::rng().random_range(0..100); + borrow_n0.left = Some(Rc::clone(&n1)); + borrow_n0.right = Some(Rc::clone(&n2)); + + let mut borrow_n1 = n1.borrow_mut(); + borrow_n1.height = rand::rng().random_range(0..100); + borrow_n1.left = Some(Rc::clone(&n3)); + borrow_n1.right = Some(Rc::clone(&n4)); + + let mut borrow_n2 = n2.borrow_mut(); + borrow_n2.height = rand::rng().random_range(0..100); + + let mut borrow_n3 = n3.borrow_mut(); + borrow_n3.height = rand::rng().random_range(0..100); + borrow_n3.left = Some(Rc::clone(&n5)); + + let mut borrow_n4 = n4.borrow_mut(); + borrow_n4.height = rand::rng().random_range(0..100); + + let mut borrow_n5 = n5.borrow_mut(); + borrow_n5.height = rand::rng().random_range(0..100); + } + + n0.update_height(); + assert_eq!(n0.borrow().height, 3); + assert_eq!(n1.borrow().height, 2); + assert_eq!(n2.borrow().height, 0); + assert_eq!(n3.borrow().height, 1); + assert_eq!(n4.borrow().height, 0); + assert_eq!(n5.borrow().height, 0); + } + + #[test] + fn test_from_iter() { + let tree = TreeNode::try_from_iter(SAMPLE).unwrap(); + + let n0 = tree; + let borrow_n0 = n0.borrow(); + assert_eq!(borrow_n0.val, 0); + assert_eq!(borrow_n0.height, 3); + + let n1 = borrow_n0.left.clone().unwrap(); + let borrow_n1 = n1.borrow(); + assert_eq!(borrow_n1.val, 1); + assert_eq!(borrow_n1.height, 2); + + let n2 = borrow_n0.right.clone().unwrap(); + let borrow_n2 = n2.borrow(); + assert_eq!(borrow_n2.val, 2); + assert_eq!(borrow_n2.height, 2); + + let n3 = borrow_n1.left.clone().unwrap(); + let borrow_n3 = n3.borrow(); + assert_eq!(borrow_n3.val, 3); + assert_eq!(borrow_n3.height, 1); + + // n4 不存在。 + assert!(borrow_n1.right.is_none()); + + let n5 = borrow_n2.left.clone().unwrap(); + let borrow_n5 = n5.borrow(); + assert_eq!(borrow_n5.val, 5); + assert_eq!(borrow_n5.height, 1); + + let n6 = borrow_n2.right.clone().unwrap(); + let borrow_n6 = n6.borrow(); + assert_eq!(borrow_n6.val, 6); + assert_eq!(borrow_n6.height, 1); + + let n7 = borrow_n3.left.clone().unwrap(); + let borrow_n7 = n7.borrow(); + assert_eq!(borrow_n7.val, 7); + assert_eq!(borrow_n7.height, 0); + + let n8 = borrow_n3.right.clone().unwrap(); + let borrow_n8 = n8.borrow(); + assert_eq!(borrow_n8.val, 8); + assert_eq!(borrow_n8.height, 0); + + // n9 和 n10 不存在且没有父节点。 + + let n11 = borrow_n5.left.clone().unwrap(); + let borrow_n11 = n11.borrow(); + assert_eq!(borrow_n11.val, 11); + assert_eq!(borrow_n11.height, 0); + + // n12 不存在。 + assert!(borrow_n5.right.is_none()); + + // n13 不存在。 + assert!(borrow_n6.left.is_none()); + + let n14 = borrow_n6.right.clone().unwrap(); + let borrow_n14 = n14.borrow(); + assert_eq!(borrow_n14.val, 14); + assert_eq!(borrow_n14.height, 0); + + // 当前实现中,无法链接的节点会被忽略。 + let mut bad_sample = SAMPLE; + bad_sample[9] = Some(10); // 此节点不会被链接。 + let tree = TreeNode::try_from_iter(bad_sample).unwrap(); + let result = tree + .traverse_level_order() + .map(|link| link.borrow().val) + .collect::>(); + let expected = vec![0, 1, 2, 3, 5, 6, 7, 8, 11, 14]; + assert_eq!(result, expected); + } + + #[test] + fn test_traverse_level_order() { + let tree = TreeNode::try_from_iter(SAMPLE).unwrap(); + let result = tree + .traverse_level_order() + .map(|link| link.borrow().val) + .collect::>(); + let expected = vec![0, 1, 2, 3, 5, 6, 7, 8, 11, 14]; + assert_eq!(result, expected); + } + + #[test] + fn test_traverse_level_order_include_nulls() { + let tree = TreeNode::try_from_iter(SAMPLE).unwrap(); + let result = LevelOrderIncludeNulls::new(tree) + .map(|opt| opt.map(|link| link.borrow().val)) + .collect::>(); + let expected = SAMPLE; + assert_eq!(result, expected); + } + + #[test] + fn test_traverse_pre_order() { + let tree = TreeNode::try_from_iter(SAMPLE).unwrap(); + let result = tree + .traverse_pre_order() + .map(|link| link.borrow().val) + .collect::>(); + let expected = vec![0, 1, 3, 7, 8, 2, 5, 11, 6, 14]; + assert_eq!(result, expected); + } + + #[test] + fn test_traverse_in_order() { + let tree = TreeNode::try_from_iter(SAMPLE).unwrap(); + let result = tree + .traverse_in_order() + .map(|link| link.borrow().val) + .collect::>(); + let expected = vec![7, 3, 8, 1, 0, 11, 5, 2, 6, 14]; + assert_eq!(result, expected); + } + + #[test] + fn test_traverse_post_order() { + let tree = TreeNode::try_from_iter(SAMPLE).unwrap(); + let result = tree + .traverse_post_order() + .map(|link| link.borrow().val) + .collect::>(); + let expected = vec![7, 8, 3, 1, 11, 5, 14, 6, 2, 0]; + assert_eq!(result, expected); + } + + #[test] + fn test_display() { + let tree = TreeNode::try_from_iter(SAMPLE).unwrap(); + let display = tree.display().to_string(); + let result = display.lines().map(str::trim_end).collect::>(); + let expected = " + Some(0) + ┌───────────────────┴───────────────────┐ + Some(1) Some(2) + ┌─────────┴─────────┐ ┌─────────┴─────────┐ + Some(3) None Some(5) Some(6) + ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ +Some(7) Some(8) None None Some(11) None None Some(14) +"[1..] // 去掉开头的换行符 + .lines() + .map(str::trim_end) + .collect::>(); + assert_eq!(result, expected); + } +} diff --git a/codes/rust/src/binary_tree/link_impl.rs b/codes/rust/src/binary_tree/link_impl.rs new file mode 100644 index 0000000000..4f31d5c83c --- /dev/null +++ b/codes/rust/src/binary_tree/link_impl.rs @@ -0,0 +1,175 @@ +use super::traverse::{InOrder, LevelOrder, LevelOrderIncludeNulls, PostOrder, PreOrder}; +use super::{BinaryTree, TreeLink, TreeNode}; +use crate::fmt::Write; +use std::convert::Infallible; +use std::fmt; +use std::rc::Rc; + +impl BinaryTree for TreeLink { + type Element = T; + type Error = &'static str; + type TraverseItem = Self; + + fn len(&self) -> usize { + // 中序遍历内存压力最小。 + Rc::clone(self).traverse_in_order().count() + } + + fn is_empty(&self) -> bool { + false + } + + fn height(&self) -> Option { + Some(self.borrow().height) + } + + fn update_height(&self) { + for link in Rc::clone(self).traverse_post_order() { + let borrow = link.borrow(); + let mut height = 0; + if let Some(left) = &borrow.left { + height = left.borrow().height + 1; + } + if let Some(right) = &borrow.right { + height = height.max(right.borrow().height + 1); + } + drop(borrow); + link.borrow_mut().height = height; + } + } + + fn try_from_slice(slice: &[Option]) -> Result + where + Self::Element: Clone, + { + let iter = slice.iter().cloned(); + TreeNode::try_from_iter(iter).ok_or("切片为空") + } + + fn try_from_array( + array: [Option; N], + ) -> Result { + let iter = array.into_iter(); + TreeNode::try_from_iter(iter).ok_or("数组为空") + } + + fn try_from_vec(vec: Vec>) -> Result { + let iter = vec.into_iter(); + TreeNode::try_from_iter(iter).ok_or("向量为空") + } + + fn traverse_level_order(self) -> impl Iterator { + LevelOrder::new(self) + } + + fn traverse_pre_order(self) -> impl Iterator { + PreOrder::new(self) + } + + fn traverse_in_order(self) -> impl Iterator { + InOrder::new(self) + } + + fn traverse_post_order(self) -> impl Iterator { + PostOrder::new(self) + } + + fn display(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let root = Some(self); + TreeDisplay { root } + } +} + +impl BinaryTree for Option> { + type Element = T; + type Error = Infallible; + type TraverseItem = TreeLink; + + fn len(&self) -> usize { + self.as_ref().map_or(0, TreeLink::len) + } + + fn is_empty(&self) -> bool { + self.is_none() + } + + fn height(&self) -> Option { + self.as_ref()?.height() + } + + fn update_height(&self) { + if let Some(link) = &self { + link.update_height(); + } + } + + fn try_from_slice(slice: &[Option]) -> Result + where + Self::Element: Clone, + { + let iter = slice.iter().cloned(); + Ok(TreeNode::try_from_iter(iter)) + } + + fn try_from_array( + array: [Option; N], + ) -> Result { + let iter = array.into_iter(); + Ok(TreeNode::try_from_iter(iter)) + } + + fn try_from_vec(vec: Vec>) -> Result { + let iter = vec.into_iter(); + Ok(TreeNode::try_from_iter(iter)) + } + + fn traverse_level_order(self) -> impl Iterator { + self.into_iter().flat_map(TreeLink::traverse_level_order) + } + + fn traverse_pre_order(self) -> impl Iterator { + self.into_iter().flat_map(TreeLink::traverse_pre_order) + } + + fn traverse_in_order(self) -> impl Iterator { + self.into_iter().flat_map(TreeLink::traverse_in_order) + } + + fn traverse_post_order(self) -> impl Iterator { + self.into_iter().flat_map(TreeLink::traverse_post_order) + } + + fn display(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let root = self.as_ref(); + TreeDisplay { root } + } +} + +struct TreeDisplay<'a, T> { + root: Option<&'a TreeLink>, +} + +impl fmt::Display for TreeDisplay<'_, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Some(root) = self.root.cloned() else { + return Ok(()); + }; + let iter = LevelOrderIncludeNulls::new(root).map(|node| { + if let Some(node) = node { + format!("Some({})", node.borrow().val) + } else { + String::from("None") + } + }); + f.write_complete_binary_tree(iter) + } +} diff --git a/codes/rust/src/binary_tree/traverse.rs b/codes/rust/src/binary_tree/traverse.rs new file mode 100644 index 0000000000..8af74ff4d4 --- /dev/null +++ b/codes/rust/src/binary_tree/traverse.rs @@ -0,0 +1,9 @@ +pub(crate) use self::in_order::InOrder; +pub(crate) use self::level_order::{LevelOrder, LevelOrderIncludeNulls}; +pub(crate) use self::post_order::PostOrder; +pub(crate) use self::pre_order::PreOrder; + +mod in_order; +mod level_order; +mod post_order; +mod pre_order; diff --git a/codes/rust/src/binary_tree/traverse/in_order.rs b/codes/rust/src/binary_tree/traverse/in_order.rs new file mode 100644 index 0000000000..4c940a81c5 --- /dev/null +++ b/codes/rust/src/binary_tree/traverse/in_order.rs @@ -0,0 +1,77 @@ +use super::super::TreeLink; +use std::mem; + +#[derive(Debug, Clone)] +pub(crate) struct InOrder { + state: State, + stack: Vec>, +} + +#[derive(Debug, Clone)] +enum State { + Push(TreeLink), + Pop, + Done, +} + +impl InOrder { + pub(crate) fn new(root: TreeLink) -> Self { + let state = State::Push(root); + let stack = Vec::new(); + Self { state, stack } + } +} + +impl Iterator for InOrder { + type Item = TreeLink; + + fn next(&mut self) -> Option { + loop { + match &mut self.state { + // 处于此状态时,如果当前节点没有左子节点,它不会被推入栈中,而是直接返回。 + // 原则上,没有左子节点的节点也可入栈,并在下一次循环中弹出,但这样会多出 + // 一次不必要的入栈和弹栈操作,降低效率。 + State::Push(link) => { + let borrow = link.borrow(); + let left = borrow.left.clone(); + let right = borrow.right.clone(); + drop(borrow); + // 如果存在左子节点,继续压栈。 + if let Some(left) = left { + let link = mem::replace(link, left); + self.stack.push(link); + continue; + } + // 如果不存在左子节点,但存在右子节点,则压入右子节点,否则弹出当前节点的父节点。 + let new_state = if let Some(right) = right { + State::Push(right) + } else { + State::Pop + }; + let old_state = mem::replace(&mut self.state, new_state); + let State::Push(link) = old_state else { + unreachable!() + }; + return Some(link); + } + + State::Pop => { + if let Some(link) = self.stack.pop() { + let right = link.borrow().right.clone(); + if let Some(right) = right { + self.state = State::Push(right); + } + return Some(link); + } + self.state = State::Done; + // 也可在下一循环中返回,但会多出一次分支跳转。 + return None; + } + + State::Done => { + return None; + } + } + } + } +} diff --git a/codes/rust/src/binary_tree/traverse/level_order.rs b/codes/rust/src/binary_tree/traverse/level_order.rs new file mode 100644 index 0000000000..ed3f95c2b0 --- /dev/null +++ b/codes/rust/src/binary_tree/traverse/level_order.rs @@ -0,0 +1,81 @@ +use super::super::{BinaryTree, TreeLink}; +use std::collections::VecDeque; + +#[derive(Debug, Clone)] +pub(crate) struct LevelOrder { + queue: VecDeque>, +} + +impl LevelOrder { + pub(crate) fn new(root: TreeLink) -> Self { + let mut queue = VecDeque::new(); + queue.push_back(root); + Self { queue } + } +} + +impl Iterator for LevelOrder { + type Item = TreeLink; + + fn next(&mut self) -> Option { + let link = self.queue.pop_front()?; + let borrow = link.borrow(); + if let Some(left) = borrow.left.clone() { + self.queue.push_back(left); + } + if let Some(right) = borrow.right.clone() { + self.queue.push_back(right); + } + drop(borrow); + Some(link) + } +} + +#[derive(Debug, Clone)] +pub(crate) struct LevelOrderIncludeNulls { + len: usize, + queue: VecDeque>>, +} + +impl LevelOrderIncludeNulls { + pub(crate) fn new(root: TreeLink) -> Self { + // 需要额外一次后序遍历的开销。 + // 如果不对外暴露节点并保证不变量被维护,这行代码可以删除。 + root.update_height(); + let height = root.borrow().height; + let len = (1 << (height + 1)) - 1; + let mut queue = VecDeque::new(); + queue.push_back(Some(root)); + Self { len, queue } + } +} + +impl Iterator for LevelOrderIncludeNulls { + type Item = Option>; + + fn next(&mut self) -> Option { + let link = self.queue.pop_front()?; + self.len -= 1; + if let Some(link) = &link { + let borrow = link.borrow(); + if let Some(left) = borrow.left.clone() { + self.queue.push_back(Some(left)); + } else if self.queue.len() < self.len { + self.queue.push_back(None); + } + if let Some(right) = borrow.right.clone() { + self.queue.push_back(Some(right)); + } else if self.queue.len() < self.len { + self.queue.push_back(None); + } + } else { + if self.queue.len() < self.len { + self.queue.push_back(None); + } + if self.queue.len() < self.len { + self.queue.push_back(None); + } + } + Some(link) + } +} diff --git a/codes/rust/src/binary_tree/traverse/post_order.rs b/codes/rust/src/binary_tree/traverse/post_order.rs new file mode 100644 index 0000000000..603ed7242c --- /dev/null +++ b/codes/rust/src/binary_tree/traverse/post_order.rs @@ -0,0 +1,61 @@ +use super::super::TreeLink; + +#[derive(Debug, Clone)] +pub(crate) struct PostOrder { + stack: Vec>, +} + +#[derive(Debug, Clone)] +struct Frame { + link: TreeLink, + visited: bool, +} + +impl PostOrder { + pub(crate) fn new(root: TreeLink) -> Self { + let frame = Frame { + link: root, + visited: false, + }; + let stack = vec![frame]; + Self { stack } + } +} + +impl Iterator for PostOrder { + type Item = TreeLink; + + fn next(&mut self) -> Option { + while let Some(mut frame) = self.stack.pop() { + if frame.visited { + return Some(frame.link); + } + + let borrow = frame.link.borrow(); + let right = borrow.right.clone(); + let left = borrow.left.clone(); + drop(borrow); + + frame.visited = true; + self.stack.push(frame); + + if let Some(right) = right { + let right = Frame { + link: right, + visited: false, + }; + self.stack.push(right); + } + + if let Some(left) = left { + let left = Frame { + link: left, + visited: false, + }; + self.stack.push(left); + } + } + + None + } +} diff --git a/codes/rust/src/binary_tree/traverse/pre_order.rs b/codes/rust/src/binary_tree/traverse/pre_order.rs new file mode 100644 index 0000000000..4d60012bfb --- /dev/null +++ b/codes/rust/src/binary_tree/traverse/pre_order.rs @@ -0,0 +1,30 @@ +use super::super::TreeLink; + +#[derive(Debug, Clone)] +pub(crate) struct PreOrder { + stack: Vec>, +} + +impl PreOrder { + pub(crate) fn new(root: TreeLink) -> Self { + let stack = vec![root]; + Self { stack } + } +} + +impl Iterator for PreOrder { + type Item = TreeLink; + + fn next(&mut self) -> Option { + let link = self.stack.pop()?; + let borrow = link.borrow(); + if let Some(right) = borrow.right.clone() { + self.stack.push(right); + } + if let Some(left) = borrow.left.clone() { + self.stack.push(left); + } + drop(borrow); + Some(link) + } +} diff --git a/codes/rust/src/fmt.rs b/codes/rust/src/fmt.rs new file mode 100644 index 0000000000..2b10cf3429 --- /dev/null +++ b/codes/rust/src/fmt.rs @@ -0,0 +1,189 @@ +use std::fmt; + +pub trait Write { + fn write_array(&mut self, iter: I) -> fmt::Result + where + I: IntoIterator; + + fn write_linked_list(&mut self, iter: I) -> fmt::Result + where + I: IntoIterator; + + fn write_complete_binary_tree(&mut self, iter: I) -> fmt::Result + where + I: IntoIterator; +} + +impl Write for W +where + W: fmt::Write, +{ + fn write_array(&mut self, iter: I) -> fmt::Result + where + I: IntoIterator, + { + let mut iter = iter.into_iter(); + let Some(first) = iter.next() else { + return write!(self, "[]"); + }; + write!(self, "[{first}")?; + for item in iter { + write!(self, ", {item}")?; + } + write!(self, "]") + } + + fn write_linked_list(&mut self, iter: I) -> fmt::Result + where + I: IntoIterator, + { + let mut iter = iter.into_iter(); + let Some(first) = iter.next() else { + return Ok(()); + }; + write!(self, "{first}")?; + for item in iter { + write!(self, "-> {item}")?; + } + Ok(()) + } + + fn write_complete_binary_tree(&mut self, iter: I) -> fmt::Result + where + I: IntoIterator, + { + // 此实现暂不考虑节点值的字符串表示存在多行的情况。 + + let mut cache = Vec::new(); + let mut current_level = Vec::new(); + let mut current_depth = 0; + let mut node_width = 0; + + for (index, node) in iter.into_iter().enumerate() { + let depth = if index == usize::MAX { + usize::BITS as usize + } else { + (usize::BITS - 1 - (index + 1).leading_zeros()) as usize + }; + if current_depth != depth { + cache.push(current_level); + current_level = Vec::new(); + current_depth = depth; + } + let node = format!("{node}"); + node_width = node.len().max(node_width); + current_level.push(node); + } + + if cache.is_empty() && current_level.is_empty() { + return Ok(()); + } + + cache.push(current_level); + + let tree_height = current_depth; + let half_node_width_left = node_width / 2; + let half_node_width_right = node_width - half_node_width_left; + + #[derive(Default)] + struct Level { + branches: String, + nodes: String, + } + + let mut margin = 0; + let mut gap = 2; + let mut levels: Vec = (0..=tree_height).map(|_| Level::default()).collect(); + + for (level, nodes) in levels.iter_mut().zip(cache).rev() { + if nodes.len() == 1 { + let root = &nodes[0]; + let half_padding_left = (node_width - root.len()) / 2; + for _ in 0..(margin + half_padding_left) { + level.nodes.push(' '); + } + level.nodes.push_str(root); + break; + } + + let half_gap_left = gap / 2; + let half_gap_right = gap - half_gap_left; + + let mut node_iter = nodes.iter(); + let mut is_left; + + { + let node = node_iter.next().unwrap_or_else(|| unreachable!()); + let padding = node_width - node.len(); + let half_padding_left = padding / 2; + let half_padding_right = padding - half_padding_left; + + for _ in 0..(margin + half_node_width_left) { + level.branches.push(' '); + } + level.branches.push('┌'); + for _ in 1..(half_node_width_right + half_gap_left) { + level.branches.push('─'); + } + level.branches.push('┘'); + + for _ in 0..(margin + half_padding_left) { + level.nodes.push(' '); + } + level.nodes.push_str(node); + for _ in 0..half_padding_right { + level.nodes.push(' '); + } + + is_left = false; + } + + for node in node_iter { + let padding = node_width - node.len(); + let half_padding_left = padding / 2; + let half_padding_right = padding - half_padding_left; + + if is_left { + for _ in 1..(half_node_width_right + gap + half_node_width_left) { + level.branches.push(' '); + } + level.branches.push('┌'); + for _ in 1..(half_node_width_right + half_gap_left) { + level.branches.push('─'); + } + level.branches.push('┘'); + } else { + // 弹出上一个左子节点多加的 '┘'。 + level.branches.pop(); + level.branches.push('┴'); + for _ in 1..(half_gap_right + half_node_width_left) { + level.branches.push('─'); + } + level.branches.push('┐'); + } + + for _ in 0..(gap + half_padding_left) { + level.nodes.push(' '); + } + level.nodes.push_str(node); + for _ in 0..half_padding_right { + level.nodes.push(' '); + } + + is_left = !is_left; + } + + margin += half_node_width_right + half_gap_left; + gap = gap * 2 + node_width; + } + + for (depth, level) in levels.iter().enumerate() { + if depth > 0 { + writeln!(self, "{}", level.branches)?; + } + writeln!(self, "{}", level.nodes)?; + } + + Ok(()) + } +} diff --git a/codes/rust/src/graph_adjacency_list.rs b/codes/rust/src/graph_adjacency_list.rs new file mode 100644 index 0000000000..92550eb42f --- /dev/null +++ b/codes/rust/src/graph_adjacency_list.rs @@ -0,0 +1,132 @@ +use crate::fmt::Write; +use std::borrow::Borrow; +use std::collections::{HashMap, HashSet}; +use std::fmt; +use std::hash::Hash; + +#[derive(Debug, Clone)] +pub struct GraphAdjList(HashMap>); + +impl GraphAdjList +where + V: Eq + Hash, +{ + pub fn new(edges: I) -> Self + where + I: IntoIterator, + V: Clone, + { + edges.into_iter().collect() + } + + pub fn size(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn get(&self, v: &U) -> Option<&HashSet> + where + U: ?Sized + Eq + Hash, + V: Borrow, + { + self.0.get(v) + } + + pub fn get_mut(&mut self, v: &U) -> Option<&mut HashSet> + where + U: ?Sized + Eq + Hash, + V: Borrow, + { + self.0.get_mut(v) + } + + pub fn add_edge(&mut self, v1: V, v2: V) + where + V: Clone, + { + if v1 == v2 { + return; + } + self.0.entry(v1.clone()).or_default().insert(v2.clone()); + self.0.entry(v2).or_default().insert(v1); + } + + pub fn remove_edge(&mut self, v1: &U, v2: &W) + where + U: ?Sized + PartialEq + Eq + Hash, + W: ?Sized + Eq + Hash, + V: Borrow + Borrow, + { + if v1 == v2 { + return; + } + if let Some(neighbors) = self.0.get_mut(v1) { + neighbors.remove(v2); + } + if let Some(neighbors) = self.0.get_mut(v2) { + neighbors.remove(v1); + } + } + + pub fn add_vertex(&mut self, v: V) { + self.0.entry(v).or_default(); + } + + pub fn remove_vertex(&mut self, v: &U) + where + U: ?Sized + Eq + Hash, + V: Borrow, + { + if let Some(neighbors) = self.0.remove(v) { + for neighbor in &neighbors { + // 这里 get_mut 的类型推导失败,可能是类型系统的一个 bug。 + if let Some(neighbors) = self.0.get_mut::(neighbor) { + neighbors.remove(v); + } + } + } + } +} + +impl FromIterator<(V, V)> for GraphAdjList +where + V: Clone + Eq + Hash, +{ + fn from_iter>(iter: I) -> Self { + let mut graph = Self(HashMap::new()); + for (v1, v2) in iter { + graph.add_edge(v1, v2); + } + graph + } +} + +impl FromIterator<[V; 2]> for GraphAdjList +where + V: Clone + Eq + Hash, +{ + fn from_iter>(iter: I) -> Self { + iter.into_iter().map(|[v1, v2]| (v1, v2)).collect() + } +} + +impl fmt::Display for GraphAdjList +where + V: fmt::Display + Eq + Hash, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.0.is_empty() { + return writeln!(f, "[]"); + } + writeln!(f, "[")?; + for (v, neighbors) in &self.0 { + write!(f, " {v}: ")?; + f.write_array(neighbors.iter())?; + writeln!(f, ",")?; + } + writeln!(f, "]") + } +} diff --git a/codes/rust/src/heap.rs b/codes/rust/src/heap.rs new file mode 100644 index 0000000000..1764f78a1b --- /dev/null +++ b/codes/rust/src/heap.rs @@ -0,0 +1,93 @@ +//! 本模块定义了 [`Heap`] trait 以辅助堆的格式化输出。请注意,此 trait 不涉及任何实际的堆操作。 +//! +//! 实现了 [`Heap`] 的类型有: +//! +//! - 标准库的 [`BinaryHeap`] +//! - 任意切片类型 `[T]` +//! +//! 此外,你可以在数组 `[T; N]`、向量 `Vec` 及其他任何可以 unsize 为切片的类型上使用 +//! `<[T] as Heap>` 的所有方法,这得益于 Rust 的点操作符语法糖。详见 *[nomicon]*。 +//! +//! [nomicon]: https://doc.rust-lang.org/stable/nomicon/dot-operator.html + +use crate::fmt::Write; +use std::collections::BinaryHeap; +use std::fmt; + +pub trait Heap { + type Element; + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display; + + fn display_as_tree(&self) -> impl fmt::Display + where + Self::Element: fmt::Display; +} + +impl Heap for BinaryHeap { + type Element = T; + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let slice = self.as_slice(); + ArrayDisplay { slice } + } + + fn display_as_tree(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let slice = self.as_slice(); + TreeDisplay { slice } + } +} + +impl Heap for [T] { + type Element = T; + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let slice = self; + ArrayDisplay { slice } + } + + fn display_as_tree(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let slice = self; + TreeDisplay { slice } + } +} + +struct ArrayDisplay<'a, T> { + slice: &'a [T], +} + +impl fmt::Display for ArrayDisplay<'_, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_array(self.slice) + } +} + +struct TreeDisplay<'a, T> { + slice: &'a [T], +} + +impl fmt::Display for TreeDisplay<'_, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_complete_binary_tree(self.slice) + } +} diff --git a/codes/rust/src/lib.rs b/codes/rust/src/lib.rs index 2883b91047..342e855e21 100644 --- a/codes/rust/src/lib.rs +++ b/codes/rust/src/lib.rs @@ -1 +1,6 @@ +pub mod binary_tree; +pub mod fmt; +pub mod graph_adjacency_list; +pub mod heap; pub mod include; +pub mod linked_list; diff --git a/codes/rust/src/linked_list.rs b/codes/rust/src/linked_list.rs new file mode 100644 index 0000000000..7d1cdc9135 --- /dev/null +++ b/codes/rust/src/linked_list.rs @@ -0,0 +1,115 @@ +//! 本模块仅用于示例代码,不建议在生产环境中使用。 +//! +//! 为了与示例代码中 `Rc>` 保持一致,本模块中的 [`ListLink`] 是前者的 +//! 类型别名而非包装类型。由于孤儿法则,本模块额外定义了 [`LinkedList`] trait 以为其实现关 +//! 联函数和方法,你不必为自己的链表类型定义或实现类似的 trait。为了方便示例代码的编写和阅读, +//! 在本模块中,实现了 [`LinkedList`] 的类型有: +//! +//! - [`ListNode`] +//! - [`ListLink`] +//! - `Option` +//! - `Option` +//! +//! 它们都被视为链表。参考实现时,以上类型作为实现细节不应暴露为公共接口,否则可能发生链表成环, +//! 这会导致内存泄露、迭代无法终止等系列问题。 + +use std::cell::RefCell; +use std::collections::HashMap; +use std::fmt; +use std::hash::Hash; +use std::rc::Rc; + +mod link_impl; +mod node_impl; + +pub trait LinkedList { + type Element; + type Error; + + fn len(&self) -> usize; + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn try_from_slice(slice: &[Self::Element]) -> Result + where + Self: Sized, + Self::Element: Clone; + + fn try_from_array(array: [Self::Element; N]) -> Result + where + Self: Sized; + + fn try_from_vec(vec: Vec) -> Result + where + Self: Sized; + + fn display_as_list(&self) -> impl fmt::Display + where + Self::Element: fmt::Display; + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display; +} + +#[derive(Debug, Clone)] +pub struct ListNode { + pub val: T, + pub next: Option>, +} + +pub type ListLink = Rc>>; + +impl ListNode { + pub fn new(val: T) -> ListLink { + let node = Self { val, next: None }; + ListLink::from(node) + } + + fn try_from_iter(mut iter: I) -> Option + where + I: DoubleEndedIterator, + { + let head = iter.next()?; + + let mut next = None; + for val in iter.rev() { + let node = Self { val, next }; + next = Some(ListLink::from(node)); + } + + Some(Self { val: head, next }) + } +} + +impl From> for ListLink { + fn from(value: ListNode) -> Self { + Rc::new(RefCell::new(value)) + } +} + +impl From> for HashMap> +where + T: Clone + Eq + Hash, +{ + fn from(value: ListNode) -> Self { + let mut map = HashMap::new(); + + let val = value.val.clone(); + let mut next = value.next.clone(); + let link = ListLink::from(value); + map.insert(val, link); + + while let Some(link) = next { + let borrow = link.borrow(); + let val = borrow.val.clone(); + next = borrow.next.clone(); + drop(borrow); + map.insert(val, link); + } + + map + } +} diff --git a/codes/rust/src/linked_list/link_impl.rs b/codes/rust/src/linked_list/link_impl.rs new file mode 100644 index 0000000000..2d357b032a --- /dev/null +++ b/codes/rust/src/linked_list/link_impl.rs @@ -0,0 +1,149 @@ +use super::{LinkedList, ListLink, ListNode}; +use std::convert::Infallible; +use std::fmt; + +impl LinkedList for ListLink { + type Element = T; + type Error = &'static str; + + fn len(&self) -> usize { + let mut count = 1; + let mut next = self.borrow().next.clone(); + while let Some(link) = next { + count += 1; + next = link.borrow().next.clone(); + } + count + } + + fn try_from_slice(slice: &[Self::Element]) -> Result + where + Self::Element: Clone, + { + let iter = slice.iter().cloned(); + ListNode::try_from_iter(iter) + .map(Self::from) + .ok_or("切片为空") + } + + fn try_from_array(array: [Self::Element; N]) -> Result { + let iter = array.into_iter(); + ListNode::try_from_iter(iter) + .map(Self::from) + .ok_or("数组为空") + } + + fn try_from_vec(vec: Vec) -> Result { + let iter = vec.into_iter(); + ListNode::try_from_iter(iter) + .map(Self::from) + .ok_or("向量为空") + } + + fn display_as_list(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = Some(self); + ListDisplay { head } + } + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = Some(self); + ArrayDisplay { head } + } +} + +impl LinkedList for Option> { + type Element = T; + type Error = Infallible; + + fn len(&self) -> usize { + self.as_ref().map_or(0, ListLink::len) + } + + fn try_from_slice(slice: &[Self::Element]) -> Result + where + Self::Element: Clone, + { + let iter = slice.iter().cloned(); + Ok(ListNode::try_from_iter(iter).map(ListLink::from)) + } + + fn try_from_array(array: [Self::Element; N]) -> Result { + let iter = array.into_iter(); + Ok(ListNode::try_from_iter(iter).map(ListLink::from)) + } + + fn try_from_vec(vec: Vec) -> Result { + let iter = vec.into_iter(); + Ok(ListNode::try_from_iter(iter).map(ListLink::from)) + } + + fn display_as_list(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = self.as_ref(); + ListDisplay { head } + } + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = self.as_ref(); + ArrayDisplay { head } + } +} + +struct ListDisplay<'a, T> { + head: Option<&'a ListLink>, +} + +impl fmt::Display for ListDisplay<'_, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Some(head) = self.head else { + return Ok(()); + }; + let borrow = head.borrow(); + write!(f, "{}", borrow.val)?; + let mut next = borrow.next.clone(); + while let Some(link) = next { + let borrow = link.borrow(); + write!(f, " -> {}", borrow.val)?; + next = borrow.next.clone(); + } + Ok(()) + } +} + +struct ArrayDisplay<'a, T> { + head: Option<&'a ListLink>, +} + +impl fmt::Display for ArrayDisplay<'_, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Some(head) = self.head else { + return write!(f, "[]"); + }; + let borrow = head.borrow(); + write!(f, "[{}", borrow.val)?; + let mut next = borrow.next.clone(); + while let Some(link) = next { + let borrow = link.borrow(); + write!(f, ", {}", borrow.val)?; + next = borrow.next.clone(); + } + write!(f, "]") + } +} diff --git a/codes/rust/src/linked_list/node_impl.rs b/codes/rust/src/linked_list/node_impl.rs new file mode 100644 index 0000000000..38bb71a316 --- /dev/null +++ b/codes/rust/src/linked_list/node_impl.rs @@ -0,0 +1,141 @@ +use super::{LinkedList, ListNode}; +use std::convert::Infallible; +use std::fmt; + +impl LinkedList for ListNode { + type Element = T; + type Error = &'static str; + + fn len(&self) -> usize { + let mut count = 1; + let mut next = self.next.clone(); + while let Some(link) = next { + count += 1; + next = link.borrow().next.clone(); + } + count + } + + fn try_from_slice(slice: &[Self::Element]) -> Result + where + Self::Element: Clone, + { + let iter = slice.iter().cloned(); + Self::try_from_iter(iter).ok_or("切片为空") + } + + fn try_from_array(array: [Self::Element; N]) -> Result { + let iter = array.into_iter(); + Self::try_from_iter(iter).ok_or("数组为空") + } + + fn try_from_vec(vec: Vec) -> Result { + let iter = vec.into_iter(); + Self::try_from_iter(iter).ok_or("向量为空") + } + + fn display_as_list(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = Some(self); + ListDisplay { head } + } + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = Some(self); + ArrayDisplay { head } + } +} + +impl LinkedList for Option> { + type Element = T; + type Error = Infallible; + + fn len(&self) -> usize { + self.as_ref().map_or(0, ListNode::len) + } + + fn try_from_slice(slice: &[Self::Element]) -> Result + where + Self::Element: Clone, + { + let iter = slice.iter().cloned(); + Ok(ListNode::try_from_iter(iter)) + } + + fn try_from_array(array: [Self::Element; N]) -> Result { + let iter = array.into_iter(); + Ok(ListNode::try_from_iter(iter)) + } + + fn try_from_vec(vec: Vec) -> Result { + let iter = vec.into_iter(); + Ok(ListNode::try_from_iter(iter)) + } + + fn display_as_list(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = self.as_ref(); + ListDisplay { head } + } + + fn display_as_array(&self) -> impl fmt::Display + where + Self::Element: fmt::Display, + { + let head = self.as_ref(); + ArrayDisplay { head } + } +} + +struct ListDisplay<'a, T> { + head: Option<&'a ListNode>, +} + +impl fmt::Display for ListDisplay<'_, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Some(head) = self.head else { + return Ok(()); + }; + write!(f, "{}", head.val)?; + let mut next = head.next.clone(); + while let Some(link) = next { + let borrow = link.borrow(); + write!(f, " -> {}", borrow.val)?; + next = borrow.next.clone(); + } + Ok(()) + } +} + +struct ArrayDisplay<'a, T> { + head: Option<&'a ListNode>, +} + +impl fmt::Display for ArrayDisplay<'_, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Some(head) = self.head else { + return write!(f, "[]"); + }; + write!(f, "[{}", head.val)?; + let mut next = head.next.clone(); + while let Some(link) = next { + let borrow = link.borrow(); + write!(f, ", {}", borrow.val)?; + next = borrow.next.clone(); + } + write!(f, "]") + } +} From 7242649302dfe340f81da6517537b77b2e57822f Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 18:59:47 +0800 Subject: [PATCH 005/109] fix: remove extra asterisks turning comment into outer doc comment First of all, these comments should not be doc comments because they do not document or explain any bit of the crates. Secondly, they should never be outer doc comments, as outer doc comments document items right below rather than the crates. It is just wrong. --- codes/rust/chapter_hashing/array_hash_map.rs | 2 +- codes/rust/chapter_sorting/merge_sort.rs | 2 +- codes/rust/chapter_sorting/quick_sort.rs | 2 +- codes/rust/chapter_tree/binary_tree.rs | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/codes/rust/chapter_hashing/array_hash_map.rs b/codes/rust/chapter_hashing/array_hash_map.rs index 2eff4f435d..c142041c8a 100644 --- a/codes/rust/chapter_hashing/array_hash_map.rs +++ b/codes/rust/chapter_hashing/array_hash_map.rs @@ -1,4 +1,4 @@ -/** +/* * File: array_hash_map.rs * Created Time: 2023-2-18 * Author: xBLACICEx (xBLACKICEx@outlook.com) diff --git a/codes/rust/chapter_sorting/merge_sort.rs b/codes/rust/chapter_sorting/merge_sort.rs index 6b28e8b011..cded284bb4 100644 --- a/codes/rust/chapter_sorting/merge_sort.rs +++ b/codes/rust/chapter_sorting/merge_sort.rs @@ -1,4 +1,4 @@ -/** +/* * File: merge_sort.rs * Created Time: 2023-02-14 * Author: xBLACKICEx (xBLACKICEx@outlook.com) diff --git a/codes/rust/chapter_sorting/quick_sort.rs b/codes/rust/chapter_sorting/quick_sort.rs index b97fa7b266..7f88dfaba1 100644 --- a/codes/rust/chapter_sorting/quick_sort.rs +++ b/codes/rust/chapter_sorting/quick_sort.rs @@ -1,4 +1,4 @@ -/** +/* * File: quick_sort.rs * Created Time: 2023-02-16 * Author: xBLACKICEx (xBLACKICE@outlook.com) diff --git a/codes/rust/chapter_tree/binary_tree.rs b/codes/rust/chapter_tree/binary_tree.rs index 5843845da5..277de0ec89 100644 --- a/codes/rust/chapter_tree/binary_tree.rs +++ b/codes/rust/chapter_tree/binary_tree.rs @@ -1,8 +1,9 @@ -/** +/* * File: binary_tree.rs * Created Time: 2023-02-27 * Author: xBLACKICEx (xBLACKICE@outlook.com) */ + use std::rc::Rc; use hello_algo_rust::include::{print_util, TreeNode}; From 81ffbfe4e22073e1847f80efe0c70f595ca7fa09 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 19:36:09 +0800 Subject: [PATCH 006/109] refactor: adjust visibility according to codes/rust/GUIDELINES.md --- .../chapter_array_and_linkedlist/array.rs | 12 +++++----- .../chapter_array_and_linkedlist/my_list.rs | 2 +- codes/rust/chapter_backtracking/n_queens.rs | 4 ++-- .../chapter_backtracking/permutations_i.rs | 4 ++-- .../chapter_backtracking/permutations_ii.rs | 4 ++-- .../preorder_traversal_i_compact.rs | 4 ++-- .../preorder_traversal_ii_compact.rs | 4 ++-- .../preorder_traversal_iii_compact.rs | 4 ++-- .../preorder_traversal_iii_template.rs | 2 +- .../rust/chapter_backtracking/subset_sum_i.rs | 4 ++-- .../subset_sum_i_naive.rs | 4 ++-- .../chapter_backtracking/subset_sum_ii.rs | 4 ++-- .../binary_search_recur.rs | 4 ++-- .../chapter_divide_and_conquer/build_tree.rs | 2 +- .../rust/chapter_divide_and_conquer/hanota.rs | 4 ++-- .../climbing_stairs_backtrack.rs | 4 ++-- .../climbing_stairs_constraint_dp.rs | 4 ++-- .../climbing_stairs_dfs.rs | 4 ++-- .../climbing_stairs_dfs_mem.rs | 4 ++-- .../climbing_stairs_dp.rs | 6 ++--- .../coin_change.rs | 6 ++--- .../coin_change_ii.rs | 6 ++--- .../edit_distance.rs | 10 ++++----- .../chapter_dynamic_programming/knapsack.rs | 10 ++++----- .../min_cost_climbing_stairs_dp.rs | 6 ++--- .../min_path_sum.rs | 10 ++++----- .../unbounded_knapsack.rs | 6 ++--- .../chapter_graph/graph_adjacency_matrix.rs | 4 ++-- codes/rust/chapter_graph/graph_bfs.rs | 2 +- codes/rust/chapter_graph/graph_dfs.rs | 2 +- .../rust/chapter_greedy/coin_change_greedy.rs | 2 +- .../chapter_greedy/fractional_knapsack.rs | 2 +- codes/rust/chapter_greedy/max_capacity.rs | 2 +- .../chapter_greedy/max_product_cutting.rs | 2 +- codes/rust/chapter_hashing/hash_map.rs | 2 +- .../rust/chapter_hashing/hash_map_chaining.rs | 20 ++++++++--------- .../hash_map_open_addressing.rs | 12 +++++----- codes/rust/chapter_hashing/simple_hash.rs | 8 +++---- codes/rust/chapter_heap/my_heap.rs | 16 +++++++------- codes/rust/chapter_heap/top_k.rs | 2 +- codes/rust/chapter_searching/binary_search.rs | 6 ++--- .../chapter_searching/binary_search_edge.rs | 4 ++-- .../binary_search_insertion.rs | 2 +- .../rust/chapter_searching/hashing_search.rs | 6 ++--- codes/rust/chapter_searching/linear_search.rs | 6 ++--- codes/rust/chapter_sorting/bubble_sort.rs | 6 ++--- codes/rust/chapter_sorting/bucket_sort.rs | 2 +- codes/rust/chapter_sorting/counting_sort.rs | 4 ++-- codes/rust/chapter_sorting/heap_sort.rs | 2 +- codes/rust/chapter_sorting/insertion_sort.rs | 2 +- codes/rust/chapter_sorting/merge_sort.rs | 2 +- codes/rust/chapter_sorting/quick_sort.rs | 6 ++--- codes/rust/chapter_sorting/radix_sort.rs | 2 +- codes/rust/chapter_sorting/selection_sort.rs | 4 ++-- .../chapter_stack_and_queue/array_deque.rs | 12 +++++----- .../chapter_stack_and_queue/array_queue.rs | 18 +++++++-------- .../chapter_stack_and_queue/array_stack.rs | 16 +++++++------- codes/rust/chapter_stack_and_queue/deque.rs | 2 +- .../linkedlist_deque.rs | 6 ++--- codes/rust/chapter_stack_and_queue/queue.rs | 2 +- codes/rust/chapter_stack_and_queue/stack.rs | 2 +- codes/rust/chapter_tree/array_binary_tree.rs | 22 +++++++++---------- codes/rust/chapter_tree/avl_tree.rs | 12 +++++----- codes/rust/chapter_tree/binary_tree_bfs.rs | 2 +- codes/rust/chapter_tree/binary_tree_dfs.rs | 6 ++--- 65 files changed, 184 insertions(+), 184 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/array.rs b/codes/rust/chapter_array_and_linkedlist/array.rs index 448099f5d1..ac59f3e8ac 100644 --- a/codes/rust/chapter_array_and_linkedlist/array.rs +++ b/codes/rust/chapter_array_and_linkedlist/array.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::print_util; use rand::Rng; /* 随机访问元素 */ -fn random_access(nums: &[i32]) -> i32 { +pub fn random_access(nums: &[i32]) -> i32 { // 在区间 [0, nums.len()) 中随机抽取一个数字 let random_index = rand::rng().random_range(0..nums.len()); // 获取并返回随机元素 @@ -17,7 +17,7 @@ fn random_access(nums: &[i32]) -> i32 { } /* 扩展数组长度 */ -fn extend(nums: &[i32], enlarge: usize) -> Vec { +pub fn extend(nums: &[i32], enlarge: usize) -> Vec { // 初始化一个扩展长度后的数组 let mut res: Vec = vec![0; nums.len() + enlarge]; // 将原数组中的所有元素复制到新 @@ -28,7 +28,7 @@ fn extend(nums: &[i32], enlarge: usize) -> Vec { } /* 在数组的索引 index 处插入元素 num */ -fn insert(nums: &mut [i32], num: i32, index: usize) { +pub fn insert(nums: &mut [i32], num: i32, index: usize) { // 把索引 index 以及之后的所有元素向后移动一位 for i in (index + 1..nums.len()).rev() { nums[i] = nums[i - 1]; @@ -38,7 +38,7 @@ fn insert(nums: &mut [i32], num: i32, index: usize) { } /* 删除索引 index 处的元素 */ -fn remove(nums: &mut [i32], index: usize) { +pub fn remove(nums: &mut [i32], index: usize) { // 把索引 index 之后的所有元素向前移动一位 for i in index..nums.len() - 1 { nums[i] = nums[i + 1]; @@ -46,7 +46,7 @@ fn remove(nums: &mut [i32], index: usize) { } /* 遍历数组 */ -fn traverse(nums: &[i32]) { +pub fn traverse(nums: &[i32]) { let mut _count = 0; // 通过索引遍历数组 for i in 0..nums.len() { @@ -60,7 +60,7 @@ fn traverse(nums: &[i32]) { } /* 在数组中查找指定元素 */ -fn find(nums: &[i32], target: i32) -> Option { +pub fn find(nums: &[i32], target: i32) -> Option { for i in 0..nums.len() { if nums[i] == target { return Some(i); diff --git a/codes/rust/chapter_array_and_linkedlist/my_list.rs b/codes/rust/chapter_array_and_linkedlist/my_list.rs index 566f8d830a..ba5d0026e9 100644 --- a/codes/rust/chapter_array_and_linkedlist/my_list.rs +++ b/codes/rust/chapter_array_and_linkedlist/my_list.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::print_util; /* 列表类 */ #[allow(dead_code)] -struct MyList { +pub struct MyList { arr: Vec, // 数组(存储列表元素) capacity: usize, // 列表容量 size: usize, // 列表长度(当前元素数量) diff --git a/codes/rust/chapter_backtracking/n_queens.rs b/codes/rust/chapter_backtracking/n_queens.rs index cf727a13eb..f37e2435f5 100644 --- a/codes/rust/chapter_backtracking/n_queens.rs +++ b/codes/rust/chapter_backtracking/n_queens.rs @@ -39,7 +39,7 @@ fn backtrack( } /* 求解 n 皇后 */ -fn n_queens(n: usize) -> Vec>> { +pub fn n_queens(n: usize) -> Vec>> { // 初始化 n*n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位 let mut state: Vec> = vec![vec!["#".to_string(); n]; n]; let mut cols = vec![false; n]; // 记录列是否有皇后 @@ -61,7 +61,7 @@ fn n_queens(n: usize) -> Vec>> { } /* Driver Code */ -pub fn main() { +fn main() { let n: usize = 4; let res = n_queens(n); diff --git a/codes/rust/chapter_backtracking/permutations_i.rs b/codes/rust/chapter_backtracking/permutations_i.rs index 3e2eec41f3..28d2f241c9 100644 --- a/codes/rust/chapter_backtracking/permutations_i.rs +++ b/codes/rust/chapter_backtracking/permutations_i.rs @@ -29,14 +29,14 @@ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: & } /* 全排列 I */ -fn permutations_i(nums: &mut [i32]) -> Vec> { +pub fn permutations_i(nums: &mut [i32]) -> Vec> { let mut res = Vec::new(); // 状态(子集) backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res); res } /* Driver Code */ -pub fn main() { +fn main() { let mut nums = [1, 2, 3]; let res = permutations_i(&mut nums); diff --git a/codes/rust/chapter_backtracking/permutations_ii.rs b/codes/rust/chapter_backtracking/permutations_ii.rs index d2db569289..d6ad37826a 100644 --- a/codes/rust/chapter_backtracking/permutations_ii.rs +++ b/codes/rust/chapter_backtracking/permutations_ii.rs @@ -33,14 +33,14 @@ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: & } /* 全排列 II */ -fn permutations_ii(nums: &mut [i32]) -> Vec> { +pub fn permutations_ii(nums: &mut [i32]) -> Vec> { let mut res = Vec::new(); backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res); res } /* Driver Code */ -pub fn main() { +fn main() { let mut nums = [1, 2, 2]; let res = permutations_ii(&mut nums); diff --git a/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs b/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs index fc69939522..1b80c030aa 100644 --- a/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs +++ b/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; use std::{cell::RefCell, rc::Rc}; /* 前序遍历:例题一 */ -fn pre_order(res: &mut Vec>>, root: Option<&Rc>>) { +pub fn pre_order(res: &mut Vec>>, root: Option<&Rc>>) { if root.is_none() { return; } @@ -23,7 +23,7 @@ fn pre_order(res: &mut Vec>>, root: Option<&Rc>>>, path: &mut Vec>>, root: Option<&Rc>>, @@ -31,7 +31,7 @@ fn pre_order( } /* Driver Code */ -pub fn main() { +fn main() { let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); println!("初始化二叉树"); print_util::print_tree(root.as_ref().unwrap()); diff --git a/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs b/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs index 9e54e66bd0..b6b9b9ec5b 100644 --- a/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs +++ b/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; use std::{cell::RefCell, rc::Rc}; /* 前序遍历:例题三 */ -fn pre_order( +pub fn pre_order( res: &mut Vec>>>, path: &mut Vec>>, root: Option<&Rc>>, @@ -32,7 +32,7 @@ fn pre_order( } /* Driver Code */ -pub fn main() { +fn main() { let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); println!("初始化二叉树"); print_util::print_tree(root.as_ref().unwrap()); diff --git a/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs b/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs index e7681b11b5..1e0426a65d 100644 --- a/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs +++ b/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs @@ -68,7 +68,7 @@ fn backtrack( } /* Driver Code */ -pub fn main() { +fn main() { let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); println!("初始化二叉树"); print_util::print_tree(root.as_ref().unwrap()); diff --git a/codes/rust/chapter_backtracking/subset_sum_i.rs b/codes/rust/chapter_backtracking/subset_sum_i.rs index 052181d60d..755cb09c1a 100644 --- a/codes/rust/chapter_backtracking/subset_sum_i.rs +++ b/codes/rust/chapter_backtracking/subset_sum_i.rs @@ -35,7 +35,7 @@ fn backtrack( } /* 求解子集和 I */ -fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec> { +pub fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec> { let mut state = Vec::new(); // 状态(子集) nums.sort(); // 对 nums 进行排序 let start = 0; // 遍历起始点 @@ -45,7 +45,7 @@ fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec> { } /* Driver Code */ -pub fn main() { +fn main() { let mut nums = [3, 4, 5]; let target = 9; diff --git a/codes/rust/chapter_backtracking/subset_sum_i_naive.rs b/codes/rust/chapter_backtracking/subset_sum_i_naive.rs index ab28a2f6a6..550fe0b241 100644 --- a/codes/rust/chapter_backtracking/subset_sum_i_naive.rs +++ b/codes/rust/chapter_backtracking/subset_sum_i_naive.rs @@ -33,7 +33,7 @@ fn backtrack( } /* 求解子集和 I(包含重复子集) */ -fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec> { +pub fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec> { let mut state = Vec::new(); // 状态(子集) let total = 0; // 子集和 let mut res = Vec::new(); // 结果列表(子集列表) @@ -42,7 +42,7 @@ fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec> { } /* Driver Code */ -pub fn main() { +fn main() { let nums = [3, 4, 5]; let target = 9; diff --git a/codes/rust/chapter_backtracking/subset_sum_ii.rs b/codes/rust/chapter_backtracking/subset_sum_ii.rs index 389bae711d..b88cb0f2c2 100644 --- a/codes/rust/chapter_backtracking/subset_sum_ii.rs +++ b/codes/rust/chapter_backtracking/subset_sum_ii.rs @@ -40,7 +40,7 @@ fn backtrack( } /* 求解子集和 II */ -fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec> { +pub fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec> { let mut state = Vec::new(); // 状态(子集) nums.sort(); // 对 nums 进行排序 let start = 0; // 遍历起始点 @@ -50,7 +50,7 @@ fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec> { } /* Driver Code */ -pub fn main() { +fn main() { let mut nums = [4, 4, 5]; let target = 9; diff --git a/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs b/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs index b0864cbca6..88b0dab33f 100644 --- a/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs +++ b/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs @@ -24,14 +24,14 @@ fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 { } /* 二分查找 */ -fn binary_search(nums: &[i32], target: i32) -> i32 { +pub fn binary_search(nums: &[i32], target: i32) -> i32 { let n = nums.len() as i32; // 求解问题 f(0, n-1) dfs(nums, target, 0, n - 1) } /* Driver Code */ -pub fn main() { +fn main() { let target = 6; let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; diff --git a/codes/rust/chapter_divide_and_conquer/build_tree.rs b/codes/rust/chapter_divide_and_conquer/build_tree.rs index e13ae641bb..9eeb9cec1c 100644 --- a/codes/rust/chapter_divide_and_conquer/build_tree.rs +++ b/codes/rust/chapter_divide_and_conquer/build_tree.rs @@ -33,7 +33,7 @@ fn dfs( } /* 构建二叉树 */ -fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option>> { +pub fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option>> { // 初始化哈希表,存储 inorder 元素到索引的映射 let mut inorder_map: HashMap = HashMap::new(); for i in 0..inorder.len() { diff --git a/codes/rust/chapter_divide_and_conquer/hanota.rs b/codes/rust/chapter_divide_and_conquer/hanota.rs index 92880a0bcd..87a65ed7a1 100644 --- a/codes/rust/chapter_divide_and_conquer/hanota.rs +++ b/codes/rust/chapter_divide_and_conquer/hanota.rs @@ -30,14 +30,14 @@ fn dfs(i: i32, src: &mut Vec, buf: &mut Vec, tar: &mut Vec) { } /* 求解汉诺塔问题 */ -fn solve_hanota(A: &mut Vec, B: &mut Vec, C: &mut Vec) { +pub fn solve_hanota(A: &mut Vec, B: &mut Vec, C: &mut Vec) { let n = A.len() as i32; // 将 A 顶部 n 个圆盘借助 B 移到 C dfs(n, A, B, C); } /* Driver Code */ -pub fn main() { +fn main() { let mut A = vec![5, 4, 3, 2, 1]; let mut B = Vec::new(); let mut C = Vec::new(); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs index 03211b5db1..5637111822 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs @@ -23,7 +23,7 @@ fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) { } /* 爬楼梯:回溯 */ -fn climbing_stairs_backtrack(n: usize) -> i32 { +pub fn climbing_stairs_backtrack(n: usize) -> i32 { let choices = vec![1, 2]; // 可选择向上爬 1 阶或 2 阶 let state = 0; // 从第 0 阶开始爬 let mut res = Vec::new(); @@ -33,7 +33,7 @@ fn climbing_stairs_backtrack(n: usize) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let n: usize = 9; let res = climbing_stairs_backtrack(n); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs index 24078307bc..68213d7119 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs @@ -5,7 +5,7 @@ */ /* 带约束爬楼梯:动态规划 */ -fn climbing_stairs_constraint_dp(n: usize) -> i32 { +pub fn climbing_stairs_constraint_dp(n: usize) -> i32 { if n == 1 || n == 2 { return 1; }; @@ -25,7 +25,7 @@ fn climbing_stairs_constraint_dp(n: usize) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let n: usize = 9; let res = climbing_stairs_constraint_dp(n); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs index 8695f59250..1c97124c1c 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs @@ -16,12 +16,12 @@ fn dfs(i: usize) -> i32 { } /* 爬楼梯:搜索 */ -fn climbing_stairs_dfs(n: usize) -> i32 { +pub fn climbing_stairs_dfs(n: usize) -> i32 { dfs(n) } /* Driver Code */ -pub fn main() { +fn main() { let n: usize = 9; let res = climbing_stairs_dfs(n); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs index 43d95896bf..e54204ad63 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs @@ -22,14 +22,14 @@ fn dfs(i: usize, mem: &mut [i32]) -> i32 { } /* 爬楼梯:记忆化搜索 */ -fn climbing_stairs_dfs_mem(n: usize) -> i32 { +pub fn climbing_stairs_dfs_mem(n: usize) -> i32 { // mem[i] 记录爬到第 i 阶的方案总数,-1 代表无记录 let mut mem = vec![-1; n + 1]; dfs(n, &mut mem) } /* Driver Code */ -pub fn main() { +fn main() { let n: usize = 9; let res = climbing_stairs_dfs_mem(n); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs index ec948e7eaf..8863338d3f 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs @@ -5,7 +5,7 @@ */ /* 爬楼梯:动态规划 */ -fn climbing_stairs_dp(n: usize) -> i32 { +pub fn climbing_stairs_dp(n: usize) -> i32 { // 已知 dp[1] 和 dp[2] ,返回之 if n == 1 || n == 2 { return n as i32; @@ -23,7 +23,7 @@ fn climbing_stairs_dp(n: usize) -> i32 { } /* 爬楼梯:空间优化后的动态规划 */ -fn climbing_stairs_dp_comp(n: usize) -> i32 { +pub fn climbing_stairs_dp_comp(n: usize) -> i32 { if n == 1 || n == 2 { return n as i32; } @@ -37,7 +37,7 @@ fn climbing_stairs_dp_comp(n: usize) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let n: usize = 9; let res = climbing_stairs_dp(n); diff --git a/codes/rust/chapter_dynamic_programming/coin_change.rs b/codes/rust/chapter_dynamic_programming/coin_change.rs index 33922a2d51..8e3d5922aa 100644 --- a/codes/rust/chapter_dynamic_programming/coin_change.rs +++ b/codes/rust/chapter_dynamic_programming/coin_change.rs @@ -5,7 +5,7 @@ */ /* 零钱兑换:动态规划 */ -fn coin_change_dp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_dp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); let max = amt + 1; // 初始化 dp 表 @@ -34,7 +34,7 @@ fn coin_change_dp(coins: &[i32], amt: usize) -> i32 { } /* 零钱兑换:空间优化后的动态规划 */ -fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); let max = amt + 1; // 初始化 dp 表 @@ -61,7 +61,7 @@ fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let coins = [1, 2, 5]; let amt: usize = 4; diff --git a/codes/rust/chapter_dynamic_programming/coin_change_ii.rs b/codes/rust/chapter_dynamic_programming/coin_change_ii.rs index 12702bdf37..cf0990e9dc 100644 --- a/codes/rust/chapter_dynamic_programming/coin_change_ii.rs +++ b/codes/rust/chapter_dynamic_programming/coin_change_ii.rs @@ -5,7 +5,7 @@ */ /* 零钱兑换 II:动态规划 */ -fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); // 初始化 dp 表 let mut dp = vec![vec![0; amt + 1]; n + 1]; @@ -29,7 +29,7 @@ fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 { } /* 零钱兑换 II:空间优化后的动态规划 */ -fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); // 初始化 dp 表 let mut dp = vec![0; amt + 1]; @@ -50,7 +50,7 @@ fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let coins = [1, 2, 5]; let amt: usize = 5; diff --git a/codes/rust/chapter_dynamic_programming/edit_distance.rs b/codes/rust/chapter_dynamic_programming/edit_distance.rs index d2dcad92c7..0c77b5f365 100644 --- a/codes/rust/chapter_dynamic_programming/edit_distance.rs +++ b/codes/rust/chapter_dynamic_programming/edit_distance.rs @@ -5,7 +5,7 @@ */ /* 编辑距离:暴力搜索 */ -fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 { +pub fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 { // 若 s 和 t 都为空,则返回 0 if i == 0 && j == 0 { return 0; @@ -31,7 +31,7 @@ fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 { } /* 编辑距离:记忆化搜索 */ -fn edit_distance_dfs_mem(s: &str, t: &str, mem: &mut Vec>, i: usize, j: usize) -> i32 { +pub fn edit_distance_dfs_mem(s: &str, t: &str, mem: &mut Vec>, i: usize, j: usize) -> i32 { // 若 s 和 t 都为空,则返回 0 if i == 0 && j == 0 { return 0; @@ -62,7 +62,7 @@ fn edit_distance_dfs_mem(s: &str, t: &str, mem: &mut Vec>, i: usize, j: } /* 编辑距离:动态规划 */ -fn edit_distance_dp(s: &str, t: &str) -> i32 { +pub fn edit_distance_dp(s: &str, t: &str) -> i32 { let (n, m) = (s.len(), t.len()); let mut dp = vec![vec![0; m + 1]; n + 1]; // 状态转移:首行首列 @@ -89,7 +89,7 @@ fn edit_distance_dp(s: &str, t: &str) -> i32 { } /* 编辑距离:空间优化后的动态规划 */ -fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { +pub fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { let (n, m) = (s.len(), t.len()); let mut dp = vec![0; m + 1]; // 状态转移:首行 @@ -118,7 +118,7 @@ fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let s = "bag"; let t = "pack"; let (n, m) = (s.len(), t.len()); diff --git a/codes/rust/chapter_dynamic_programming/knapsack.rs b/codes/rust/chapter_dynamic_programming/knapsack.rs index 9e99b4c044..c7b38c5199 100644 --- a/codes/rust/chapter_dynamic_programming/knapsack.rs +++ b/codes/rust/chapter_dynamic_programming/knapsack.rs @@ -5,7 +5,7 @@ */ /* 0-1 背包:暴力搜索 */ -fn knapsack_dfs(wgt: &[i32], val: &[i32], i: usize, c: usize) -> i32 { +pub fn knapsack_dfs(wgt: &[i32], val: &[i32], i: usize, c: usize) -> i32 { // 若已选完所有物品或背包无剩余容量,则返回价值 0 if i == 0 || c == 0 { return 0; @@ -22,7 +22,7 @@ fn knapsack_dfs(wgt: &[i32], val: &[i32], i: usize, c: usize) -> i32 { } /* 0-1 背包:记忆化搜索 */ -fn knapsack_dfs_mem(wgt: &[i32], val: &[i32], mem: &mut Vec>, i: usize, c: usize) -> i32 { +pub fn knapsack_dfs_mem(wgt: &[i32], val: &[i32], mem: &mut Vec>, i: usize, c: usize) -> i32 { // 若已选完所有物品或背包无剩余容量,则返回价值 0 if i == 0 || c == 0 { return 0; @@ -44,7 +44,7 @@ fn knapsack_dfs_mem(wgt: &[i32], val: &[i32], mem: &mut Vec>, i: usize, } /* 0-1 背包:动态规划 */ -fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); // 初始化 dp 表 let mut dp = vec![vec![0; cap + 1]; n + 1]; @@ -67,7 +67,7 @@ fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { } /* 0-1 背包:空间优化后的动态规划 */ -fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); // 初始化 dp 表 let mut dp = vec![0; cap + 1]; @@ -85,7 +85,7 @@ fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let wgt = [10, 20, 30, 40, 50]; let val = [50, 120, 150, 210, 240]; let cap: usize = 50; diff --git a/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs b/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs index 146068e594..d54d776888 100644 --- a/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs +++ b/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs @@ -7,7 +7,7 @@ use std::cmp; /* 爬楼梯最小代价:动态规划 */ -fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 { +pub fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 { let n = cost.len() - 1; if n == 1 || n == 2 { return cost[n]; @@ -25,7 +25,7 @@ fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 { } /* 爬楼梯最小代价:空间优化后的动态规划 */ -fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { +pub fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { let n = cost.len() - 1; if n == 1 || n == 2 { return cost[n]; @@ -40,7 +40,7 @@ fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1]; println!("输入楼梯的代价列表为 {:?}", &cost); diff --git a/codes/rust/chapter_dynamic_programming/min_path_sum.rs b/codes/rust/chapter_dynamic_programming/min_path_sum.rs index bb7b9c8e10..4901238576 100644 --- a/codes/rust/chapter_dynamic_programming/min_path_sum.rs +++ b/codes/rust/chapter_dynamic_programming/min_path_sum.rs @@ -5,7 +5,7 @@ */ /* 最小路径和:暴力搜索 */ -fn min_path_sum_dfs(grid: &Vec>, i: i32, j: i32) -> i32 { +pub fn min_path_sum_dfs(grid: &Vec>, i: i32, j: i32) -> i32 { // 若为左上角单元格,则终止搜索 if i == 0 && j == 0 { return grid[0][0]; @@ -22,7 +22,7 @@ fn min_path_sum_dfs(grid: &Vec>, i: i32, j: i32) -> i32 { } /* 最小路径和:记忆化搜索 */ -fn min_path_sum_dfs_mem(grid: &Vec>, mem: &mut Vec>, i: i32, j: i32) -> i32 { +pub fn min_path_sum_dfs_mem(grid: &Vec>, mem: &mut Vec>, i: i32, j: i32) -> i32 { // 若为左上角单元格,则终止搜索 if i == 0 && j == 0 { return grid[0][0]; @@ -44,7 +44,7 @@ fn min_path_sum_dfs_mem(grid: &Vec>, mem: &mut Vec>, i: i32, j } /* 最小路径和:动态规划 */ -fn min_path_sum_dp(grid: &Vec>) -> i32 { +pub fn min_path_sum_dp(grid: &Vec>) -> i32 { let (n, m) = (grid.len(), grid[0].len()); // 初始化 dp 表 let mut dp = vec![vec![0; m]; n]; @@ -67,7 +67,7 @@ fn min_path_sum_dp(grid: &Vec>) -> i32 { } /* 最小路径和:空间优化后的动态规划 */ -fn min_path_sum_dp_comp(grid: &Vec>) -> i32 { +pub fn min_path_sum_dp_comp(grid: &Vec>) -> i32 { let (n, m) = (grid.len(), grid[0].len()); // 初始化 dp 表 let mut dp = vec![0; m]; @@ -89,7 +89,7 @@ fn min_path_sum_dp_comp(grid: &Vec>) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let grid = vec![ vec![1, 3, 1, 5], vec![2, 2, 4, 2], diff --git a/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs b/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs index 670f845afe..b12d2c7a46 100644 --- a/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs +++ b/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs @@ -5,7 +5,7 @@ */ /* 完全背包:动态规划 */ -fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); // 初始化 dp 表 let mut dp = vec![vec![0; cap + 1]; n + 1]; @@ -25,7 +25,7 @@ fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { } /* 完全背包:空间优化后的动态规划 */ -fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); // 初始化 dp 表 let mut dp = vec![0; cap + 1]; @@ -45,7 +45,7 @@ fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let wgt = [1, 2, 3]; let val = [5, 11, 15]; let cap: usize = 4; diff --git a/codes/rust/chapter_graph/graph_adjacency_matrix.rs b/codes/rust/chapter_graph/graph_adjacency_matrix.rs index 0444072169..6770526702 100644 --- a/codes/rust/chapter_graph/graph_adjacency_matrix.rs +++ b/codes/rust/chapter_graph/graph_adjacency_matrix.rs @@ -7,9 +7,9 @@ /* 基于邻接矩阵实现的无向图类型 */ pub struct GraphAdjMat { // 顶点列表,元素代表“顶点值”,索引代表“顶点索引” - pub vertices: Vec, + vertices: Vec, // 邻接矩阵,行列索引对应“顶点索引” - pub adj_mat: Vec>, + adj_mat: Vec>, } impl GraphAdjMat { diff --git a/codes/rust/chapter_graph/graph_bfs.rs b/codes/rust/chapter_graph/graph_bfs.rs index 38bcea0a54..1d47161d15 100644 --- a/codes/rust/chapter_graph/graph_bfs.rs +++ b/codes/rust/chapter_graph/graph_bfs.rs @@ -12,7 +12,7 @@ use std::collections::{HashSet, VecDeque}; /* 广度优先遍历 */ // 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点 -fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { +pub fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { // 顶点遍历序列 let mut res = vec![]; // 哈希集合,用于记录已被访问过的顶点 diff --git a/codes/rust/chapter_graph/graph_dfs.rs b/codes/rust/chapter_graph/graph_dfs.rs index 2a2c18a706..d01a52ff22 100644 --- a/codes/rust/chapter_graph/graph_dfs.rs +++ b/codes/rust/chapter_graph/graph_dfs.rs @@ -28,7 +28,7 @@ fn dfs(graph: &GraphAdjList, visited: &mut HashSet, res: &mut Vec Vec { +pub fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { // 顶点遍历序列 let mut res = vec![]; // 哈希集合,用于记录已被访问过的顶点 diff --git a/codes/rust/chapter_greedy/coin_change_greedy.rs b/codes/rust/chapter_greedy/coin_change_greedy.rs index f00c483b88..8637b994ad 100644 --- a/codes/rust/chapter_greedy/coin_change_greedy.rs +++ b/codes/rust/chapter_greedy/coin_change_greedy.rs @@ -5,7 +5,7 @@ */ /* 零钱兑换:贪心 */ -fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 { +pub fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 { // 假设 coins 列表有序 let mut i = coins.len() - 1; let mut count = 0; diff --git a/codes/rust/chapter_greedy/fractional_knapsack.rs b/codes/rust/chapter_greedy/fractional_knapsack.rs index 6e3ebe333c..e18f81b8de 100644 --- a/codes/rust/chapter_greedy/fractional_knapsack.rs +++ b/codes/rust/chapter_greedy/fractional_knapsack.rs @@ -17,7 +17,7 @@ impl Item { } /* 分数背包:贪心 */ -fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 { +pub fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 { // 创建物品列表,包含两个属性:重量、价值 let mut items = wgt .iter() diff --git a/codes/rust/chapter_greedy/max_capacity.rs b/codes/rust/chapter_greedy/max_capacity.rs index 631022179f..d169111b47 100644 --- a/codes/rust/chapter_greedy/max_capacity.rs +++ b/codes/rust/chapter_greedy/max_capacity.rs @@ -5,7 +5,7 @@ */ /* 最大容量:贪心 */ -fn max_capacity(ht: &[i32]) -> i32 { +pub fn max_capacity(ht: &[i32]) -> i32 { // 初始化 i, j,使其分列数组两端 let mut i = 0; let mut j = ht.len() - 1; diff --git a/codes/rust/chapter_greedy/max_product_cutting.rs b/codes/rust/chapter_greedy/max_product_cutting.rs index c8fe012402..2a952e82e0 100644 --- a/codes/rust/chapter_greedy/max_product_cutting.rs +++ b/codes/rust/chapter_greedy/max_product_cutting.rs @@ -5,7 +5,7 @@ */ /* 最大切分乘积:贪心 */ -fn max_product_cutting(n: i32) -> i32 { +pub fn max_product_cutting(n: i32) -> i32 { // 当 n <= 3 时,必须切分出一个 1 if n <= 3 { return 1 * (n - 1); diff --git a/codes/rust/chapter_hashing/hash_map.rs b/codes/rust/chapter_hashing/hash_map.rs index 53200d0554..81375a891d 100644 --- a/codes/rust/chapter_hashing/hash_map.rs +++ b/codes/rust/chapter_hashing/hash_map.rs @@ -9,7 +9,7 @@ use hello_algo_rust::include::print_util; use std::collections::HashMap; /* Driver Code */ -pub fn main() { +fn main() { // 初始化哈希表 let mut map = HashMap::new(); diff --git a/codes/rust/chapter_hashing/hash_map_chaining.rs b/codes/rust/chapter_hashing/hash_map_chaining.rs index ae3fe1ca37..a4b901fe01 100644 --- a/codes/rust/chapter_hashing/hash_map_chaining.rs +++ b/codes/rust/chapter_hashing/hash_map_chaining.rs @@ -6,13 +6,13 @@ #[derive(Clone)] /* 键值对 */ -struct Pair { - key: i32, - val: String, +pub struct Pair { + pub key: i32, + pub val: String, } /* 链式地址哈希表 */ -struct HashMapChaining { +pub struct HashMapChaining { size: usize, capacity: usize, load_thres: f32, @@ -22,7 +22,7 @@ struct HashMapChaining { impl HashMapChaining { /* 构造方法 */ - fn new() -> Self { + pub fn new() -> Self { Self { size: 0, capacity: 4, @@ -43,7 +43,7 @@ impl HashMapChaining { } /* 删除操作 */ - fn remove(&mut self, key: i32) -> Option { + pub fn remove(&mut self, key: i32) -> Option { let index = self.hash_func(key); // 遍历桶,从中删除键值对 @@ -78,7 +78,7 @@ impl HashMapChaining { } /* 打印哈希表 */ - fn print(&self) { + pub fn print(&self) { for bucket in &self.buckets { let mut res = Vec::new(); for pair in bucket { @@ -89,7 +89,7 @@ impl HashMapChaining { } /* 添加操作 */ - fn put(&mut self, key: i32, val: String) { + pub fn put(&mut self, key: i32, val: String) { // 当负载因子超过阈值时,执行扩容 if self.load_factor() > self.load_thres { self.extend(); @@ -112,7 +112,7 @@ impl HashMapChaining { } /* 查询操作 */ - fn get(&self, key: i32) -> Option<&str> { + pub fn get(&self, key: i32) -> Option<&str> { let index = self.hash_func(key); // 遍历桶,若找到 key ,则返回对应 val @@ -128,7 +128,7 @@ impl HashMapChaining { } /* Driver Code */ -pub fn main() { +fn main() { /* 初始化哈希表 */ let mut map = HashMapChaining::new(); diff --git a/codes/rust/chapter_hashing/hash_map_open_addressing.rs b/codes/rust/chapter_hashing/hash_map_open_addressing.rs index 5ed34fc435..6c5f607e68 100644 --- a/codes/rust/chapter_hashing/hash_map_open_addressing.rs +++ b/codes/rust/chapter_hashing/hash_map_open_addressing.rs @@ -11,7 +11,7 @@ mod array_hash_map; use array_hash_map::Pair; /* 开放寻址哈希表 */ -struct HashMapOpenAddressing { +pub struct HashMapOpenAddressing { size: usize, // 键值对数量 capacity: usize, // 哈希表容量 load_thres: f64, // 触发扩容的负载因子阈值 @@ -22,7 +22,7 @@ struct HashMapOpenAddressing { impl HashMapOpenAddressing { /* 构造方法 */ - fn new() -> Self { + pub fn new() -> Self { Self { size: 0, capacity: 4, @@ -78,7 +78,7 @@ impl HashMapOpenAddressing { } /* 查询操作 */ - fn get(&mut self, key: i32) -> Option<&str> { + pub fn get(&mut self, key: i32) -> Option<&str> { // 搜索 key 对应的桶索引 let index = self.find_bucket(key); // 若找到键值对,则返回对应 val @@ -90,7 +90,7 @@ impl HashMapOpenAddressing { } /* 添加操作 */ - fn put(&mut self, key: i32, val: String) { + pub fn put(&mut self, key: i32, val: String) { // 当负载因子超过阈值时,执行扩容 if self.load_factor() > self.load_thres { self.extend(); @@ -108,7 +108,7 @@ impl HashMapOpenAddressing { } /* 删除操作 */ - fn remove(&mut self, key: i32) { + pub fn remove(&mut self, key: i32) { // 搜索 key 对应的桶索引 let index = self.find_bucket(key); // 若找到键值对,则用删除标记覆盖它 @@ -138,7 +138,7 @@ impl HashMapOpenAddressing { } } /* 打印哈希表 */ - fn print(&self) { + pub fn print(&self) { for pair in &self.buckets { if pair.is_none() { println!("null"); diff --git a/codes/rust/chapter_hashing/simple_hash.rs b/codes/rust/chapter_hashing/simple_hash.rs index 1106101bbf..0c78ea79da 100644 --- a/codes/rust/chapter_hashing/simple_hash.rs +++ b/codes/rust/chapter_hashing/simple_hash.rs @@ -5,7 +5,7 @@ */ /* 加法哈希 */ -fn add_hash(key: &str) -> i32 { +pub fn add_hash(key: &str) -> i32 { let mut hash = 0_i64; const MODULUS: i64 = 1000000007; @@ -17,7 +17,7 @@ fn add_hash(key: &str) -> i32 { } /* 乘法哈希 */ -fn mul_hash(key: &str) -> i32 { +pub fn mul_hash(key: &str) -> i32 { let mut hash = 0_i64; const MODULUS: i64 = 1000000007; @@ -29,7 +29,7 @@ fn mul_hash(key: &str) -> i32 { } /* 异或哈希 */ -fn xor_hash(key: &str) -> i32 { +pub fn xor_hash(key: &str) -> i32 { let mut hash = 0_i64; const MODULUS: i64 = 1000000007; @@ -41,7 +41,7 @@ fn xor_hash(key: &str) -> i32 { } /* 旋转哈希 */ -fn rot_hash(key: &str) -> i32 { +pub fn rot_hash(key: &str) -> i32 { let mut hash = 0_i64; const MODULUS: i64 = 1000000007; diff --git a/codes/rust/chapter_heap/my_heap.rs b/codes/rust/chapter_heap/my_heap.rs index 18b67c6229..05b1fb09cb 100644 --- a/codes/rust/chapter_heap/my_heap.rs +++ b/codes/rust/chapter_heap/my_heap.rs @@ -7,14 +7,14 @@ use hello_algo_rust::include::print_util; /* 大顶堆 */ -struct MaxHeap { +pub struct MaxHeap { // 使用 vector 而非数组,这样无须考虑扩容问题 max_heap: Vec, } impl MaxHeap { /* 构造方法,根据输入列表建堆 */ - fn new(nums: Vec) -> Self { + pub fn new(nums: Vec) -> Self { // 将列表元素原封不动添加进堆 let mut heap = MaxHeap { max_heap: nums }; // 堆化除叶节点以外的其他所有节点 @@ -45,22 +45,22 @@ impl MaxHeap { } /* 获取堆大小 */ - fn size(&self) -> usize { + pub fn size(&self) -> usize { self.max_heap.len() } /* 判断堆是否为空 */ - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.max_heap.is_empty() } /* 访问堆顶元素 */ - fn peek(&self) -> Option { + pub fn peek(&self) -> Option { self.max_heap.first().copied() } /* 元素入堆 */ - fn push(&mut self, val: i32) { + pub fn push(&mut self, val: i32) { // 添加节点 self.max_heap.push(val); // 从底至顶堆化 @@ -88,7 +88,7 @@ impl MaxHeap { } /* 元素出堆 */ - fn pop(&mut self) -> i32 { + pub fn pop(&mut self) -> i32 { // 判空处理 if self.is_empty() { panic!("index out of bounds"); @@ -126,7 +126,7 @@ impl MaxHeap { } /* 打印堆(二叉树) */ - fn print(&self) { + pub fn print(&self) { print_util::print_heap(self.max_heap.clone()); } } diff --git a/codes/rust/chapter_heap/top_k.rs b/codes/rust/chapter_heap/top_k.rs index d79076147f..15c2c0ac9a 100644 --- a/codes/rust/chapter_heap/top_k.rs +++ b/codes/rust/chapter_heap/top_k.rs @@ -10,7 +10,7 @@ use std::cmp::Reverse; use std::collections::BinaryHeap; /* 基于堆查找数组中最大的 k 个元素 */ -fn top_k_heap(nums: Vec, k: usize) -> BinaryHeap> { +pub fn top_k_heap(nums: Vec, k: usize) -> BinaryHeap> { // BinaryHeap 是大顶堆,使用 Reverse 将元素取反,从而实现小顶堆 let mut heap = BinaryHeap::>::new(); // 将数组的前 k 个元素入堆 diff --git a/codes/rust/chapter_searching/binary_search.rs b/codes/rust/chapter_searching/binary_search.rs index b60742e0fc..06a85ff38d 100644 --- a/codes/rust/chapter_searching/binary_search.rs +++ b/codes/rust/chapter_searching/binary_search.rs @@ -5,7 +5,7 @@ */ /* 二分查找(双闭区间) */ -fn binary_search(nums: &[i32], target: i32) -> i32 { +pub fn binary_search(nums: &[i32], target: i32) -> i32 { // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 let mut i = 0; let mut j = nums.len() as i32 - 1; @@ -28,7 +28,7 @@ fn binary_search(nums: &[i32], target: i32) -> i32 { } /* 二分查找(左闭右开区间) */ -fn binary_search_lcro(nums: &[i32], target: i32) -> i32 { +pub fn binary_search_lcro(nums: &[i32], target: i32) -> i32 { // 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 let mut i = 0; let mut j = nums.len() as i32; @@ -51,7 +51,7 @@ fn binary_search_lcro(nums: &[i32], target: i32) -> i32 { } /* Driver Code */ -pub fn main() { +fn main() { let target = 6; let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; diff --git a/codes/rust/chapter_searching/binary_search_edge.rs b/codes/rust/chapter_searching/binary_search_edge.rs index 5d8195ab33..7e2e21edcc 100644 --- a/codes/rust/chapter_searching/binary_search_edge.rs +++ b/codes/rust/chapter_searching/binary_search_edge.rs @@ -9,7 +9,7 @@ mod binary_search_insertion; use binary_search_insertion::binary_search_insertion; /* 二分查找最左一个 target */ -fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 { +pub fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 { // 等价于查找 target 的插入点 let i = binary_search_insertion(nums, target); // 未找到 target ,返回 -1 @@ -21,7 +21,7 @@ fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 { } /* 二分查找最右一个 target */ -fn binary_search_right_edge(nums: &[i32], target: i32) -> i32 { +pub fn binary_search_right_edge(nums: &[i32], target: i32) -> i32 { // 转化为查找最左一个 target + 1 let i = binary_search_insertion(nums, target + 1); // j 指向最右一个 target ,i 指向首个大于 target 的元素 diff --git a/codes/rust/chapter_searching/binary_search_insertion.rs b/codes/rust/chapter_searching/binary_search_insertion.rs index d0c584e3ca..67a9d94221 100644 --- a/codes/rust/chapter_searching/binary_search_insertion.rs +++ b/codes/rust/chapter_searching/binary_search_insertion.rs @@ -6,7 +6,7 @@ #![allow(unused)] /* 二分查找插入点(无重复元素) */ -fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 { +pub fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 { let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] while i <= j { let m = i + (j - i) / 2; // 计算中点索引 m diff --git a/codes/rust/chapter_searching/hashing_search.rs b/codes/rust/chapter_searching/hashing_search.rs index b2229edcf2..891e675099 100644 --- a/codes/rust/chapter_searching/hashing_search.rs +++ b/codes/rust/chapter_searching/hashing_search.rs @@ -10,14 +10,14 @@ use std::collections::HashMap; use std::rc::Rc; /* 哈希查找(数组) */ -fn hashing_search_array<'a>(map: &'a HashMap, target: i32) -> Option<&'a usize> { +pub fn hashing_search_array<'a>(map: &'a HashMap, target: i32) -> Option<&'a usize> { // 哈希表的 key: 目标元素,value: 索引 // 若哈希表中无此 key ,返回 None map.get(&target) } /* 哈希查找(链表) */ -fn hashing_search_linked_list( +pub fn hashing_search_linked_list( map: &HashMap>>>, target: i32, ) -> Option<&Rc>>> { @@ -27,7 +27,7 @@ fn hashing_search_linked_list( } /* Driver Code */ -pub fn main() { +fn main() { let target = 3; /* 哈希查找(数组) */ diff --git a/codes/rust/chapter_searching/linear_search.rs b/codes/rust/chapter_searching/linear_search.rs index 25f6547bb6..63d6521109 100644 --- a/codes/rust/chapter_searching/linear_search.rs +++ b/codes/rust/chapter_searching/linear_search.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::rc::Rc; /* 线性查找(数组) */ -fn linear_search_array(nums: &[i32], target: i32) -> i32 { +pub fn linear_search_array(nums: &[i32], target: i32) -> i32 { // 遍历数组 for (i, num) in nums.iter().enumerate() { // 找到目标元素,返回其索引 @@ -22,7 +22,7 @@ fn linear_search_array(nums: &[i32], target: i32) -> i32 { } /* 线性查找(链表) */ -fn linear_search_linked_list( +pub fn linear_search_linked_list( head: Rc>>, target: i32, ) -> Option>>> { @@ -39,7 +39,7 @@ fn linear_search_linked_list( } /* Driver Code */ -pub fn main() { +fn main() { let target = 3; /* 在数组中执行线性查找 */ diff --git a/codes/rust/chapter_sorting/bubble_sort.rs b/codes/rust/chapter_sorting/bubble_sort.rs index 972eb69028..9ac4615511 100644 --- a/codes/rust/chapter_sorting/bubble_sort.rs +++ b/codes/rust/chapter_sorting/bubble_sort.rs @@ -7,7 +7,7 @@ use hello_algo_rust::include::print_util; /* 冒泡排序 */ -fn bubble_sort(nums: &mut [i32]) { +pub fn bubble_sort(nums: &mut [i32]) { // 外循环:未排序区间为 [0, i] for i in (1..nums.len()).rev() { // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 @@ -21,7 +21,7 @@ fn bubble_sort(nums: &mut [i32]) { } /* 冒泡排序(标志优化) */ -fn bubble_sort_with_flag(nums: &mut [i32]) { +pub fn bubble_sort_with_flag(nums: &mut [i32]) { // 外循环:未排序区间为 [0, i] for i in (1..nums.len()).rev() { let mut flag = false; // 初始化标志位 @@ -40,7 +40,7 @@ fn bubble_sort_with_flag(nums: &mut [i32]) { } /* Driver Code */ -pub fn main() { +fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; bubble_sort(&mut nums); print!("冒泡排序完成后 nums = "); diff --git a/codes/rust/chapter_sorting/bucket_sort.rs b/codes/rust/chapter_sorting/bucket_sort.rs index c959559ac2..3c87e0f0cf 100644 --- a/codes/rust/chapter_sorting/bucket_sort.rs +++ b/codes/rust/chapter_sorting/bucket_sort.rs @@ -7,7 +7,7 @@ use hello_algo_rust::include::print_util; /* 桶排序 */ -fn bucket_sort(nums: &mut [f64]) { +pub fn bucket_sort(nums: &mut [f64]) { // 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素 let k = nums.len() / 2; let mut buckets = vec![vec![]; k]; diff --git a/codes/rust/chapter_sorting/counting_sort.rs b/codes/rust/chapter_sorting/counting_sort.rs index ed478afb5a..b59eb2b2cd 100644 --- a/codes/rust/chapter_sorting/counting_sort.rs +++ b/codes/rust/chapter_sorting/counting_sort.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::print_util; /* 计数排序 */ // 简单实现,无法用于排序对象 -fn counting_sort_naive(nums: &mut [i32]) { +pub fn counting_sort_naive(nums: &mut [i32]) { // 1. 统计数组最大元素 m let m = *nums.iter().max().unwrap(); // 2. 统计各数字的出现次数 @@ -29,7 +29,7 @@ fn counting_sort_naive(nums: &mut [i32]) { /* 计数排序 */ // 完整实现,可排序对象,并且是稳定排序 -fn counting_sort(nums: &mut [i32]) { +pub fn counting_sort(nums: &mut [i32]) { // 1. 统计数组最大元素 m let m = *nums.iter().max().unwrap() as usize; // 2. 统计各数字的出现次数 diff --git a/codes/rust/chapter_sorting/heap_sort.rs b/codes/rust/chapter_sorting/heap_sort.rs index a70c2c8ab8..209c9f924c 100644 --- a/codes/rust/chapter_sorting/heap_sort.rs +++ b/codes/rust/chapter_sorting/heap_sort.rs @@ -31,7 +31,7 @@ fn sift_down(nums: &mut [i32], n: usize, mut i: usize) { } /* 堆排序 */ -fn heap_sort(nums: &mut [i32]) { +pub fn heap_sort(nums: &mut [i32]) { // 建堆操作:堆化除叶节点以外的其他所有节点 for i in (0..nums.len() / 2).rev() { sift_down(nums, nums.len(), i); diff --git a/codes/rust/chapter_sorting/insertion_sort.rs b/codes/rust/chapter_sorting/insertion_sort.rs index 8772e7d021..e433f5c9a2 100644 --- a/codes/rust/chapter_sorting/insertion_sort.rs +++ b/codes/rust/chapter_sorting/insertion_sort.rs @@ -7,7 +7,7 @@ use hello_algo_rust::include::print_util; /* 插入排序 */ -fn insertion_sort(nums: &mut [i32]) { +pub fn insertion_sort(nums: &mut [i32]) { // 外循环:已排序区间为 [0, i-1] for i in 1..nums.len() { let (base, mut j) = (nums[i], (i - 1) as i32); diff --git a/codes/rust/chapter_sorting/merge_sort.rs b/codes/rust/chapter_sorting/merge_sort.rs index cded284bb4..a97bb3cc64 100644 --- a/codes/rust/chapter_sorting/merge_sort.rs +++ b/codes/rust/chapter_sorting/merge_sort.rs @@ -41,7 +41,7 @@ fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) { } /* 归并排序 */ -fn merge_sort(nums: &mut [i32], left: usize, right: usize) { +pub fn merge_sort(nums: &mut [i32], left: usize, right: usize) { // 终止条件 if left >= right { return; // 当子数组长度为 1 时终止递归 diff --git a/codes/rust/chapter_sorting/quick_sort.rs b/codes/rust/chapter_sorting/quick_sort.rs index 7f88dfaba1..f521769602 100644 --- a/codes/rust/chapter_sorting/quick_sort.rs +++ b/codes/rust/chapter_sorting/quick_sort.rs @@ -5,7 +5,7 @@ */ /* 快速排序 */ -struct QuickSort; +pub struct QuickSort; impl QuickSort { /* 哨兵划分 */ @@ -40,7 +40,7 @@ impl QuickSort { } /* 快速排序(中位基准数优化) */ -struct QuickSortMedian; +pub struct QuickSortMedian; impl QuickSortMedian { /* 选取三个候选元素的中位数 */ @@ -91,7 +91,7 @@ impl QuickSortMedian { } /* 快速排序(递归深度优化) */ -struct QuickSortTailCall; +pub struct QuickSortTailCall; impl QuickSortTailCall { /* 哨兵划分 */ diff --git a/codes/rust/chapter_sorting/radix_sort.rs b/codes/rust/chapter_sorting/radix_sort.rs index f213c4273c..91dd069cf7 100644 --- a/codes/rust/chapter_sorting/radix_sort.rs +++ b/codes/rust/chapter_sorting/radix_sort.rs @@ -39,7 +39,7 @@ fn counting_sort_digit(nums: &mut [i32], exp: i32) { } /* 基数排序 */ -fn radix_sort(nums: &mut [i32]) { +pub fn radix_sort(nums: &mut [i32]) { // 获取数组的最大元素,用于判断最大位数 let m = *nums.into_iter().max().unwrap(); // 按照从低位到高位的顺序遍历 diff --git a/codes/rust/chapter_sorting/selection_sort.rs b/codes/rust/chapter_sorting/selection_sort.rs index 87265a5417..ab75b67e24 100644 --- a/codes/rust/chapter_sorting/selection_sort.rs +++ b/codes/rust/chapter_sorting/selection_sort.rs @@ -7,7 +7,7 @@ use hello_algo_rust::include::print_util; /* 选择排序 */ -fn selection_sort(nums: &mut [i32]) { +pub fn selection_sort(nums: &mut [i32]) { if nums.is_empty() { return; } @@ -27,7 +27,7 @@ fn selection_sort(nums: &mut [i32]) { } /* Driver Code */ -pub fn main() { +fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; selection_sort(&mut nums); print!("\n选择排序完成后 nums = "); diff --git a/codes/rust/chapter_stack_and_queue/array_deque.rs b/codes/rust/chapter_stack_and_queue/array_deque.rs index 97b0512795..09a68095de 100644 --- a/codes/rust/chapter_stack_and_queue/array_deque.rs +++ b/codes/rust/chapter_stack_and_queue/array_deque.rs @@ -5,7 +5,7 @@ */ use hello_algo_rust::include::print_util; /* 基于环形数组实现的双向队列 */ -struct ArrayDeque { +pub struct ArrayDeque { nums: Vec, // 用于存储双向队列元素的数组 front: usize, // 队首指针,指向队首元素 que_size: usize, // 双向队列长度 @@ -72,7 +72,7 @@ impl ArrayDeque { } /* 队首出队 */ - fn pop_first(&mut self) -> T { + pub fn pop_first(&mut self) -> T { let num = self.peek_first(); // 队首指针向后移动一位 self.front = self.index(self.front as i32 + 1); @@ -81,14 +81,14 @@ impl ArrayDeque { } /* 队尾出队 */ - fn pop_last(&mut self) -> T { + pub fn pop_last(&mut self) -> T { let num = self.peek_last(); self.que_size -= 1; num } /* 访问队首元素 */ - fn peek_first(&self) -> T { + pub fn peek_first(&self) -> T { if self.is_empty() { panic!("双向队列为空") }; @@ -96,7 +96,7 @@ impl ArrayDeque { } /* 访问队尾元素 */ - fn peek_last(&self) -> T { + pub fn peek_last(&self) -> T { if self.is_empty() { panic!("双向队列为空") }; @@ -106,7 +106,7 @@ impl ArrayDeque { } /* 返回数组用于打印 */ - fn to_array(&self) -> Vec { + pub fn to_array(&self) -> Vec { // 仅转换有效长度范围内的列表元素 let mut res = vec![T::default(); self.que_size]; let mut j = self.front; diff --git a/codes/rust/chapter_stack_and_queue/array_queue.rs b/codes/rust/chapter_stack_and_queue/array_queue.rs index 62423fa1d0..a33b53f338 100644 --- a/codes/rust/chapter_stack_and_queue/array_queue.rs +++ b/codes/rust/chapter_stack_and_queue/array_queue.rs @@ -5,7 +5,7 @@ */ /* 基于环形数组实现的队列 */ -struct ArrayQueue { +pub struct ArrayQueue { nums: Vec, // 用于存储队列元素的数组 front: i32, // 队首指针,指向队首元素 que_size: i32, // 队列长度 @@ -14,7 +14,7 @@ struct ArrayQueue { impl ArrayQueue { /* 构造方法 */ - fn new(capacity: i32) -> ArrayQueue { + pub fn new(capacity: i32) -> ArrayQueue { ArrayQueue { nums: vec![T::default(); capacity as usize], front: 0, @@ -24,22 +24,22 @@ impl ArrayQueue { } /* 获取队列的容量 */ - fn capacity(&self) -> i32 { + pub fn capacity(&self) -> i32 { self.que_capacity } /* 获取队列的长度 */ - fn size(&self) -> i32 { + pub fn size(&self) -> i32 { self.que_size } /* 判断队列是否为空 */ - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.que_size == 0 } /* 入队 */ - fn push(&mut self, num: T) { + pub fn push(&mut self, num: T) { if self.que_size == self.capacity() { println!("队列已满"); return; @@ -53,7 +53,7 @@ impl ArrayQueue { } /* 出队 */ - fn pop(&mut self) -> T { + pub fn pop(&mut self) -> T { let num = self.peek(); // 队首指针向后移动一位,若越过尾部,则返回到数组头部 self.front = (self.front + 1) % self.que_capacity; @@ -62,7 +62,7 @@ impl ArrayQueue { } /* 访问队首元素 */ - fn peek(&self) -> T { + pub fn peek(&self) -> T { if self.is_empty() { panic!("index out of bounds"); } @@ -70,7 +70,7 @@ impl ArrayQueue { } /* 返回数组 */ - fn to_vector(&self) -> Vec { + pub fn to_vector(&self) -> Vec { let cap = self.que_capacity; let mut j = self.front; let mut arr = vec![T::default(); cap as usize]; diff --git a/codes/rust/chapter_stack_and_queue/array_stack.rs b/codes/rust/chapter_stack_and_queue/array_stack.rs index 19c902207a..454e202fae 100644 --- a/codes/rust/chapter_stack_and_queue/array_stack.rs +++ b/codes/rust/chapter_stack_and_queue/array_stack.rs @@ -7,40 +7,40 @@ use hello_algo_rust::include::print_util; /* 基于数组实现的栈 */ -struct ArrayStack { +pub struct ArrayStack { stack: Vec, } impl ArrayStack { /* 初始化栈 */ - fn new() -> ArrayStack { + pub fn new() -> ArrayStack { ArrayStack:: { stack: Vec::::new(), } } /* 获取栈的长度 */ - fn size(&self) -> usize { + pub fn size(&self) -> usize { self.stack.len() } /* 判断栈是否为空 */ - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.size() == 0 } /* 入栈 */ - fn push(&mut self, num: T) { + pub fn push(&mut self, num: T) { self.stack.push(num); } /* 出栈 */ - fn pop(&mut self) -> Option { + pub fn pop(&mut self) -> Option { self.stack.pop() } /* 访问栈顶元素 */ - fn peek(&self) -> Option<&T> { + pub fn peek(&self) -> Option<&T> { if self.is_empty() { panic!("栈为空") }; @@ -48,7 +48,7 @@ impl ArrayStack { } /* 返回 &Vec */ - fn to_array(&self) -> &Vec { + pub fn to_array(&self) -> &Vec { &self.stack } } diff --git a/codes/rust/chapter_stack_and_queue/deque.rs b/codes/rust/chapter_stack_and_queue/deque.rs index 28b3ad38f2..ce8cffb66d 100644 --- a/codes/rust/chapter_stack_and_queue/deque.rs +++ b/codes/rust/chapter_stack_and_queue/deque.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::print_util; use std::collections::VecDeque; /* Driver Code */ -pub fn main() { +fn main() { // 初始化双向队列 let mut deque: VecDeque = VecDeque::new(); deque.push_back(3); diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs index 44eacf4d02..5dd523baf3 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs @@ -11,9 +11,9 @@ use std::rc::Rc; /* 双向链表节点 */ pub struct ListNode { - pub val: T, // 节点值 - pub next: Option>>>, // 后继节点指针 - pub prev: Option>>>, // 前驱节点指针 + val: T, // 节点值 + next: Option>>>, // 后继节点指针 + prev: Option>>>, // 前驱节点指针 } impl ListNode { diff --git a/codes/rust/chapter_stack_and_queue/queue.rs b/codes/rust/chapter_stack_and_queue/queue.rs index e2fd8400c1..209aa441c2 100644 --- a/codes/rust/chapter_stack_and_queue/queue.rs +++ b/codes/rust/chapter_stack_and_queue/queue.rs @@ -9,7 +9,7 @@ use hello_algo_rust::include::print_util; use std::collections::VecDeque; /* Driver Code */ -pub fn main() { +fn main() { // 初始化队列 let mut queue: VecDeque = VecDeque::new(); diff --git a/codes/rust/chapter_stack_and_queue/stack.rs b/codes/rust/chapter_stack_and_queue/stack.rs index b2df65b5b9..a1d7798bf0 100644 --- a/codes/rust/chapter_stack_and_queue/stack.rs +++ b/codes/rust/chapter_stack_and_queue/stack.rs @@ -7,7 +7,7 @@ use hello_algo_rust::include::print_util; /* Driver Code */ -pub fn main() { +fn main() { // 初始化栈 // 在 rust 中,推荐将 Vec 当作栈来使用 let mut stack: Vec = Vec::new(); diff --git a/codes/rust/chapter_tree/array_binary_tree.rs b/codes/rust/chapter_tree/array_binary_tree.rs index 296f247df9..3cf65e4e67 100644 --- a/codes/rust/chapter_tree/array_binary_tree.rs +++ b/codes/rust/chapter_tree/array_binary_tree.rs @@ -7,23 +7,23 @@ use hello_algo_rust::include::{print_util, tree_node}; /* 数组表示下的二叉树类 */ -struct ArrayBinaryTree { +pub struct ArrayBinaryTree { tree: Vec>, } impl ArrayBinaryTree { /* 构造方法 */ - fn new(arr: Vec>) -> Self { + pub fn new(arr: Vec>) -> Self { Self { tree: arr } } /* 列表容量 */ - fn size(&self) -> i32 { + pub fn size(&self) -> i32 { self.tree.len() as i32 } /* 获取索引为 i 节点的值 */ - fn val(&self, i: i32) -> Option { + pub fn val(&self, i: i32) -> Option { // 若索引越界,则返回 None ,代表空位 if i < 0 || i >= self.size() { None @@ -33,22 +33,22 @@ impl ArrayBinaryTree { } /* 获取索引为 i 节点的左子节点的索引 */ - fn left(&self, i: i32) -> i32 { + pub fn left(&self, i: i32) -> i32 { 2 * i + 1 } /* 获取索引为 i 节点的右子节点的索引 */ - fn right(&self, i: i32) -> i32 { + pub fn right(&self, i: i32) -> i32 { 2 * i + 2 } /* 获取索引为 i 节点的父节点的索引 */ - fn parent(&self, i: i32) -> i32 { + pub fn parent(&self, i: i32) -> i32 { (i - 1) / 2 } /* 层序遍历 */ - fn level_order(&self) -> Vec { + pub fn level_order(&self) -> Vec { self.tree.iter().filter_map(|&x| x).collect() } @@ -75,21 +75,21 @@ impl ArrayBinaryTree { } /* 前序遍历 */ - fn pre_order(&self) -> Vec { + pub fn pre_order(&self) -> Vec { let mut res = vec![]; self.dfs(0, "pre", &mut res); res } /* 中序遍历 */ - fn in_order(&self) -> Vec { + pub fn in_order(&self) -> Vec { let mut res = vec![]; self.dfs(0, "in", &mut res); res } /* 后序遍历 */ - fn post_order(&self) -> Vec { + pub fn post_order(&self) -> Vec { let mut res = vec![]; self.dfs(0, "post", &mut res); res diff --git a/codes/rust/chapter_tree/avl_tree.rs b/codes/rust/chapter_tree/avl_tree.rs index faa3787efc..908f632d33 100644 --- a/codes/rust/chapter_tree/avl_tree.rs +++ b/codes/rust/chapter_tree/avl_tree.rs @@ -13,18 +13,18 @@ use std::rc::Rc; type OptionTreeNodeRc = Option>>; /* AVL 树 */ -struct AVLTree { +pub struct AVLTree { root: OptionTreeNodeRc, // 根节点 } impl AVLTree { /* 构造方法 */ - fn new() -> Self { + pub fn new() -> Self { Self { root: None } } /* 获取节点高度 */ - fn height(node: OptionTreeNodeRc) -> i32 { + pub fn height(node: OptionTreeNodeRc) -> i32 { // 空节点高度为 -1 ,叶节点高度为 0 match node { Some(node) => node.borrow().height, @@ -128,7 +128,7 @@ impl AVLTree { } /* 插入节点 */ - fn insert(&mut self, val: i32) { + pub fn insert(&mut self, val: i32) { self.root = Self::insert_helper(self.root.clone(), val); } @@ -167,7 +167,7 @@ impl AVLTree { } /* 删除节点 */ - fn remove(&self, val: i32) { + pub fn remove(&self, val: i32) { Self::remove_helper(self.root.clone(), val); } @@ -222,7 +222,7 @@ impl AVLTree { } /* 查找节点 */ - fn search(&self, val: i32) -> OptionTreeNodeRc { + pub fn search(&self, val: i32) -> OptionTreeNodeRc { let mut cur = self.root.clone(); // 循环查找,越过叶节点后跳出 while let Some(current) = cur.clone() { diff --git a/codes/rust/chapter_tree/binary_tree_bfs.rs b/codes/rust/chapter_tree/binary_tree_bfs.rs index e50c2df952..5cb0fa750b 100644 --- a/codes/rust/chapter_tree/binary_tree_bfs.rs +++ b/codes/rust/chapter_tree/binary_tree_bfs.rs @@ -11,7 +11,7 @@ use std::collections::VecDeque; use std::{cell::RefCell, rc::Rc}; /* 层序遍历 */ -fn level_order(root: &Rc>) -> Vec { +pub fn level_order(root: &Rc>) -> Vec { // 初始化队列,加入根节点 let mut que = VecDeque::new(); que.push_back(root.clone()); diff --git a/codes/rust/chapter_tree/binary_tree_dfs.rs b/codes/rust/chapter_tree/binary_tree_dfs.rs index 77533d52f9..c2daa0afcb 100644 --- a/codes/rust/chapter_tree/binary_tree_dfs.rs +++ b/codes/rust/chapter_tree/binary_tree_dfs.rs @@ -11,7 +11,7 @@ use std::cell::RefCell; use std::rc::Rc; /* 前序遍历 */ -fn pre_order(root: Option<&Rc>>) -> Vec { +pub fn pre_order(root: Option<&Rc>>) -> Vec { let mut result = vec![]; fn dfs(root: Option<&Rc>>, res: &mut Vec) { @@ -29,7 +29,7 @@ fn pre_order(root: Option<&Rc>>) -> Vec { } /* 中序遍历 */ -fn in_order(root: Option<&Rc>>) -> Vec { +pub fn in_order(root: Option<&Rc>>) -> Vec { let mut result = vec![]; fn dfs(root: Option<&Rc>>, res: &mut Vec) { @@ -47,7 +47,7 @@ fn in_order(root: Option<&Rc>>) -> Vec { } /* 后序遍历 */ -fn post_order(root: Option<&Rc>>) -> Vec { +pub fn post_order(root: Option<&Rc>>) -> Vec { let mut result = vec![]; fn dfs(root: Option<&Rc>>, res: &mut Vec) { From 0a09bcb62c80641a835f54908b80e3f8a9cfb274 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 19:39:40 +0800 Subject: [PATCH 007/109] refactor: use a more intuitive way to join strings --- .../chapter_computational_complexity/iteration.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/iteration.rs b/codes/rust/chapter_computational_complexity/iteration.rs index 3117419414..473c845d43 100644 --- a/codes/rust/chapter_computational_complexity/iteration.rs +++ b/codes/rust/chapter_computational_complexity/iteration.rs @@ -44,15 +44,15 @@ fn while_loop_ii(n: i32) -> i32 { /* 双层 for 循环 */ fn nested_for_loop(n: i32) -> String { - let mut res = vec![]; + let mut res = String::new(); // 循环 i = 1, 2, ..., n-1, n for i in 1..=n { // 循环 j = 1, 2, ..., n-1, n for j in 1..=n { - res.push(format!("({}, {}), ", i, j)); + res += &format!("({i}, {j}), "); } } - res.join("") + res } /* Driver Code */ @@ -61,14 +61,14 @@ fn main() { let mut res; res = for_loop(n); - println!("\nfor 循环的求和结果 res = {res}"); + println!("for 循环的求和结果 res = {res}"); res = while_loop(n); - println!("\nwhile 循环的求和结果 res = {res}"); + println!("while 循环的求和结果 res = {res}"); res = while_loop_ii(n); - println!("\nwhile 循环(两次更新)求和结果 res = {}", res); + println!("while 循环(两次更新)求和结果 res = {res}"); let res = nested_for_loop(n); - println!("\n双层 for 循环的遍历结果 {res}"); + println!("双层 for 循环的遍历结果 {res}"); } From a647b7e473e3eedbb5ee5d397afded3d8187e925 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 19:42:41 +0800 Subject: [PATCH 008/109] perf: eliminate unnecessary branch jump in `Option::unwrap` --- codes/rust/chapter_computational_complexity/recursion.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/recursion.rs b/codes/rust/chapter_computational_complexity/recursion.rs index 6035c0362e..688d399fdd 100644 --- a/codes/rust/chapter_computational_complexity/recursion.rs +++ b/codes/rust/chapter_computational_complexity/recursion.rs @@ -27,9 +27,9 @@ fn for_loop_recur(n: i32) -> i32 { stack.push(i); } // 归:返回结果 - while !stack.is_empty() { - // 通过“出栈操作”模拟“归” - res += stack.pop().unwrap(); + // 通过“出栈操作”模拟“归” + while let Some(i) = stack.pop() { + res += i; } // res = 1+2+3+...+n res From dc5ea1d9abd08dd9a5ba7ca2ccc490e4ecdeacc0 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:25:46 +0800 Subject: [PATCH 009/109] fix: resolve warning Removed: - `clippy::let_and_return` --- .../chapter_computational_complexity/recursion.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/recursion.rs b/codes/rust/chapter_computational_complexity/recursion.rs index 688d399fdd..f33465291b 100644 --- a/codes/rust/chapter_computational_complexity/recursion.rs +++ b/codes/rust/chapter_computational_complexity/recursion.rs @@ -51,10 +51,8 @@ fn fib(n: i32) -> i32 { if n == 1 || n == 2 { return n - 1; } - // 递归调用 f(n) = f(n-1) + f(n-2) - let res = fib(n - 1) + fib(n - 2); - // 返回结果 - res + // 递归调用 f(n) = f(n-1) + f(n-2) 并返回结果 + fib(n - 1) + fib(n - 2) } /* Driver Code */ @@ -63,14 +61,14 @@ fn main() { let mut res; res = recur(n); - println!("\n递归函数的求和结果 res = {res}"); + println!("递归函数的求和结果 res = {res}"); res = for_loop_recur(n); - println!("\n使用迭代模拟递归求和结果 res = {res}"); + println!("使用迭代模拟递归求和结果 res = {res}"); res = tail_recur(n, 0); - println!("\n尾递归函数的求和结果 res = {res}"); + println!("尾递归函数的求和结果 res = {res}"); res = fib(n); - println!("\n斐波那契数列的第 {n} 项为 {res}"); + println!("斐波那契数列的第 {n} 项为 {res}"); } From 72232eeed4bded378b86d292106264c4a9f3253b Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:27:21 +0800 Subject: [PATCH 010/109] fix: resolve warnings Removed: - `clippy::assign_op_pattern` - `clippy::let_and_return` Explicitly omitted: - `clippy::manual_swap` --- .../time_complexity.rs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/time_complexity.rs b/codes/rust/chapter_computational_complexity/time_complexity.rs index 8fb4121a27..1854f8bf7a 100644 --- a/codes/rust/chapter_computational_complexity/time_complexity.rs +++ b/codes/rust/chapter_computational_complexity/time_complexity.rs @@ -47,6 +47,7 @@ fn quadratic(n: i32) -> i32 { } /* 平方阶(冒泡排序) */ +#[allow(clippy::manual_swap)] fn bubble_sort(nums: &mut [i32]) -> i32 { let mut count = 0; // 计数器 @@ -73,7 +74,7 @@ fn exponential(n: i32) -> i32 { // 细胞每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1) for _ in 0..n { for _ in 0..base { - count += 1 + count += 1; } base *= 2; } @@ -93,7 +94,7 @@ fn exp_recur(n: i32) -> i32 { fn logarithmic(mut n: i32) -> i32 { let mut count = 0; while n > 1 { - n = n / 2; + n /= 2; count += 1; } count @@ -116,7 +117,7 @@ fn linear_log_recur(n: i32) -> i32 { for _ in 0..n { count += 1; } - return count; + count } /* 阶乘阶(递归实现) */ @@ -139,32 +140,32 @@ fn main() { println!("输入数据大小 n = {}", n); let mut count = constant(n); - println!("常数阶的操作数量 = {}", count); + println!("常数阶的操作数量 = {count}"); count = linear(n); - println!("线性阶的操作数量 = {}", count); + println!("线性阶的操作数量 = {count}"); count = array_traversal(&vec![0; n as usize]); - println!("线性阶(遍历数组)的操作数量 = {}", count); + println!("线性阶(遍历数组)的操作数量 = {count}"); count = quadratic(n); - println!("平方阶的操作数量 = {}", count); - let mut nums = (1..=n).rev().collect::>(); // [n,n-1,...,2,1] + println!("平方阶的操作数量 = {count}"); + let mut nums = (1..=n).rev().collect::>(); count = bubble_sort(&mut nums); - println!("平方阶(冒泡排序)的操作数量 = {}", count); + println!("平方阶(冒泡排序)的操作数量 = {count}"); count = exponential(n); - println!("指数阶(循环实现)的操作数量 = {}", count); + println!("指数阶(循环实现)的操作数量 = {count}"); count = exp_recur(n); - println!("指数阶(递归实现)的操作数量 = {}", count); + println!("指数阶(递归实现)的操作数量 = {count}"); count = logarithmic(n); - println!("对数阶(循环实现)的操作数量 = {}", count); + println!("对数阶(循环实现)的操作数量 = {count}"); count = log_recur(n); - println!("对数阶(递归实现)的操作数量 = {}", count); + println!("对数阶(递归实现)的操作数量 = {count}"); count = linear_log_recur(n); - println!("线性对数阶(递归实现)的操作数量 = {}", count); + println!("线性对数阶(递归实现)的操作数量 = {count}"); count = factorial_recur(n); - println!("阶乘阶(递归实现)的操作数量 = {}", count); + println!("阶乘阶(递归实现)的操作数量 = {count}"); } From cb80ebee0ee2deb4325f4397356780358f0aa995 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:28:30 +0800 Subject: [PATCH 011/109] fix: resolve warnings Removed: - `clippy::needless_return` Explicitly omitted: - `dead_code` - `unused_variables` --- .../space_complexity.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/space_complexity.rs b/codes/rust/chapter_computational_complexity/space_complexity.rs index d1583fe252..3b77d36273 100644 --- a/codes/rust/chapter_computational_complexity/space_complexity.rs +++ b/codes/rust/chapter_computational_complexity/space_complexity.rs @@ -4,7 +4,10 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, ListNode, TreeNode}; +#![allow(dead_code)] +#![allow(unused_variables)] + +use hello_algo_rust::include::{ListNode, TreeNode, print_util}; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -12,11 +15,10 @@ use std::rc::Rc; /* 函数 */ fn function() -> i32 { // 执行某些操作 - return 0; + 0 } /* 常数阶 */ -#[allow(unused)] fn constant(n: i32) { // 常量、变量、对象占用 O(1) 空间 const A: i32 = 0; @@ -24,20 +26,19 @@ fn constant(n: i32) { let nums = vec![0; 10000]; let node = ListNode::new(0); // 循环中的变量占用 O(1) 空间 - for i in 0..n { + for _ in 0..n { let c = 0; } // 循环中的函数占用 O(1) 空间 - for i in 0..n { + for _ in 0..n { function(); } } /* 线性阶 */ -#[allow(unused)] fn linear(n: i32) { // 长度为 n 的数组占用 O(n) 空间 - let mut nums = vec![0; n as usize]; + let nums = vec![0; n as usize]; // 长度为 n 的列表占用 O(n) 空间 let mut nodes = Vec::new(); for i in 0..n { @@ -60,15 +61,14 @@ fn linear_recur(n: i32) { } /* 平方阶 */ -#[allow(unused)] fn quadratic(n: i32) { // 矩阵占用 O(n^2) 空间 let num_matrix = vec![vec![0; n as usize]; n as usize]; // 二维列表占用 O(n^2) 空间 let mut num_list = Vec::new(); - for i in 0..n { + for _ in 0..n { let mut tmp = Vec::new(); - for j in 0..n { + for _ in 0..n { tmp.push(0); } num_list.push(tmp); @@ -83,7 +83,7 @@ fn quadratic_recur(n: i32) -> i32 { // 数组 nums 长度为 n, n-1, ..., 2, 1 let nums = vec![0; n as usize]; println!("递归 n = {} 中的 nums 长度 = {}", n, nums.len()); - return quadratic_recur(n - 1); + quadratic_recur(n - 1) } /* 指数阶(建立满二叉树) */ @@ -94,7 +94,7 @@ fn build_tree(n: i32) -> Option>> { let root = TreeNode::new(0); root.borrow_mut().left = build_tree(n - 1); root.borrow_mut().right = build_tree(n - 1); - return Some(root); + Some(root) } /* Driver Code */ From 1870e88395ccbbf90941350d0247a80d116ac04e Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:29:21 +0800 Subject: [PATCH 012/109] refactor: replace all `n` types with `usize` When it comes to spatial overhead, `usize` should be used. --- .../space_complexity.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/space_complexity.rs b/codes/rust/chapter_computational_complexity/space_complexity.rs index 3b77d36273..6e384c9029 100644 --- a/codes/rust/chapter_computational_complexity/space_complexity.rs +++ b/codes/rust/chapter_computational_complexity/space_complexity.rs @@ -19,7 +19,7 @@ fn function() -> i32 { } /* 常数阶 */ -fn constant(n: i32) { +fn constant(n: usize) { // 常量、变量、对象占用 O(1) 空间 const A: i32 = 0; let b = 0; @@ -36,9 +36,9 @@ fn constant(n: i32) { } /* 线性阶 */ -fn linear(n: i32) { +fn linear(n: usize) { // 长度为 n 的数组占用 O(n) 空间 - let nums = vec![0; n as usize]; + let nums = vec![0; n]; // 长度为 n 的列表占用 O(n) 空间 let mut nodes = Vec::new(); for i in 0..n { @@ -52,18 +52,18 @@ fn linear(n: i32) { } /* 线性阶(递归实现) */ -fn linear_recur(n: i32) { +fn linear_recur(n: usize) { println!("递归 n = {}", n); if n == 1 { return; - }; + } linear_recur(n - 1); } /* 平方阶 */ -fn quadratic(n: i32) { +fn quadratic(n: usize) { // 矩阵占用 O(n^2) 空间 - let num_matrix = vec![vec![0; n as usize]; n as usize]; + let num_matrix = vec![vec![0; n]; n]; // 二维列表占用 O(n^2) 空间 let mut num_list = Vec::new(); for _ in 0..n { @@ -76,18 +76,18 @@ fn quadratic(n: i32) { } /* 平方阶(递归实现) */ -fn quadratic_recur(n: i32) -> i32 { - if n <= 0 { +fn quadratic_recur(n: usize) -> i32 { + if n == 0 { return 0; }; // 数组 nums 长度为 n, n-1, ..., 2, 1 - let nums = vec![0; n as usize]; + let nums = vec![0; n]; println!("递归 n = {} 中的 nums 长度 = {}", n, nums.len()); quadratic_recur(n - 1) } /* 指数阶(建立满二叉树) */ -fn build_tree(n: i32) -> Option>> { +fn build_tree(n: usize) -> Option>> { if n == 0 { return None; }; From 9080fb48efb93866974ff377c3e1529be202893c Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:30:09 +0800 Subject: [PATCH 013/109] refactor: simplify code --- .../space_complexity.rs | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/space_complexity.rs b/codes/rust/chapter_computational_complexity/space_complexity.rs index 6e384c9029..3ea42f1291 100644 --- a/codes/rust/chapter_computational_complexity/space_complexity.rs +++ b/codes/rust/chapter_computational_complexity/space_complexity.rs @@ -7,11 +7,14 @@ #![allow(dead_code)] #![allow(unused_variables)] -use hello_algo_rust::include::{ListNode, TreeNode, print_util}; +use hello_algo_rust::binary_tree::BinaryTree; +use hello_algo_rust::linked_list::ListNode; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; +type TreeNode = hello_algo_rust::binary_tree::TreeNode; + /* 函数 */ fn function() -> i32 { // 执行某些操作 @@ -40,20 +43,16 @@ fn linear(n: usize) { // 长度为 n 的数组占用 O(n) 空间 let nums = vec![0; n]; // 长度为 n 的列表占用 O(n) 空间 - let mut nodes = Vec::new(); - for i in 0..n { - nodes.push(ListNode::new(i)) - } + let nodes = (0..n).map(ListNode::new).collect::>(); // 长度为 n 的哈希表占用 O(n) 空间 - let mut map = HashMap::new(); - for i in 0..n { - map.insert(i, i.to_string()); - } + let map = (0..n) + .map(|i| (i, i.to_string())) + .collect::>(); } /* 线性阶(递归实现) */ fn linear_recur(n: usize) { - println!("递归 n = {}", n); + println!("递归 n = {n}"); if n == 1 { return; } @@ -62,27 +61,18 @@ fn linear_recur(n: usize) { /* 平方阶 */ fn quadratic(n: usize) { - // 矩阵占用 O(n^2) 空间 - let num_matrix = vec![vec![0; n]; n]; // 二维列表占用 O(n^2) 空间 - let mut num_list = Vec::new(); - for _ in 0..n { - let mut tmp = Vec::new(); - for _ in 0..n { - tmp.push(0); - } - num_list.push(tmp); - } + let num_matrix = vec![vec![0; n]; n]; } /* 平方阶(递归实现) */ fn quadratic_recur(n: usize) -> i32 { if n == 0 { return 0; - }; + } // 数组 nums 长度为 n, n-1, ..., 2, 1 let nums = vec![0; n]; - println!("递归 n = {} 中的 nums 长度 = {}", n, nums.len()); + println!("递归 n = {n} 中的 nums 长度 = {n}"); quadratic_recur(n - 1) } @@ -90,7 +80,7 @@ fn quadratic_recur(n: usize) -> i32 { fn build_tree(n: usize) -> Option>> { if n == 0 { return None; - }; + } let root = TreeNode::new(0); root.borrow_mut().left = build_tree(n - 1); root.borrow_mut().right = build_tree(n - 1); @@ -110,5 +100,5 @@ fn main() { quadratic_recur(n); // 指数阶 let root = build_tree(n); - print_util::print_tree(&root.unwrap()); + println!("{}", root.display()) } From e3037584c04368e3f7e56c265c8feb2870e6648a Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:31:48 +0800 Subject: [PATCH 014/109] fix: resolve warnings Explicitly omitted: - `clippy::manual_find` - `clippy::needless_range_loop` --- .../worst_best_time_complexity.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs b/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs index 1eb18fa105..b5848d3617 100644 --- a/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs +++ b/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs @@ -4,7 +4,6 @@ * Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; use rand::seq::SliceRandom; /* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */ @@ -17,6 +16,8 @@ fn random_numbers(n: i32) -> Vec { } /* 查找数组 nums 中数字 1 所在索引 */ +#[allow(clippy::manual_find)] +#[allow(clippy::needless_range_loop)] fn find_one(nums: &[i32]) -> Option { for i in 0..nums.len() { // 当元素 1 在数组头部时,达到最佳时间复杂度 O(1) @@ -34,8 +35,7 @@ fn main() { let n = 100; let nums = random_numbers(n); let index = find_one(&nums).unwrap(); - print!("\n数组 [ 1, 2, ..., n ] 被打乱后 = "); - print_util::print_array(&nums); - println!("\n数字 1 的索引为 {}", index); + println!("数组 [ 1, 2, ..., n ] 被打乱后 = {nums:?}"); + println!("数字 1 的索引为 {index}"); } } From 09839e39bd314e8b27fc2985ffaef92ecbe61ea3 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:33:48 +0800 Subject: [PATCH 015/109] fix: resolve warnings Removed: - `clippy::let_and_return` Explicitly omitted: - `unused_variables` - `unused_assignments` - `clippy::needless_range_loop` - `clippy::manual_find` --- .../chapter_array_and_linkedlist/array.rs | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/array.rs b/codes/rust/chapter_array_and_linkedlist/array.rs index ac59f3e8ac..d52f2861bb 100644 --- a/codes/rust/chapter_array_and_linkedlist/array.rs +++ b/codes/rust/chapter_array_and_linkedlist/array.rs @@ -4,7 +4,6 @@ * Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; use rand::Rng; /* 随机访问元素 */ @@ -12,8 +11,7 @@ pub fn random_access(nums: &[i32]) -> i32 { // 在区间 [0, nums.len()) 中随机抽取一个数字 let random_index = rand::rng().random_range(0..nums.len()); // 获取并返回随机元素 - let random_num = nums[random_index]; - random_num + nums[random_index] } /* 扩展数组长度 */ @@ -30,7 +28,7 @@ pub fn extend(nums: &[i32], enlarge: usize) -> Vec { /* 在数组的索引 index 处插入元素 num */ pub fn insert(nums: &mut [i32], num: i32, index: usize) { // 把索引 index 以及之后的所有元素向后移动一位 - for i in (index + 1..nums.len()).rev() { + for i in ((index + 1)..nums.len()).rev() { nums[i] = nums[i - 1]; } // 将 num 赋给 index 处的元素 @@ -40,26 +38,31 @@ pub fn insert(nums: &mut [i32], num: i32, index: usize) { /* 删除索引 index 处的元素 */ pub fn remove(nums: &mut [i32], index: usize) { // 把索引 index 之后的所有元素向前移动一位 - for i in index..nums.len() - 1 { + for i in index..(nums.len() - 1) { nums[i] = nums[i + 1]; } } /* 遍历数组 */ +#[allow(unused_variables)] +#[allow(unused_assignments)] +#[allow(clippy::needless_range_loop)] pub fn traverse(nums: &[i32]) { - let mut _count = 0; + let mut count = 0; // 通过索引遍历数组 for i in 0..nums.len() { - _count += nums[i]; + count += nums[i]; } // 直接遍历数组元素 - _count = 0; + count = 0; for &num in nums { - _count += num; + count += num; } } /* 在数组中查找指定元素 */ +#[allow(clippy::manual_find)] +#[allow(clippy::needless_range_loop)] pub fn find(nums: &[i32], target: i32) -> Option { for i in 0..nums.len() { if nums[i] == target { @@ -73,39 +76,34 @@ pub fn find(nums: &[i32], target: i32) -> Option { fn main() { /* 初始化数组 */ let arr: [i32; 5] = [0; 5]; - print!("数组 arr = "); - print_util::print_array(&arr); + println!("数组 arr = {arr:?}"); // 在 Rust 中,指定长度时([i32; 5])为数组,不指定长度时(&[i32])为切片 // 由于 Rust 的数组被设计为在编译期确定长度,因此只能使用常量来指定长度 // Vector 是 Rust 一般情况下用作动态数组的类型 // 为了方便实现扩容 extend() 方法,以下将 vector 看作数组(array) let nums: Vec = vec![1, 3, 2, 5, 4]; - print!("\n数组 nums = "); - print_util::print_array(&nums); + println!("数组 nums = {nums:?}"); // 随机访问 let random_num = random_access(&nums); - println!("\n在 nums 中获取随机元素 {}", random_num); + println!("在 nums 中获取随机元素 {random_num}"); // 长度扩展 let mut nums: Vec = extend(&nums, 3); - print!("将数组长度扩展至 8 ,得到 nums = "); - print_util::print_array(&nums); + print!("将数组长度扩展至 8 ,得到 nums = {nums:?}"); // 插入元素 insert(&mut nums, 6, 3); - print!("\n在索引 3 处插入数字 6 ,得到 nums = "); - print_util::print_array(&nums); + println!("在索引 3 处插入数字 6 ,得到 nums = {nums:?}"); // 删除元素 remove(&mut nums, 2); - print!("\n删除索引 2 处的元素,得到 nums = "); - print_util::print_array(&nums); + println!("删除索引 2 处的元素,得到 nums = {nums:?}"); // 遍历数组 traverse(&nums); // 查找元素 let index = find(&nums, 3).unwrap(); - println!("\n在 nums 中查找元素 3 ,得到索引 = {}", index); + println!("在 nums 中查找元素 3 ,得到索引 = {index}"); } From 560e79c250e2597ad250289fca23d3800a8964d8 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:37:10 +0800 Subject: [PATCH 016/109] refactor: simplify code --- .../linked_list.rs | 71 +++++++++---------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/linked_list.rs b/codes/rust/chapter_array_and_linkedlist/linked_list.rs index 99ac5c5302..4f3b69b0ef 100644 --- a/codes/rust/chapter_array_and_linkedlist/linked_list.rs +++ b/codes/rust/chapter_array_and_linkedlist/linked_list.rs @@ -4,7 +4,7 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, ListNode}; +use hello_algo_rust::linked_list::{LinkedList, ListNode}; use std::cell::RefCell; use std::rc::Rc; @@ -28,39 +28,36 @@ pub fn remove(n0: &Rc>>) { } /* 访问链表中索引为 index 的节点 */ -pub fn access(head: Rc>>, index: i32) -> Option>>> { - fn dfs( - head: Option<&Rc>>>, - index: i32, - ) -> Option>>> { - if index <= 0 { - return head.cloned(); - } - - if let Some(node) = head { - dfs(node.borrow().next.as_ref(), index - 1) - } else { - None - } +pub fn access( + head: &Rc>>, + index: usize, +) -> Option>>> { + if index == 0 { + return Some(head.clone()); } - - dfs(Some(head).as_ref(), index) + let mut next = head.borrow().next.clone(); + for _ in 1..index { + let node = next?; + next = node.borrow().next.clone(); + } + next } /* 在链表中查找值为 target 的首个节点 */ -pub fn find(head: Rc>>, target: T) -> i32 { - fn find(head: Option<&Rc>>>, target: T, idx: i32) -> i32 { - if let Some(node) = head { - if node.borrow().val == target { - return idx; - } - return find(node.borrow().next.as_ref(), target, idx + 1); - } else { - -1 +pub fn find(head: &Rc>>, target: T) -> Option { + if head.borrow().val == target { + return Some(0); + } + let mut next = head.borrow().next.clone(); + let mut index = 1; + while let Some(node) = next { + if node.borrow().val == target { + return Some(index); } + next = node.borrow().next.clone(); + index += 1; } - - find(Some(head).as_ref(), target, 0) + None } /* Driver Code */ @@ -77,24 +74,20 @@ fn main() { n1.borrow_mut().next = Some(n2.clone()); n2.borrow_mut().next = Some(n3.clone()); n3.borrow_mut().next = Some(n4.clone()); - print!("初始化的链表为 "); - print_util::print_linked_list(&n0); + println!("初始化的链表为 {}", n0.display_as_list()); /* 插入节点 */ insert(&n0, ListNode::new(0)); - print!("插入节点后的链表为 "); - print_util::print_linked_list(&n0); - + println!("插入节点后的链表为 {}", n0.display_as_list()); /* 删除节点 */ remove(&n0); - print!("删除节点后的链表为 "); - print_util::print_linked_list(&n0); + println!("删除节点后的链表为 {}", n0.display_as_list()); /* 访问节点 */ - let node = access(n0.clone(), 3); - println!("链表中索引 3 处的节点的值 = {}", node.unwrap().borrow().val); + let node = access(&n0, 3).unwrap(); + println!("链表中索引 3 处的节点的值 = {}", node.borrow().val); /* 查找节点 */ - let index = find(n0.clone(), 2); - println!("链表中值为 2 的节点的索引 = {}", index); + let index = find(&n0, 2).unwrap(); + println!("链表中值为 2 的节点的索引 = {index}"); } From de9e7c37fcaff0ac4b05e294024b50a16fb07d8f Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 20:41:21 +0800 Subject: [PATCH 017/109] fix: resolve warnings Explicitly omitted: - `unused_variables` - `unused_assignments` - `clippy::needless_range_loop` --- .../rust/chapter_array_and_linkedlist/list.rs | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/list.rs b/codes/rust/chapter_array_and_linkedlist/list.rs index d2f267be3b..3bc74e0ae0 100644 --- a/codes/rust/chapter_array_and_linkedlist/list.rs +++ b/codes/rust/chapter_array_and_linkedlist/list.rs @@ -3,28 +3,27 @@ * Created Time: 2023-01-18 * Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; /* Driver Code */ +#[allow(unused_variables)] +#[allow(unused_assignments)] +#[allow(clippy::needless_range_loop)] fn main() { // 初始化列表 let mut nums: Vec = vec![1, 3, 2, 5, 4]; - print!("列表 nums = "); - print_util::print_array(&nums); + println!("列表 nums = {nums:?}"); // 访问元素 let num = nums[1]; - println!("\n访问索引 1 处的元素,得到 num = {num}"); + println!("访问索引 1 处的元素,得到 num = {num}"); // 更新元素 nums[1] = 0; - print!("将索引 1 处的元素更新为 0 ,得到 nums = "); - print_util::print_array(&nums); + println!("将索引 1 处的元素更新为 0 ,得到 nums = {nums:?}"); // 清空列表 nums.clear(); - print!("\n清空列表后 nums = "); - print_util::print_array(&nums); + println!("清空列表后 nums = {nums:?}"); // 在尾部添加元素 nums.push(1); @@ -32,40 +31,34 @@ fn main() { nums.push(2); nums.push(5); nums.push(4); - print!("\n添加元素后 nums = "); - print_util::print_array(&nums); + println!("添加元素后 nums = {nums:?}"); // 在中间插入元素 nums.insert(3, 6); - print!("\n在索引 3 处插入数字 6 ,得到 nums = "); - print_util::print_array(&nums); + println!("在索引 3 处插入数字 6 ,得到 nums = {nums:?}"); // 删除元素 nums.remove(3); - print!("\n删除索引 3 处的元素,得到 nums = "); - print_util::print_array(&nums); + println!("删除索引 3 处的元素,得到 nums = {nums:?}"); // 通过索引遍历列表 - let mut _count = 0; + let mut count = 0; for i in 0..nums.len() { - _count += nums[i]; + count += nums[i]; } + // 直接遍历列表元素 - _count = 0; + let mut count = 0; for x in &nums { - _count += x; + count += x; } // 拼接两个列表 - let mut nums1 = vec![6, 8, 7, 10, 9]; - nums.append(&mut nums1); // append(移动) 之后 nums1 为空! - - // nums.extend(&nums1); // extend(借用) nums1 能继续使用 - print!("\n将列表 nums1 拼接到 nums 之后,得到 nums = "); - print_util::print_array(&nums); + let nums1 = vec![6, 8, 7, 10, 9]; + nums.extend(nums1); + println!("将列表 nums1 拼接到 nums 之后,得到 nums = {nums:?}"); // 排序列表 nums.sort(); - print!("\n排序列表后 nums = "); - print_util::print_array(&nums); + println!("排序列表后 nums = {nums:?}"); } From 86b72d0a797506ee81332328ed0d0199b345b0d9 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:05:40 +0800 Subject: [PATCH 018/109] fix: resolve warning Removed: - `clippy::needless_return` --- codes/rust/chapter_array_and_linkedlist/my_list.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/my_list.rs b/codes/rust/chapter_array_and_linkedlist/my_list.rs index ba5d0026e9..87a4bf768f 100644 --- a/codes/rust/chapter_array_and_linkedlist/my_list.rs +++ b/codes/rust/chapter_array_and_linkedlist/my_list.rs @@ -7,7 +7,6 @@ use hello_algo_rust::include::print_util; /* 列表类 */ -#[allow(dead_code)] pub struct MyList { arr: Vec, // 数组(存储列表元素) capacity: usize, // 列表容量 @@ -15,13 +14,11 @@ pub struct MyList { extend_ratio: usize, // 每次列表扩容的倍数 } -#[allow(unused, unused_comparisons)] impl MyList { /* 构造方法 */ pub fn new(capacity: usize) -> Self { - let mut vec = vec![0; capacity]; Self { - arr: vec, + arr: vec![0; capacity], capacity, size: 0, extend_ratio: 2, @@ -30,12 +27,12 @@ impl MyList { /* 获取列表长度(当前元素数量)*/ pub fn size(&self) -> usize { - return self.size; + self.size } /* 获取列表容量 */ pub fn capacity(&self) -> usize { - return self.capacity; + self.capacity } /* 访问元素 */ @@ -44,7 +41,7 @@ impl MyList { if index >= self.size { panic!("索引越界") }; - return self.arr[index]; + self.arr[index] } /* 更新元素 */ @@ -97,7 +94,7 @@ impl MyList { // 更新元素数量 self.size -= 1; // 返回被删除的元素 - return num; + num } /* 列表扩容 */ From cf8163bcb940b8d5b78fbff5f7a6abda340688fa Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:05:52 +0800 Subject: [PATCH 019/109] fix: resolve a bug where capacity remained 0 when supposed to grow --- codes/rust/chapter_array_and_linkedlist/my_list.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/my_list.rs b/codes/rust/chapter_array_and_linkedlist/my_list.rs index 87a4bf768f..af57362634 100644 --- a/codes/rust/chapter_array_and_linkedlist/my_list.rs +++ b/codes/rust/chapter_array_and_linkedlist/my_list.rs @@ -99,8 +99,14 @@ impl MyList { /* 列表扩容 */ pub fn extend_capacity(&mut self) { - // 新建一个长度为原数组 extend_ratio 倍的新数组,并将原数组复制到新数组 - let new_capacity = self.capacity * self.extend_ratio; + // 如果原数组容量为 0,新建一个长度为 4 的新数组,否则新建一个长度为原数组 extend_ratio 倍的新数组; + // 将原数组复制到新数组 + let new_capacity = if self.capacity == 0 { + // 先前实现没有考虑初始容量为 0 的情况,这会导致容量无法增长 + 4 + } else { + self.capacity * self.extend_ratio + }; self.arr.resize(new_capacity, 0); // 更新列表容量 self.capacity = new_capacity; From 99fcfed8a347672922fb91852c3bc932cca4fb0d Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:06:03 +0800 Subject: [PATCH 020/109] refactor: replace field `extend_ratio` with associated constant `EXTEND_RATIO` --- codes/rust/chapter_array_and_linkedlist/my_list.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/my_list.rs b/codes/rust/chapter_array_and_linkedlist/my_list.rs index af57362634..f6f1a8addf 100644 --- a/codes/rust/chapter_array_and_linkedlist/my_list.rs +++ b/codes/rust/chapter_array_and_linkedlist/my_list.rs @@ -8,20 +8,20 @@ use hello_algo_rust::include::print_util; /* 列表类 */ pub struct MyList { - arr: Vec, // 数组(存储列表元素) - capacity: usize, // 列表容量 - size: usize, // 列表长度(当前元素数量) - extend_ratio: usize, // 每次列表扩容的倍数 + arr: Vec, // 数组(存储列表元素) + capacity: usize, // 列表容量 + size: usize, // 列表长度(当前元素数量) } impl MyList { + const EXTEND_RATIO: usize = 2; // 每次列表扩容的倍数 + /* 构造方法 */ pub fn new(capacity: usize) -> Self { Self { arr: vec![0; capacity], capacity, size: 0, - extend_ratio: 2, } } @@ -105,7 +105,7 @@ impl MyList { // 先前实现没有考虑初始容量为 0 的情况,这会导致容量无法增长 4 } else { - self.capacity * self.extend_ratio + self.capacity * Self::EXTEND_RATIO }; self.arr.resize(new_capacity, 0); // 更新列表容量 From ca4b3d35264303b24b732ffa95b3e0a1771c58d1 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:06:13 +0800 Subject: [PATCH 021/109] refactor: rewrite formatted output logic --- .../chapter_array_and_linkedlist/my_list.rs | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/codes/rust/chapter_array_and_linkedlist/my_list.rs b/codes/rust/chapter_array_and_linkedlist/my_list.rs index f6f1a8addf..90ccab1d67 100644 --- a/codes/rust/chapter_array_and_linkedlist/my_list.rs +++ b/codes/rust/chapter_array_and_linkedlist/my_list.rs @@ -4,7 +4,8 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; +use hello_algo_rust::fmt::Write; +use std::fmt; /* 列表类 */ pub struct MyList { @@ -39,16 +40,16 @@ impl MyList { pub fn get(&self, index: usize) -> i32 { // 索引如果越界,则抛出异常,下同 if index >= self.size { - panic!("索引越界") - }; + panic!("索引越界"); + } self.arr[index] } /* 更新元素 */ pub fn set(&mut self, index: usize, num: i32) { if index >= self.size { - panic!("索引越界") - }; + panic!("索引越界"); + } self.arr[index] = num; } @@ -66,8 +67,8 @@ impl MyList { /* 在中间插入元素 */ pub fn insert(&mut self, index: usize, num: i32) { if index >= self.size() { - panic!("索引越界") - }; + panic!("索引越界"); + } // 元素数量超出容量时,触发扩容机制 if self.size == self.capacity() { self.extend_capacity(); @@ -84,8 +85,8 @@ impl MyList { /* 删除元素 */ pub fn remove(&mut self, index: usize) -> i32 { if index >= self.size() { - panic!("索引越界") - }; + panic!("索引越界"); + } let num = self.arr[index]; // 将索引 index 之后的元素都向前移动一位 for j in index..self.size - 1 { @@ -115,53 +116,58 @@ impl MyList { /* 将列表转换为数组 */ pub fn to_array(&self) -> Vec { // 仅转换有效长度范围内的列表元素 - let mut arr = Vec::new(); - for i in 0..self.size { - arr.push(self.get(i)); - } - arr + self.arr[0..self.size].to_vec() + } +} + +impl fmt::Display for MyList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_array(&self.arr[0..self.size]) } } /* Driver Code */ fn main() { /* 初始化列表 */ - let mut nums = MyList::new(10); + let mut nums = MyList::new(5); /* 在尾部添加元素 */ nums.add(1); nums.add(3); nums.add(2); nums.add(5); nums.add(4); - print!("列表 nums = "); - print_util::print_array(&nums.to_array()); - print!(" ,容量 = {} ,长度 = {}", nums.capacity(), nums.size()); + println!( + "列表 nums = {} ,容量 = {} ,长度 = {}", + nums, + nums.capacity(), + nums.size() + ); /* 在中间插入元素 */ nums.insert(3, 6); - print!("\n在索引 3 处插入数字 6 ,得到 nums = "); - print_util::print_array(&nums.to_array()); + println!("在索引 3 处插入数字 6 ,得到 nums = {nums}"); /* 删除元素 */ nums.remove(3); - print!("\n删除索引 3 处的元素,得到 nums = "); - print_util::print_array(&nums.to_array()); + println!("删除索引 3 处的元素,得到 nums = {nums}"); /* 访问元素 */ let num = nums.get(1); - println!("\n访问索引 1 处的元素,得到 num = {num}"); + println!("访问索引 1 处的元素,得到 num = {num}"); /* 更新元素 */ nums.set(1, 0); - print!("将索引 1 处的元素更新为 0 ,得到 nums = "); - print_util::print_array(&nums.to_array()); + println!("将索引 1 处的元素更新为 0 ,得到 nums = {nums}"); /* 测试扩容机制 */ for i in 0..10 { // 在 i = 5 时,列表长度将超出列表容量,此时触发扩容机制 nums.add(i); } - print!("\n扩容后的列表 nums = "); - print_util::print_array(&nums.to_array()); - print!(" ,容量 = {} ,长度 = {}", nums.capacity(), nums.size()); + println!( + "扩容后的列表 nums = {} ,容量 = {} ,长度 = {}", + nums, + nums.capacity(), + nums.size() + ); } From 368166270396266e9a4c79dc1cc8113f4797d9d6 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:06:20 +0800 Subject: [PATCH 022/109] fix: resolve warning Explicitly omitted: - `clippy::vec_init_then_push` --- codes/rust/chapter_stack_and_queue/stack.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/stack.rs b/codes/rust/chapter_stack_and_queue/stack.rs index a1d7798bf0..a67a043713 100644 --- a/codes/rust/chapter_stack_and_queue/stack.rs +++ b/codes/rust/chapter_stack_and_queue/stack.rs @@ -4,9 +4,8 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; - /* Driver Code */ +#[allow(clippy::vec_init_then_push)] fn main() { // 初始化栈 // 在 rust 中,推荐将 Vec 当作栈来使用 @@ -18,23 +17,21 @@ fn main() { stack.push(2); stack.push(5); stack.push(4); - print!("栈 stack = "); - print_util::print_array(&stack); + println!("栈 stack = {stack:?}"); // 访问栈顶元素 let peek = stack.last().unwrap(); - print!("\n栈顶元素 peek = {peek}"); + println!("栈顶元素 peek = {peek}"); // 元素出栈 let pop = stack.pop().unwrap(); - print!("\n出栈元素 pop = {pop},出栈后 stack = "); - print_util::print_array(&stack); + println!("出栈元素 pop = {pop},出栈后 stack = {stack:?}"); // 获取栈的长度 let size = stack.len(); - print!("\n栈的长度 size = {size}"); + println!("栈的长度 size = {size}"); // 判断栈是否为空 let is_empty = stack.is_empty(); - print!("\n栈是否为空 = {is_empty}"); + println!("栈是否为空 = {is_empty}"); } From 1a57965a843ae3d941cc4c6b92b1f456f6d641f4 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:10:35 +0800 Subject: [PATCH 023/109] refactor: rewrite `LinkedListStack::pop` and `LinkedListStack::to_array` --- .../linkedlist_stack.rs | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs b/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs index 7f75586b0c..daf1b08284 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs @@ -4,29 +4,29 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, ListNode}; +use hello_algo_rust::include::{ListNode, print_util}; use std::cell::RefCell; use std::rc::Rc; /* 基于链表实现的栈 */ -#[allow(dead_code)] + pub struct LinkedListStack { - stack_peek: Option>>>, // 将头节点作为栈顶 - stk_size: usize, // 栈的长度 + peek: Option>>>, // 将头节点作为栈顶 + size: usize, // 栈的长度 } -impl LinkedListStack { +impl LinkedListStack { pub fn new() -> Self { Self { - stack_peek: None, - stk_size: 0, + peek: None, + size: 0, } } /* 获取栈的长度 */ pub fn size(&self) -> usize { - return self.stk_size; + return self.size; } /* 判断栈是否为空 */ @@ -37,38 +37,42 @@ impl LinkedListStack { /* 入栈 */ pub fn push(&mut self, num: T) { let node = ListNode::new(num); - node.borrow_mut().next = self.stack_peek.take(); - self.stack_peek = Some(node); - self.stk_size += 1; + node.borrow_mut().next = self.peek.take(); + self.peek = Some(node); + self.size += 1; } /* 出栈 */ - pub fn pop(&mut self) -> Option { - self.stack_peek.take().map(|old_head| { - self.stack_peek = old_head.borrow_mut().next.take(); - self.stk_size -= 1; - - old_head.borrow().val - }) + pub fn pop(&mut self) -> Option + where + T: Clone, + { + let peek = self.peek.take()?; + let val = peek.borrow().val.clone(); + self.peek = peek.borrow_mut().next.take(); + self.size -= 1; + Some(val) } /* 访问栈顶元素 */ - pub fn peek(&self) -> Option<&Rc>>> { - self.stack_peek.as_ref() + pub fn peek(&self) -> &Option>>> { + &self.peek } /* 将 List 转化为 Array 并返回 */ - pub fn to_array(&self) -> Vec { - fn _to_array(head: Option<&Rc>>>) -> Vec { - if let Some(node) = head { - let mut nums = _to_array(node.borrow().next.as_ref()); - nums.push(node.borrow().val); - return nums; - } - return Vec::new(); + pub fn to_array(&self) -> Vec + where + T: Clone, + { + let mut res = Vec::with_capacity(self.size); + let mut next = self.peek.clone(); + while let Some(node) = next { + let borrow = node.borrow(); + let val = borrow.val.clone(); + res.push(val); + next = borrow.next.clone(); } - - _to_array(self.peek()) + res } } @@ -87,7 +91,7 @@ fn main() { print_util::print_array(&stack.to_array()); /* 访问栈顶元素 */ - let peek = stack.peek().unwrap().borrow().val; + let peek = stack.peek().as_ref().unwrap().borrow().val; print!("\n栈顶元素 peek = {}", peek); /* 元素出栈 */ From 9321f08151b67ffd93492942e5508ff44aff147a Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:11:05 +0800 Subject: [PATCH 024/109] fix: resolve warnings Removed: - `clippy::needless_return` Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_stack_and_queue/linkedlist_stack.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs b/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs index daf1b08284..0bc5757f43 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs @@ -17,6 +17,7 @@ pub struct LinkedListStack { } impl LinkedListStack { + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { peek: None, @@ -26,12 +27,12 @@ impl LinkedListStack { /* 获取栈的长度 */ pub fn size(&self) -> usize { - return self.size; + self.size } /* 判断栈是否为空 */ pub fn is_empty(&self) -> bool { - return self.size() == 0; + self.size == 0 } /* 入栈 */ From 981797af2eca139703ab0388435779cf73a0e762 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 21:13:23 +0800 Subject: [PATCH 025/109] refactor: rewrite formatted output logic --- .../linkedlist_stack.rs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs b/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs index 0bc5757f43..5f5f05fab3 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs @@ -4,13 +4,12 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{ListNode, print_util}; - +use hello_algo_rust::linked_list::{LinkedList, ListNode}; use std::cell::RefCell; +use std::fmt; use std::rc::Rc; /* 基于链表实现的栈 */ - pub struct LinkedListStack { peek: Option>>>, // 将头节点作为栈顶 size: usize, // 栈的长度 @@ -77,6 +76,15 @@ impl LinkedListStack { } } +impl fmt::Display for LinkedListStack +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.peek.display_as_array()) + } +} + /* Driver Code */ fn main() { /* 初始化栈 */ @@ -88,23 +96,21 @@ fn main() { stack.push(2); stack.push(5); stack.push(4); - print!("栈 stack = "); - print_util::print_array(&stack.to_array()); + println!("栈 stack = {stack}"); /* 访问栈顶元素 */ let peek = stack.peek().as_ref().unwrap().borrow().val; - print!("\n栈顶元素 peek = {}", peek); + println!("栈顶元素 peek = {peek}"); /* 元素出栈 */ let pop = stack.pop().unwrap(); - print!("\n出栈元素 pop = {},出栈后 stack = ", pop); - print_util::print_array(&stack.to_array()); + println!("出栈元素 pop = {pop},出栈后 stack = {stack}"); /* 获取栈的长度 */ let size = stack.size(); - print!("\n栈的长度 size = {}", size); + println!("栈的长度 size = {size}"); /* 判断是否为空 */ let is_empty = stack.is_empty(); - print!("\n栈是否为空 = {}", is_empty); + println!("栈是否为空 = {is_empty}"); } From 1849698fa88fd49a746f38c5ca8ea34d75a80cb3 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:32:23 +0800 Subject: [PATCH 026/109] fix: resolve warning Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_stack_and_queue/array_stack.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/codes/rust/chapter_stack_and_queue/array_stack.rs b/codes/rust/chapter_stack_and_queue/array_stack.rs index 454e202fae..eb0b873333 100644 --- a/codes/rust/chapter_stack_and_queue/array_stack.rs +++ b/codes/rust/chapter_stack_and_queue/array_stack.rs @@ -13,6 +13,7 @@ pub struct ArrayStack { impl ArrayStack { /* 初始化栈 */ + #[allow(clippy::new_without_default)] pub fn new() -> ArrayStack { ArrayStack:: { stack: Vec::::new(), From 532750a16fe5ec09968f1f3fbc0b5a845a134130 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:32:31 +0800 Subject: [PATCH 027/109] refactor: simplify code --- .../chapter_stack_and_queue/array_stack.rs | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/array_stack.rs b/codes/rust/chapter_stack_and_queue/array_stack.rs index eb0b873333..d0f688032a 100644 --- a/codes/rust/chapter_stack_and_queue/array_stack.rs +++ b/codes/rust/chapter_stack_and_queue/array_stack.rs @@ -4,8 +4,6 @@ * Author: WSL0809 (wslzzy@outlook.com), codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; - /* 基于数组实现的栈 */ pub struct ArrayStack { stack: Vec, @@ -15,9 +13,7 @@ impl ArrayStack { /* 初始化栈 */ #[allow(clippy::new_without_default)] pub fn new() -> ArrayStack { - ArrayStack:: { - stack: Vec::::new(), - } + Self { stack: Vec::new() } } /* 获取栈的长度 */ @@ -42,9 +38,6 @@ impl ArrayStack { /* 访问栈顶元素 */ pub fn peek(&self) -> Option<&T> { - if self.is_empty() { - panic!("栈为空") - }; self.stack.last() } @@ -65,23 +58,25 @@ fn main() { stack.push(2); stack.push(5); stack.push(4); - print!("栈 stack = "); - print_util::print_array(stack.to_array()); + println!("栈 stack = {:?}", stack.to_array()); //访问栈顶元素 let peek = stack.peek().unwrap(); - print!("\n栈顶元素 peek = {}", peek); + println!("栈顶元素 peek = {peek}"); // 元素出栈 let pop = stack.pop().unwrap(); - print!("\n出栈元素 pop = {pop},出栈后 stack = "); - print_util::print_array(stack.to_array()); + println!( + "出栈元素 pop = {},出栈后 stack = {:?}", + pop, + stack.to_array() + ); // 获取栈的长度 let size = stack.size(); - print!("\n栈的长度 size = {size}"); + println!("栈的长度 size = {size}"); // 判断是否为空 let is_empty = stack.is_empty(); - print!("\n栈是否为空 = {is_empty}"); + println!("栈是否为空 = {is_empty}"); } From f223a4666f611af5636427c3eb1bc2fa5991d94c Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:32:41 +0800 Subject: [PATCH 028/109] refactor: simplify formatted output logic --- codes/rust/chapter_stack_and_queue/queue.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/queue.rs b/codes/rust/chapter_stack_and_queue/queue.rs index 209aa441c2..ad440cda20 100644 --- a/codes/rust/chapter_stack_and_queue/queue.rs +++ b/codes/rust/chapter_stack_and_queue/queue.rs @@ -4,14 +4,12 @@ * Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICEx@outlook.com) */ -use hello_algo_rust::include::print_util; - use std::collections::VecDeque; /* Driver Code */ fn main() { // 初始化队列 - let mut queue: VecDeque = VecDeque::new(); + let mut queue = VecDeque::new(); // 元素入队 queue.push_back(1); @@ -19,23 +17,21 @@ fn main() { queue.push_back(2); queue.push_back(5); queue.push_back(4); - print!("队列 queue = "); - print_util::print_queue(&queue); + println!("队列 queue = {queue:?}"); // 访问队首元素 let peek = queue.front().unwrap(); - println!("\n队首元素 peek = {peek}"); + println!("队首元素 peek = {peek}"); // 元素出队 let pop = queue.pop_front().unwrap(); - print!("出队元素 pop = {pop},出队后 queue = "); - print_util::print_queue(&queue); + println!("出队元素 pop = {pop},出队后 queue = {queue:?}"); // 获取队列的长度 let size = queue.len(); - print!("\n队列长度 size = {size}"); + println!("队列长度 size = {size}"); // 判断队列是否为空 let is_empty = queue.is_empty(); - print!("\n队列是否为空 = {is_empty}"); + println!("队列是否为空 = {is_empty}"); } From 7f3cb244e2e971ddeb7ef14745266d20625a6829 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:33:00 +0800 Subject: [PATCH 029/109] refactor: rewrite `LinkedListQueue::pop` and `LinkedListQueue::to_array` --- .../linkedlist_queue.rs | 73 ++++++++++--------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs b/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs index d359182413..2181f214d0 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs @@ -4,7 +4,7 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, ListNode}; +use hello_algo_rust::include::{ListNode, print_util}; use std::cell::RefCell; use std::rc::Rc; @@ -14,26 +14,26 @@ use std::rc::Rc; pub struct LinkedListQueue { front: Option>>>, // 头节点 front rear: Option>>>, // 尾节点 rear - que_size: usize, // 队列的长度 + size: usize, // 队列的长度 } -impl LinkedListQueue { +impl LinkedListQueue { pub fn new() -> Self { Self { front: None, rear: None, - que_size: 0, + size: 0, } } /* 获取队列的长度 */ pub fn size(&self) -> usize { - return self.que_size; + return self.size; } /* 判断队列是否为空 */ pub fn is_empty(&self) -> bool { - return self.que_size == 0; + return self.size == 0; } /* 入队 */ @@ -52,43 +52,46 @@ impl LinkedListQueue { self.rear = Some(new_rear); } } - self.que_size += 1; + self.size += 1; } /* 出队 */ - pub fn pop(&mut self) -> Option { - self.front.take().map(|old_front| { - match old_front.borrow_mut().next.take() { - Some(new_front) => { - self.front = Some(new_front); - } - None => { - self.rear.take(); - } + pub fn pop(&mut self) -> Option + where + T: Clone, + { + let old_front = self.front.take()?; + match old_front.borrow_mut().next.take() { + Some(new_front) => { + self.front = Some(new_front); } - self.que_size -= 1; - old_front.borrow().val - }) + None => { + self.rear = None; + } + } + self.size -= 1; + let val = old_front.borrow().val.clone(); + Some(val) } /* 访问队首元素 */ - pub fn peek(&self) -> Option<&Rc>>> { - self.front.as_ref() + pub fn peek(&self) -> &Option>>> { + &self.front } /* 将链表转化为 Array 并返回 */ - pub fn to_array(&self, head: Option<&Rc>>>) -> Vec { - let mut res: Vec = Vec::new(); - - fn recur(cur: Option<&Rc>>>, res: &mut Vec) { - if let Some(cur) = cur { - res.push(cur.borrow().val); - recur(cur.borrow().next.as_ref(), res); - } + pub fn to_array(&self) -> Vec + where + T: Clone, + { + let mut res = Vec::with_capacity(self.size); + let mut next = self.front.clone(); + while let Some(node) = next { + let borrow = node.borrow(); + let val = borrow.val.clone(); + res.push(val); + next = borrow.next.clone(); } - - recur(head, &mut res); - res } } @@ -105,16 +108,16 @@ fn main() { queue.push(5); queue.push(4); print!("队列 queue = "); - print_util::print_array(&queue.to_array(queue.peek())); + print_util::print_array(&queue.to_array()); /* 访问队首元素 */ - let peek = queue.peek().unwrap().borrow().val; + let peek = queue.peek().as_ref().unwrap().borrow().val; print!("\n队首元素 peek = {}", peek); /* 元素出队 */ let pop = queue.pop().unwrap(); print!("\n出队元素 pop = {},出队后 queue = ", pop); - print_util::print_array(&queue.to_array(queue.peek())); + print_util::print_array(&queue.to_array()); /* 获取队列的长度 */ let size = queue.size(); From 7d3c628e94612ab1687ac150701e4c13b13b6abc Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:33:10 +0800 Subject: [PATCH 030/109] fix: resolve warnings Removed: - `clippy::needless_return` Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_stack_and_queue/linkedlist_queue.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs b/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs index 2181f214d0..a876678af9 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs @@ -10,7 +10,6 @@ use std::cell::RefCell; use std::rc::Rc; /* 基于链表实现的队列 */ -#[allow(dead_code)] pub struct LinkedListQueue { front: Option>>>, // 头节点 front rear: Option>>>, // 尾节点 rear @@ -18,6 +17,7 @@ pub struct LinkedListQueue { } impl LinkedListQueue { + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { front: None, @@ -28,12 +28,12 @@ impl LinkedListQueue { /* 获取队列的长度 */ pub fn size(&self) -> usize { - return self.size; + self.size } /* 判断队列是否为空 */ pub fn is_empty(&self) -> bool { - return self.size == 0; + self.size == 0 } /* 入队 */ From 1ee80121ef5c33aa8f4fc15f88ece58f66c4be5e Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:33:19 +0800 Subject: [PATCH 031/109] refactor: rewrite formatted output logic --- .../linkedlist_queue.rs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs b/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs index a876678af9..0450abf4ed 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs @@ -4,15 +4,15 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{ListNode, print_util}; - +use hello_algo_rust::linked_list::{LinkedList, ListNode}; use std::cell::RefCell; +use std::fmt; use std::rc::Rc; /* 基于链表实现的队列 */ pub struct LinkedListQueue { - front: Option>>>, // 头节点 front - rear: Option>>>, // 尾节点 rear + front: Option>>>, // 头节点 + rear: Option>>>, // 尾节点 size: usize, // 队列的长度 } @@ -96,6 +96,15 @@ impl LinkedListQueue { } } +impl fmt::Display for LinkedListQueue +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.front.display_as_array()) + } +} + /* Driver Code */ fn main() { /* 初始化队列 */ @@ -107,23 +116,21 @@ fn main() { queue.push(2); queue.push(5); queue.push(4); - print!("队列 queue = "); - print_util::print_array(&queue.to_array()); + println!("队列 queue = {queue}"); /* 访问队首元素 */ let peek = queue.peek().as_ref().unwrap().borrow().val; - print!("\n队首元素 peek = {}", peek); + println!("队首元素 peek = {peek}"); /* 元素出队 */ let pop = queue.pop().unwrap(); - print!("\n出队元素 pop = {},出队后 queue = ", pop); - print_util::print_array(&queue.to_array()); + println!("出队元素 pop = {pop},出队后 queue = {queue}"); /* 获取队列的长度 */ let size = queue.size(); - print!("\n队列长度 size = {}", size); + println!("队列长度 size = {size}"); /* 判断队列是否为空 */ let is_empty = queue.is_empty(); - print!("\n队列是否为空 = {}", is_empty); + println!("队列是否为空 = {is_empty}"); } From 9ad1178913d5292882444f3eae5f49b349923124 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:33:30 +0800 Subject: [PATCH 032/109] refactor: remove unnecessary trait field and trait bound --- .../chapter_stack_and_queue/array_queue.rs | 94 ++++++++++--------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/array_queue.rs b/codes/rust/chapter_stack_and_queue/array_queue.rs index a33b53f338..c1776dd91b 100644 --- a/codes/rust/chapter_stack_and_queue/array_queue.rs +++ b/codes/rust/chapter_stack_and_queue/array_queue.rs @@ -6,79 +6,89 @@ /* 基于环形数组实现的队列 */ pub struct ArrayQueue { - nums: Vec, // 用于存储队列元素的数组 - front: i32, // 队首指针,指向队首元素 - que_size: i32, // 队列长度 - que_capacity: i32, // 队列容量 + nums: Vec, // 用于存储队列元素的数组 + front: usize, // 队首指针,指向队首元素 + size: usize, // 队列长度 } -impl ArrayQueue { +impl ArrayQueue { /* 构造方法 */ - pub fn new(capacity: i32) -> ArrayQueue { - ArrayQueue { - nums: vec![T::default(); capacity as usize], + pub fn new(capacity: usize) -> Self + where + T: Default, + { + Self { + nums: (0..capacity).map(|_| T::default()).collect(), front: 0, - que_size: 0, - que_capacity: capacity, + size: 0, } } /* 获取队列的容量 */ - pub fn capacity(&self) -> i32 { - self.que_capacity + pub fn capacity(&self) -> usize { + self.nums.len() } /* 获取队列的长度 */ - pub fn size(&self) -> i32 { - self.que_size + pub fn size(&self) -> usize { + self.size } /* 判断队列是否为空 */ pub fn is_empty(&self) -> bool { - self.que_size == 0 + self.size == 0 } /* 入队 */ pub fn push(&mut self, num: T) { - if self.que_size == self.capacity() { - println!("队列已满"); - return; + if self.size == self.capacity() { + panic!("队列已满"); } // 计算队尾指针,指向队尾索引 + 1 // 通过取余操作实现 rear 越过数组尾部后回到头部 - let rear = (self.front + self.que_size) % self.que_capacity; + let rear = (self.front + self.size) % self.capacity(); // 将 num 添加至队尾 - self.nums[rear as usize] = num; - self.que_size += 1; + self.nums[rear] = num; + self.size += 1; } /* 出队 */ - pub fn pop(&mut self) -> T { - let num = self.peek(); + pub fn pop(&mut self) -> Option + where + T: Clone, + { + if self.is_empty() { + return None; + } + let num = self.nums[self.front].clone(); // 队首指针向后移动一位,若越过尾部,则返回到数组头部 - self.front = (self.front + 1) % self.que_capacity; - self.que_size -= 1; - num + self.front = (self.front + 1) % self.capacity(); + self.size -= 1; + Some(num) } /* 访问队首元素 */ - pub fn peek(&self) -> T { + pub fn peek(&self) -> Option<&T> { if self.is_empty() { - panic!("index out of bounds"); + return None; } - self.nums[self.front as usize] + Some(&self.nums[self.front]) } /* 返回数组 */ - pub fn to_vector(&self) -> Vec { - let cap = self.que_capacity; - let mut j = self.front; - let mut arr = vec![T::default(); cap as usize]; - for i in 0..self.que_size { - arr[i as usize] = self.nums[(j % cap) as usize]; - j += 1; + pub fn to_array(&self) -> Vec + where + T: Clone, + { + let mut res = Vec::with_capacity(self.size); + for index in self.front..(self.front + self.size) { + // 考虑存在不变式 `self.size <= self.capacity()`, + // 且 `self.size == 0` 时不会进入该循环,除零错误不会发生。 + let index = index % self.capacity(); + let num = self.nums[index].clone(); + res.push(num); } - arr + res } } @@ -94,18 +104,18 @@ fn main() { queue.push(2); queue.push(5); queue.push(4); - println!("队列 queue = {:?}", queue.to_vector()); + println!("队列 queue = {:?}", queue.to_array()); /* 访问队首元素 */ - let peek = queue.peek(); + let peek = queue.peek().unwrap(); println!("队首元素 peek = {}", peek); /* 元素出队 */ - let pop = queue.pop(); + let pop = queue.pop().unwrap(); println!( "出队元素 pop = {:?},出队后 queue = {:?}", pop, - queue.to_vector() + queue.to_array() ); /* 获取队列的长度 */ @@ -120,6 +130,6 @@ fn main() { for i in 0..10 { queue.push(i); queue.pop(); - println!("第 {:?} 轮入队 + 出队后 queue = {:?}", i, queue.to_vector()); + println!("第 {:?} 轮入队 + 出队后 queue = {:?}", i, queue.to_array()); } } From 8d8005c456138e767d7ba44e10aed0c9e4d2e2c9 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:33:38 +0800 Subject: [PATCH 033/109] refactor: rewrite formatted output logic --- .../chapter_stack_and_queue/array_queue.rs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/array_queue.rs b/codes/rust/chapter_stack_and_queue/array_queue.rs index c1776dd91b..3788986095 100644 --- a/codes/rust/chapter_stack_and_queue/array_queue.rs +++ b/codes/rust/chapter_stack_and_queue/array_queue.rs @@ -4,6 +4,9 @@ * Author: WSL0809 (wslzzy@outlook.com) */ +use hello_algo_rust::fmt::Write; +use std::fmt; + /* 基于环形数组实现的队列 */ pub struct ArrayQueue { nums: Vec, // 用于存储队列元素的数组 @@ -92,6 +95,17 @@ impl ArrayQueue { } } +impl fmt::Display for ArrayQueue +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = + (self.front..(self.front + self.size)).map(|index| &self.nums[index % self.capacity()]); + f.write_array(iter) + } +} + /* Driver Code */ fn main() { /* 初始化队列 */ @@ -104,23 +118,19 @@ fn main() { queue.push(2); queue.push(5); queue.push(4); - println!("队列 queue = {:?}", queue.to_array()); + println!("队列 queue = {queue}"); /* 访问队首元素 */ let peek = queue.peek().unwrap(); - println!("队首元素 peek = {}", peek); + println!("队首元素 peek = {peek}"); /* 元素出队 */ let pop = queue.pop().unwrap(); - println!( - "出队元素 pop = {:?},出队后 queue = {:?}", - pop, - queue.to_array() - ); + println!("出队元素 pop = {pop},出队后 queue = {queue}"); /* 获取队列的长度 */ let size = queue.size(); - println!("队列长度 size = {}", size); + println!("队列长度 size = {size}"); /* 判断队列是否为空 */ let is_empty = queue.is_empty(); @@ -130,6 +140,6 @@ fn main() { for i in 0..10 { queue.push(i); queue.pop(); - println!("第 {:?} 轮入队 + 出队后 queue = {:?}", i, queue.to_array()); + println!("第 {i} 轮入队 + 出队后 queue = {queue}"); } } From ac7b05a1a90dd6591f5b8df80c5508c4c677d750 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:33:45 +0800 Subject: [PATCH 034/109] refactor: simplify formatted output logic --- codes/rust/chapter_stack_and_queue/deque.rs | 27 +++++++++------------ 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/deque.rs b/codes/rust/chapter_stack_and_queue/deque.rs index ce8cffb66d..396a031076 100644 --- a/codes/rust/chapter_stack_and_queue/deque.rs +++ b/codes/rust/chapter_stack_and_queue/deque.rs @@ -4,7 +4,6 @@ * Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICEx@outlook.com) */ -use hello_algo_rust::include::print_util; use std::collections::VecDeque; /* Driver Code */ @@ -14,36 +13,32 @@ fn main() { deque.push_back(3); deque.push_back(2); deque.push_back(5); - print!("双向队列 deque = "); - print_util::print_queue(&deque); + println!("双向队列 deque = {deque:?} "); // 访问元素 let peek_first = deque.front().unwrap(); - print!("\n队首元素 peekFirst = {peek_first}"); + println!("队首元素 peek_first = {peek_first}"); let peek_last = deque.back().unwrap(); - print!("\n队尾元素 peekLast = {peek_last}"); + println!("队尾元素 peek_last = {peek_last}"); - /* 元素入队 */ + // 元素入队 deque.push_back(4); - print!("\n元素 4 队尾入队后 deque = "); - print_util::print_queue(&deque); + println!("元素 4 队尾入队后 deque = {deque:?}"); + println!("双向队列 deque = {deque:?}"); deque.push_front(1); - print!("\n元素 1 队首入队后 deque = "); - print_util::print_queue(&deque); + println!("元素 1 队首入队后 deque = {deque:?}"); // 元素出队 let pop_last = deque.pop_back().unwrap(); - print!("\n队尾出队元素 = {pop_last},队尾出队后 deque = "); - print_util::print_queue(&deque); + println!("队尾出队元素 = {pop_last},队尾出队后 deque = {deque:?}"); let pop_first = deque.pop_front().unwrap(); - print!("\n队首出队元素 = {pop_first},队首出队后 deque = "); - print_util::print_queue(&deque); + println!("队首出队元素 = {pop_first},队首出队后 deque = {deque:?}"); // 获取双向队列的长度 let size = deque.len(); - print!("\n双向队列长度 size = {size}"); + println!("双向队列长度 size = {size}"); // 判断双向队列是否为空 let is_empty = deque.is_empty(); - print!("\n双向队列是否为空 = {is_empty}"); + println!("双向队列是否为空 = {is_empty}"); } From 41a21cea2937775fd9579eca886c4b8eb3b56811 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:33:55 +0800 Subject: [PATCH 035/109] refactor: replace trait bound `Copy` with `Clone` and narrow its scope `Copy` should only be used for trait specialization, which is unrelated here and not stabilized. --- .../linkedlist_deque.rs | 139 ++++++++++-------- 1 file changed, 78 insertions(+), 61 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs index 5dd523baf3..fe6e668e2b 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs @@ -27,30 +27,29 @@ impl ListNode { } /* 基于双向链表实现的双向队列 */ -#[allow(dead_code)] pub struct LinkedListDeque { - front: Option>>>, // 头节点 front - rear: Option>>>, // 尾节点 rear - que_size: usize, // 双向队列的长度 + front: Option>>>, // 头节点 + rear: Option>>>, // 尾节点 + size: usize, // 双向队列的长度 } -impl LinkedListDeque { +impl LinkedListDeque { pub fn new() -> Self { Self { front: None, rear: None, - que_size: 0, + size: 0, } } /* 获取双向队列的长度 */ pub fn size(&self) -> usize { - return self.que_size; + return self.size; } /* 判断双向队列是否为空 */ pub fn is_empty(&self) -> bool { - return self.que_size == 0; + return self.size == 0; } /* 入队操作 */ @@ -68,7 +67,8 @@ impl LinkedListDeque { Some(old_front) => { old_front.borrow_mut().prev = Some(node.clone()); node.borrow_mut().next = Some(old_front); - self.front = Some(node); // 更新头节点 + // 更新头节点 + self.front = Some(node); } } } @@ -84,11 +84,13 @@ impl LinkedListDeque { Some(old_rear) => { old_rear.borrow_mut().next = Some(node.clone()); node.borrow_mut().prev = Some(old_rear); - self.rear = Some(node); // 更新尾节点 + // 更新尾节点 + self.rear = Some(node); } } } - self.que_size += 1; // 更新队列长度 + // 更新队列长度 + self.size += 1; } /* 队首入队 */ @@ -102,76 +104,91 @@ impl LinkedListDeque { } /* 出队操作 */ - fn pop(&mut self, is_front: bool) -> Option { + fn pop(&mut self, is_front: bool) -> Option + where + T: Clone, + { // 若队列为空,直接返回 None if self.is_empty() { return None; - }; + } // 队首出队操作 if is_front { - self.front.take().map(|old_front| { - match old_front.borrow_mut().next.take() { - Some(new_front) => { - new_front.borrow_mut().prev.take(); - self.front = Some(new_front); // 更新头节点 - } - None => { - self.rear.take(); - } + let old_front = self.front.take()?; + match old_front.borrow_mut().next.take() { + Some(new_front) => { + new_front.borrow_mut().prev = None; + // 更新头节点 + self.front = Some(new_front); } - self.que_size -= 1; // 更新队列长度 - old_front.borrow().val - }) + None => { + self.rear = None; + } + } + // 更新队列长度 + self.size -= 1; + let val = old_front.borrow().val.clone(); + Some(val) } // 队尾出队操作 else { - self.rear.take().map(|old_rear| { - match old_rear.borrow_mut().prev.take() { - Some(new_rear) => { - new_rear.borrow_mut().next.take(); - self.rear = Some(new_rear); // 更新尾节点 - } - None => { - self.front.take(); - } + let old_rear = self.rear.take()?; + match old_rear.borrow_mut().prev.take() { + Some(new_rear) => { + new_rear.borrow_mut().next = None; + // 更新尾节点 + self.rear = Some(new_rear); } - self.que_size -= 1; // 更新队列长度 - old_rear.borrow().val - }) + None => { + self.front = None; + } + } + // 更新队列长度 + self.size -= 1; + let val = old_rear.borrow().val.clone(); + Some(val) } } /* 队首出队 */ - pub fn pop_first(&mut self) -> Option { - return self.pop(true); + pub fn pop_first(&mut self) -> Option + where + T: Clone, + { + self.pop(true) } /* 队尾出队 */ - pub fn pop_last(&mut self) -> Option { - return self.pop(false); + pub fn pop_last(&mut self) -> Option + where + T: Clone, + { + self.pop(false) } /* 访问队首元素 */ - pub fn peek_first(&self) -> Option<&Rc>>> { - self.front.as_ref() + pub fn peek_first(&self) -> &Option>>> { + &self.front } /* 访问队尾元素 */ - pub fn peek_last(&self) -> Option<&Rc>>> { - self.rear.as_ref() + pub fn peek_last(&self) -> &Option>>> { + &self.rear } /* 返回数组用于打印 */ - pub fn to_array(&self, head: Option<&Rc>>>) -> Vec { - let mut res: Vec = Vec::new(); - fn recur(cur: Option<&Rc>>>, res: &mut Vec) { - if let Some(cur) = cur { - res.push(cur.borrow().val); - recur(cur.borrow().next.as_ref(), res); - } + pub fn to_array(&self) -> Vec + where + T: Clone, + { + let mut res = Vec::with_capacity(self.size); + let mut next = self.front.clone(); + while let Some(node) = next { + let borrow = node.borrow(); + let val = borrow.val.clone(); + res.push(val); + next = borrow.next.clone(); } - - recur(head, &mut res); res } } @@ -184,29 +201,29 @@ fn main() { deque.push_last(2); deque.push_last(5); print!("双向队列 deque = "); - print_util::print_array(&deque.to_array(deque.peek_first())); + print_util::print_array(&deque.to_array()); /* 访问元素 */ - let peek_first = deque.peek_first().unwrap().borrow().val; + let peek_first = deque.peek_first().as_ref().unwrap().borrow().val; print!("\n队首元素 peek_first = {}", peek_first); - let peek_last = deque.peek_last().unwrap().borrow().val; + let peek_last = deque.peek_last().as_ref().unwrap().borrow().val; print!("\n队尾元素 peek_last = {}", peek_last); /* 元素入队 */ deque.push_last(4); print!("\n元素 4 队尾入队后 deque = "); - print_util::print_array(&deque.to_array(deque.peek_first())); + print_util::print_array(&deque.to_array()); deque.push_first(1); print!("\n元素 1 队首入队后 deque = "); - print_util::print_array(&deque.to_array(deque.peek_first())); + print_util::print_array(&deque.to_array()); /* 元素出队 */ let pop_last = deque.pop_last().unwrap(); print!("\n队尾出队元素 = {},队尾出队后 deque = ", pop_last); - print_util::print_array(&deque.to_array(deque.peek_first())); + print_util::print_array(&deque.to_array()); let pop_first = deque.pop_first().unwrap(); print!("\n队首出队元素 = {},队首出队后 deque = ", pop_first); - print_util::print_array(&deque.to_array(deque.peek_first())); + print_util::print_array(&deque.to_array()); /* 获取双向队列的长度 */ let size = deque.size(); From 0ef71204e3224169354c7e1e375896afdccb6562 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:34:05 +0800 Subject: [PATCH 036/109] fix: resolve warnings Removed: - `clippy::needless_return` Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_stack_and_queue/linkedlist_deque.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs index fe6e668e2b..8dbf014cf5 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs @@ -34,6 +34,7 @@ pub struct LinkedListDeque { } impl LinkedListDeque { + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { front: None, @@ -44,12 +45,12 @@ impl LinkedListDeque { /* 获取双向队列的长度 */ pub fn size(&self) -> usize { - return self.size; + self.size } /* 判断双向队列是否为空 */ pub fn is_empty(&self) -> bool { - return self.size == 0; + self.size == 0 } /* 入队操作 */ From 92f52b36d5475f952494e596404c3e7d605d6c8b Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:34:18 +0800 Subject: [PATCH 037/109] refactor: rewrite formatted output logic --- .../linkedlist_deque.rs | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs index 8dbf014cf5..3634260ccf 100644 --- a/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs +++ b/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs @@ -4,9 +4,8 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; - use std::cell::RefCell; +use std::fmt; use std::rc::Rc; /* 双向链表节点 */ @@ -194,6 +193,26 @@ impl LinkedListDeque { } } +impl fmt::Display for LinkedListDeque +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Some(front) = &self.front else { + return write!(f, "[]"); + }; + let borrow = front.borrow(); + write!(f, "[{}", borrow.val)?; + let mut next = borrow.next.clone(); + while let Some(link) = next { + let borrow = link.borrow(); + write!(f, ", {}", borrow.val)?; + next = borrow.next.clone(); + } + write!(f, "]") + } +} + /* Driver Code */ fn main() { /* 初始化双向队列 */ @@ -201,36 +220,31 @@ fn main() { deque.push_last(3); deque.push_last(2); deque.push_last(5); - print!("双向队列 deque = "); - print_util::print_array(&deque.to_array()); + println!("双向队列 deque = {deque}"); /* 访问元素 */ let peek_first = deque.peek_first().as_ref().unwrap().borrow().val; - print!("\n队首元素 peek_first = {}", peek_first); + println!("队首元素 peek_first = {peek_first}"); let peek_last = deque.peek_last().as_ref().unwrap().borrow().val; - print!("\n队尾元素 peek_last = {}", peek_last); + println!("队尾元素 peek_last = {peek_last}"); /* 元素入队 */ deque.push_last(4); - print!("\n元素 4 队尾入队后 deque = "); - print_util::print_array(&deque.to_array()); + println!("元素 4 队尾入队后 deque = {deque}"); deque.push_first(1); - print!("\n元素 1 队首入队后 deque = "); - print_util::print_array(&deque.to_array()); + println!("元素 1 队首入队后 deque = {deque}"); /* 元素出队 */ let pop_last = deque.pop_last().unwrap(); - print!("\n队尾出队元素 = {},队尾出队后 deque = ", pop_last); - print_util::print_array(&deque.to_array()); + println!("队尾出队元素 = {pop_last},队尾出队后 deque = {deque}"); let pop_first = deque.pop_first().unwrap(); - print!("\n队首出队元素 = {},队首出队后 deque = ", pop_first); - print_util::print_array(&deque.to_array()); + println!("队首出队元素 = {pop_first},队首出队后 deque = {deque}"); /* 获取双向队列的长度 */ let size = deque.size(); - print!("\n双向队列长度 size = {}", size); + println!("双向队列长度 size = {size}"); /* 判断双向队列是否为空 */ let is_empty = deque.is_empty(); - print!("\n双向队列是否为空 = {}", is_empty); + println!("双向队列是否为空 = {is_empty}"); } From deda87cc26485f8cd59c447d54126263b3d9fb3e Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:34:31 +0800 Subject: [PATCH 038/109] refactor: rewrite for readability and consistency --- .../chapter_stack_and_queue/array_deque.rs | 117 ++++++++++-------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/array_deque.rs b/codes/rust/chapter_stack_and_queue/array_deque.rs index 09a68095de..835c10235e 100644 --- a/codes/rust/chapter_stack_and_queue/array_deque.rs +++ b/codes/rust/chapter_stack_and_queue/array_deque.rs @@ -6,18 +6,21 @@ use hello_algo_rust::include::print_util; /* 基于环形数组实现的双向队列 */ pub struct ArrayDeque { - nums: Vec, // 用于存储双向队列元素的数组 - front: usize, // 队首指针,指向队首元素 - que_size: usize, // 双向队列长度 + nums: Vec, // 用于存储双向队列元素的数组 + front: usize, // 队首指针,指向队首元素 + size: usize, // 双向队列长度 } -impl ArrayDeque { +impl ArrayDeque { /* 构造方法 */ - pub fn new(capacity: usize) -> Self { + pub fn new(capacity: usize) -> Self + where + T: Default, + { Self { - nums: vec![T::default(); capacity], + nums: (0..capacity).map(|_| T::default()).collect(), front: 0, - que_size: 0, + size: 0, } } @@ -28,91 +31,99 @@ impl ArrayDeque { /* 获取双向队列的长度 */ pub fn size(&self) -> usize { - self.que_size + self.size } /* 判断双向队列是否为空 */ pub fn is_empty(&self) -> bool { - self.que_size == 0 - } - - /* 计算环形数组索引 */ - fn index(&self, i: i32) -> usize { - // 通过取余操作实现数组首尾相连 - // 当 i 越过数组尾部后,回到头部 - // 当 i 越过数组头部后,回到尾部 - ((i + self.capacity() as i32) % self.capacity() as i32) as usize + self.size == 0 } /* 队首入队 */ pub fn push_first(&mut self, num: T) { - if self.que_size == self.capacity() { - println!("双向队列已满"); - return; + if self.size == self.capacity() { + panic!("双向队列已满"); } // 队首指针向左移动一位 // 通过取余操作实现 front 越过数组头部后回到尾部 - self.front = self.index(self.front as i32 - 1); + self.front = (self.capacity() + self.front - 1) % self.capacity(); // 将 num 添加至队首 self.nums[self.front] = num; - self.que_size += 1; + self.size += 1; } /* 队尾入队 */ pub fn push_last(&mut self, num: T) { - if self.que_size == self.capacity() { - println!("双向队列已满"); - return; + if self.size == self.capacity() { + panic!("双向队列已满"); } // 计算队尾指针,指向队尾索引 + 1 - let rear = self.index(self.front as i32 + self.que_size as i32); + let rear = (self.front + self.size) % self.capacity(); // 将 num 添加至队尾 self.nums[rear] = num; - self.que_size += 1; + self.size += 1; } /* 队首出队 */ - pub fn pop_first(&mut self) -> T { - let num = self.peek_first(); + pub fn pop_first(&mut self) -> Option + where + T: Clone, + { + if self.is_empty() { + return None; + }; + let num = self.nums[self.front].clone(); // 队首指针向后移动一位 - self.front = self.index(self.front as i32 + 1); - self.que_size -= 1; - num + self.front = (self.front + 1) % self.capacity(); + self.size -= 1; + Some(num) } /* 队尾出队 */ - pub fn pop_last(&mut self) -> T { - let num = self.peek_last(); - self.que_size -= 1; - num + pub fn pop_last(&mut self) -> Option + where + T: Clone, + { + if self.is_empty() { + return None; + }; + let last = (self.front + self.size - 1) % self.capacity(); + let num = self.nums[last].clone(); + self.size -= 1; + Some(num) } /* 访问队首元素 */ - pub fn peek_first(&self) -> T { + pub fn peek_first(&self) -> Option<&T> { if self.is_empty() { - panic!("双向队列为空") + return None; }; - self.nums[self.front] + Some(&self.nums[self.front]) } /* 访问队尾元素 */ - pub fn peek_last(&self) -> T { + pub fn peek_last(&self) -> Option<&T> { if self.is_empty() { - panic!("双向队列为空") + return None; }; // 计算尾元素索引 - let last = self.index(self.front as i32 + self.que_size as i32 - 1); - self.nums[last] + let last = (self.front + self.size - 1) % self.capacity(); + Some(&self.nums[last]) } /* 返回数组用于打印 */ - pub fn to_array(&self) -> Vec { + pub fn to_array(&self) -> Vec + where + T: Clone, + { // 仅转换有效长度范围内的列表元素 - let mut res = vec![T::default(); self.que_size]; - let mut j = self.front; - for i in 0..self.que_size { - res[i] = self.nums[self.index(j as i32)]; - j += 1; + let mut res = Vec::with_capacity(self.size); + for index in self.front..(self.front + self.size) { + // 考虑存在不变式 `self.size <= self.capacity()`, + // 且 `self.size == 0` 时不会进入该循环,除零错误不会发生。 + let index = index % self.capacity(); + let num = self.nums[index].clone(); + res.push(num); } res } @@ -129,9 +140,9 @@ fn main() { print_util::print_array(&deque.to_array()); /* 访问元素 */ - let peek_first = deque.peek_first(); + let peek_first = deque.peek_first().unwrap(); print!("\n队首元素 peek_first = {}", peek_first); - let peek_last = deque.peek_last(); + let peek_last = deque.peek_last().unwrap(); print!("\n队尾元素 peek_last = {}", peek_last); /* 元素入队 */ @@ -143,10 +154,10 @@ fn main() { print_util::print_array(&deque.to_array()); /* 元素出队 */ - let pop_last = deque.pop_last(); + let pop_last = deque.pop_last().unwrap(); print!("\n队尾出队元素 = {},队尾出队后 deque = ", pop_last); print_util::print_array(&deque.to_array()); - let pop_first = deque.pop_first(); + let pop_first = deque.pop_first().unwrap(); print!("\n队首出队元素 = {},队首出队后 deque = ", pop_first); print_util::print_array(&deque.to_array()); From a9fc04c04a3a3e43764dc98c219da864ab3a9c39 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:34:41 +0800 Subject: [PATCH 039/109] refactor: rewrite formatted output logic --- .../chapter_stack_and_queue/array_deque.rs | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/codes/rust/chapter_stack_and_queue/array_deque.rs b/codes/rust/chapter_stack_and_queue/array_deque.rs index 835c10235e..b9ec7eb392 100644 --- a/codes/rust/chapter_stack_and_queue/array_deque.rs +++ b/codes/rust/chapter_stack_and_queue/array_deque.rs @@ -3,7 +3,10 @@ * Created Time: 2023-03-11 * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; + +use hello_algo_rust::fmt::Write; +use std::fmt; + /* 基于环形数组实现的双向队列 */ pub struct ArrayDeque { nums: Vec, // 用于存储双向队列元素的数组 @@ -129,6 +132,17 @@ impl ArrayDeque { } } +impl fmt::Display for ArrayDeque +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = + (self.front..(self.front + self.size)).map(|index| &self.nums[index % self.capacity()]); + f.write_array(iter) + } +} + /* Driver Code */ fn main() { /* 初始化双向队列 */ @@ -136,36 +150,31 @@ fn main() { deque.push_last(3); deque.push_last(2); deque.push_last(5); - print!("双向队列 deque = "); - print_util::print_array(&deque.to_array()); + println!("双向队列 deque = {deque}"); /* 访问元素 */ let peek_first = deque.peek_first().unwrap(); - print!("\n队首元素 peek_first = {}", peek_first); + println!("队首元素 peek_first = {peek_first}"); let peek_last = deque.peek_last().unwrap(); - print!("\n队尾元素 peek_last = {}", peek_last); + println!("队尾元素 peek_last = {peek_last}"); /* 元素入队 */ deque.push_last(4); - print!("\n元素 4 队尾入队后 deque = "); - print_util::print_array(&deque.to_array()); + println!("元素 4 队尾入队后 deque = {deque}"); deque.push_first(1); - print!("\n元素 1 队首入队后 deque = "); - print_util::print_array(&deque.to_array()); + println!("元素 1 队首入队后 deque = {deque}"); /* 元素出队 */ let pop_last = deque.pop_last().unwrap(); - print!("\n队尾出队元素 = {},队尾出队后 deque = ", pop_last); - print_util::print_array(&deque.to_array()); + println!("队尾出队元素 = {pop_last},队尾出队后 deque = {deque}"); let pop_first = deque.pop_first().unwrap(); - print!("\n队首出队元素 = {},队首出队后 deque = ", pop_first); - print_util::print_array(&deque.to_array()); + println!("队首出队元素 = {pop_first},队首出队后 deque = {deque}"); /* 获取双向队列的长度 */ let size = deque.size(); - print!("\n双向队列长度 size = {}", size); + println!("双向队列长度 size = {size}"); /* 判断双向队列是否为空 */ let is_empty = deque.is_empty(); - print!("\n双向队列是否为空 = {}", is_empty); + println!("双向队列是否为空 = {is_empty}"); } From 96c860498e839785af9efe8f7f589c33dc67e38c Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:34:51 +0800 Subject: [PATCH 040/109] refactor: decouple binary crates --- codes/rust/chapter_hashing/hash_map_open_addressing.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/codes/rust/chapter_hashing/hash_map_open_addressing.rs b/codes/rust/chapter_hashing/hash_map_open_addressing.rs index 6c5f607e68..1377ba5e37 100644 --- a/codes/rust/chapter_hashing/hash_map_open_addressing.rs +++ b/codes/rust/chapter_hashing/hash_map_open_addressing.rs @@ -6,9 +6,11 @@ #![allow(non_snake_case)] #![allow(unused)] -mod array_hash_map; - -use array_hash_map::Pair; +#[derive(Clone, PartialEq)] +pub struct Pair { + pub key: i32, + pub val: String, +} /* 开放寻址哈希表 */ pub struct HashMapOpenAddressing { From 7d57c938aba37d49f2a7e00eb8eb8ef8cec1a5dc Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:34:57 +0800 Subject: [PATCH 041/109] fix: resolve warning Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_hashing/array_hash_map.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/codes/rust/chapter_hashing/array_hash_map.rs b/codes/rust/chapter_hashing/array_hash_map.rs index c142041c8a..53c5e8322d 100644 --- a/codes/rust/chapter_hashing/array_hash_map.rs +++ b/codes/rust/chapter_hashing/array_hash_map.rs @@ -16,6 +16,7 @@ pub struct ArrayHashMap { } impl ArrayHashMap { + #[allow(clippy::new_without_default)] pub fn new() -> ArrayHashMap { // 初始化数组,包含 100 个桶 Self { From 1be0d25df2e444bb8e6e4e091d0f9606fe414358 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:38:29 +0800 Subject: [PATCH 042/109] refactor: change method signatures to follow best practices --- codes/rust/chapter_hashing/array_hash_map.rs | 60 +++++++++++--------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/codes/rust/chapter_hashing/array_hash_map.rs b/codes/rust/chapter_hashing/array_hash_map.rs index 53c5e8322d..0c243a4ef4 100644 --- a/codes/rust/chapter_hashing/array_hash_map.rs +++ b/codes/rust/chapter_hashing/array_hash_map.rs @@ -1,15 +1,16 @@ -/* +/** * File: array_hash_map.rs * Created Time: 2023-2-18 * Author: xBLACICEx (xBLACKICEx@outlook.com) */ /* 键值对 */ -#[derive(Debug, Clone, PartialEq)] +#[derive(Clone)] pub struct Pair { pub key: i32, pub val: String, } + /* 基于数组实现的哈希表 */ pub struct ArrayHashMap { buckets: Vec>, @@ -17,7 +18,7 @@ pub struct ArrayHashMap { impl ArrayHashMap { #[allow(clippy::new_without_default)] - pub fn new() -> ArrayHashMap { + pub fn new() -> Self { // 初始化数组,包含 100 个桶 Self { buckets: vec![None; 100], @@ -30,18 +31,15 @@ impl ArrayHashMap { } /* 查询操作 */ - pub fn get(&self, key: i32) -> Option<&String> { + pub fn get(&self, key: i32) -> Option<&str> { let index = self.hash_func(key); - self.buckets[index].as_ref().map(|pair| &pair.val) + self.buckets[index].as_ref().map(|pair| &pair.val[..]) } /* 添加操作 */ - pub fn put(&mut self, key: i32, val: &str) { + pub fn put(&mut self, key: i32, val: String) { let index = self.hash_func(key); - self.buckets[index] = Some(Pair { - key, - val: val.to_string(), - }); + self.buckets[index] = Some(Pair { key, val }); } /* 删除操作 */ @@ -68,10 +66,10 @@ impl ArrayHashMap { } /* 获取所有值 */ - pub fn value_set(&self) -> Vec<&String> { + pub fn value_set(&self) -> Vec<&str> { self.buckets .iter() - .filter_map(|pair| pair.as_ref().map(|pair| &pair.val)) + .filter_map(|pair| pair.as_ref().map(|pair| &pair.val[..])) .collect() } @@ -88,38 +86,48 @@ fn main() { let mut map = ArrayHashMap::new(); /*添加操作 */ // 在哈希表中添加键值对(key, value) - map.put(12836, "小哈"); - map.put(15937, "小啰"); - map.put(16750, "小算"); - map.put(13276, "小法"); - map.put(10583, "小鸭"); - println!("\n添加完成后,哈希表为\nKey -> Value"); + map.put(12836, "小哈".to_string()); + map.put(15937, "小啰".to_string()); + map.put(16750, "小算".to_string()); + map.put(13276, "小法".to_string()); + map.put(10583, "小鸭".to_string()); + println!("添加完成后,哈希表为\nKey -> Value"); map.print(); + println!(); + /* 查询操作 */ - // 向哈希表中输入键 key ,得到值 value + // 向哈希表中输入键 key,得到值 value let name = map.get(15937).unwrap(); - println!("\n输入学号 15937 ,查询到姓名 {}", name); + println!("输入学号 15937 ,查询到姓名 {name}"); + + println!(); /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.remove(10583); - println!("\n删除 10583 后,哈希表为\nKey -> Value"); + println!("删除 10583 后,哈希表为\nKey -> Value"); map.print(); + println!(); + /* 遍历哈希表 */ - println!("\n遍历键值对 Key->Value"); + println!("遍历键值对 Key -> Value"); for pair in map.entry_set() { println!("{} -> {}", pair.key, pair.val); } - println!("\n单独遍历键 Key"); + println!(); + + println!("单独遍历键 Key"); for key in map.key_set() { - println!("{}", key); + println!("{key}"); } - println!("\n单独遍历值 Value"); + println!(); + + println!("单独遍历值 Value"); for val in map.value_set() { - println!("{}", val); + println!("{val}"); } } From 05e6928f8c47b1b1fe77828bad2ca9ebacb05d75 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:39:50 +0800 Subject: [PATCH 043/109] fix: resolve warning Explicitly omitted: - `clippy::approx_constant` --- codes/rust/chapter_hashing/build_in_hash.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/codes/rust/chapter_hashing/build_in_hash.rs b/codes/rust/chapter_hashing/build_in_hash.rs index 456f9791a4..5cb90085cd 100644 --- a/codes/rust/chapter_hashing/build_in_hash.rs +++ b/codes/rust/chapter_hashing/build_in_hash.rs @@ -4,46 +4,46 @@ * Author: WSL0809 (wslzzy@outlook.com) */ -use hello_algo_rust::include::ListNode; - +use hello_algo_rust::linked_list::ListNode; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; /* Driver Code */ +#[allow(clippy::approx_constant)] fn main() { let num = 3; let mut num_hasher = DefaultHasher::new(); num.hash(&mut num_hasher); let hash_num = num_hasher.finish(); - println!("整数 {} 的哈希值为 {}", num, hash_num); + println!("整数 {num} 的哈希值为 {hash_num}"); let bol = true; let mut bol_hasher = DefaultHasher::new(); bol.hash(&mut bol_hasher); let hash_bol = bol_hasher.finish(); - println!("布尔量 {} 的哈希值为 {}", bol, hash_bol); + println!("布尔量 {bol} 的哈希值为 {hash_bol}"); let dec: f32 = 3.14159; let mut dec_hasher = DefaultHasher::new(); dec.to_bits().hash(&mut dec_hasher); let hash_dec = dec_hasher.finish(); - println!("小数 {} 的哈希值为 {}", dec, hash_dec); + println!("小数 {dec} 的哈希值为 {hash_dec}"); let str = "Hello 算法"; let mut str_hasher = DefaultHasher::new(); str.hash(&mut str_hasher); let hash_str = str_hasher.finish(); - println!("字符串 {} 的哈希值为 {}", str, hash_str); + println!("字符串 {str} 的哈希值为 {hash_str}"); let arr = (&12836, &"小哈"); let mut tup_hasher = DefaultHasher::new(); arr.hash(&mut tup_hasher); let hash_tup = tup_hasher.finish(); - println!("元组 {:?} 的哈希值为 {}", arr, hash_tup); + println!("元组 {arr:?} 的哈希值为 {hash_tup}"); let node = ListNode::new(42); let mut hasher = DefaultHasher::new(); node.borrow().val.hash(&mut hasher); let hash = hasher.finish(); - println!("节点对象 {:?} 的哈希值为{}", node, hash); + println!("节点对象 {node:?} 的哈希值为 {hash}"); } From 12570683c2ad8e68a4622dcb073ca5324c6f5457 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:43:09 +0800 Subject: [PATCH 044/109] refactor: reorder methods --- .../rust/chapter_hashing/hash_map_chaining.rs | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/codes/rust/chapter_hashing/hash_map_chaining.rs b/codes/rust/chapter_hashing/hash_map_chaining.rs index a4b901fe01..a334b18313 100644 --- a/codes/rust/chapter_hashing/hash_map_chaining.rs +++ b/codes/rust/chapter_hashing/hash_map_chaining.rs @@ -42,6 +42,44 @@ impl HashMapChaining { self.size as f32 / self.capacity as f32 } + /* 查询操作 */ + pub fn get(&self, key: i32) -> Option<&str> { + let index = self.hash_func(key); + + // 遍历桶,若找到 key ,则返回对应 val + for pair in self.buckets[index].iter() { + if pair.key == key { + return Some(&pair.val); + } + } + + // 若未找到 key ,则返回 None + None + } + + /* 添加操作 */ + pub fn put(&mut self, key: i32, val: String) { + // 当负载因子超过阈值时,执行扩容 + if self.load_factor() > self.load_thres { + self.extend(); + } + + let index = self.hash_func(key); + + // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 + for pair in self.buckets[index].iter_mut() { + if pair.key == key { + pair.val = val; + return; + } + } + + // 若无该 key ,则将键值对添加至尾部 + let pair = Pair { key, val }; + self.buckets[index].push(pair); + self.size += 1; + } + /* 删除操作 */ pub fn remove(&mut self, key: i32) -> Option { let index = self.hash_func(key); @@ -66,7 +104,7 @@ impl HashMapChaining { // 初始化扩容后的新哈希表 self.capacity *= self.extend_ratio; - self.buckets = vec![Vec::new(); self.capacity as usize]; + self.buckets = vec![Vec::new(); self.capacity]; self.size = 0; // 将键值对从原哈希表搬运至新哈希表 @@ -87,44 +125,6 @@ impl HashMapChaining { println!("{:?}", res); } } - - /* 添加操作 */ - pub fn put(&mut self, key: i32, val: String) { - // 当负载因子超过阈值时,执行扩容 - if self.load_factor() > self.load_thres { - self.extend(); - } - - let index = self.hash_func(key); - - // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 - for pair in self.buckets[index].iter_mut() { - if pair.key == key { - pair.val = val; - return; - } - } - - // 若无该 key ,则将键值对添加至尾部 - let pair = Pair { key, val }; - self.buckets[index].push(pair); - self.size += 1; - } - - /* 查询操作 */ - pub fn get(&self, key: i32) -> Option<&str> { - let index = self.hash_func(key); - - // 遍历桶,若找到 key ,则返回对应 val - for pair in self.buckets[index].iter() { - if pair.key == key { - return Some(&pair.val); - } - } - - // 若未找到 key ,则返回 None - None - } } /* Driver Code */ From 41e9a4461dc4eea56eb1be001728784a97269422 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:45:21 +0800 Subject: [PATCH 045/109] fix: resolve warnings Removed: - `clippy::manual_unwrap_or` Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_hashing/hash_map_chaining.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/codes/rust/chapter_hashing/hash_map_chaining.rs b/codes/rust/chapter_hashing/hash_map_chaining.rs index a334b18313..fd31f5ccf2 100644 --- a/codes/rust/chapter_hashing/hash_map_chaining.rs +++ b/codes/rust/chapter_hashing/hash_map_chaining.rs @@ -22,6 +22,7 @@ pub struct HashMapChaining { impl HashMapChaining { /* 构造方法 */ + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { size: 0, @@ -145,11 +146,8 @@ fn main() { /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value println!( - "\n输入学号 13276,查询到姓名 {}", - match map.get(13276) { - Some(value) => value, - None => "Not a valid Key", - } + "\n输入学号 13276,查询到姓名 {}", + map.get(13276).unwrap_or("Not a valid Key") ); /* 删除操作 */ From ea0e0cf4b97b0290e8c92f49c1ce9135ce0ba433 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:51:09 +0800 Subject: [PATCH 046/109] refactor: replace fields `load_thres` and `extend_ratio` with associated constants `LOAD_THRES` and `EXTEND_RATIO` respectively --- .../rust/chapter_hashing/hash_map_chaining.rs | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/codes/rust/chapter_hashing/hash_map_chaining.rs b/codes/rust/chapter_hashing/hash_map_chaining.rs index fd31f5ccf2..58f51e1e1b 100644 --- a/codes/rust/chapter_hashing/hash_map_chaining.rs +++ b/codes/rust/chapter_hashing/hash_map_chaining.rs @@ -4,8 +4,10 @@ * Author: WSL0809 (wslzzy@outlook.com) */ -#[derive(Clone)] +use std::mem; + /* 键值对 */ +#[derive(Clone)] pub struct Pair { pub key: i32, pub val: String, @@ -15,20 +17,19 @@ pub struct Pair { pub struct HashMapChaining { size: usize, capacity: usize, - load_thres: f32, - extend_ratio: usize, buckets: Vec>, } impl HashMapChaining { + const LOAD_THRES: f64 = 2.0 / 3.0; + const EXTEND_RATIO: usize = 2; + /* 构造方法 */ #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { size: 0, capacity: 4, - load_thres: 2.0 / 3.0, - extend_ratio: 2, buckets: vec![vec![]; 4], } } @@ -39,29 +40,29 @@ impl HashMapChaining { } /* 负载因子 */ - fn load_factor(&self) -> f32 { - self.size as f32 / self.capacity as f32 + fn load_factor(&self) -> f64 { + self.size as f64 / self.capacity as f64 } /* 查询操作 */ pub fn get(&self, key: i32) -> Option<&str> { let index = self.hash_func(key); - // 遍历桶,若找到 key ,则返回对应 val + // 遍历桶,若找到 key,则返回对应 val for pair in self.buckets[index].iter() { if pair.key == key { return Some(&pair.val); } } - // 若未找到 key ,则返回 None + // 若未找到 key,则返回 None None } /* 添加操作 */ pub fn put(&mut self, key: i32, val: String) { // 当负载因子超过阈值时,执行扩容 - if self.load_factor() > self.load_thres { + if self.load_factor() > Self::LOAD_THRES { self.extend(); } @@ -86,8 +87,8 @@ impl HashMapChaining { let index = self.hash_func(key); // 遍历桶,从中删除键值对 - for (i, p) in self.buckets[index].iter_mut().enumerate() { - if p.key == key { + for (i, pair) in self.buckets[index].iter_mut().enumerate() { + if pair.key == key { let pair = self.buckets[index].remove(i); self.size -= 1; return Some(pair.val); @@ -101,15 +102,15 @@ impl HashMapChaining { /* 扩容哈希表 */ fn extend(&mut self) { // 暂存原哈希表 - let buckets_tmp = std::mem::take(&mut self.buckets); + let buckets = mem::take(&mut self.buckets); // 初始化扩容后的新哈希表 - self.capacity *= self.extend_ratio; + self.capacity *= Self::EXTEND_RATIO; self.buckets = vec![Vec::new(); self.capacity]; self.size = 0; // 将键值对从原哈希表搬运至新哈希表 - for bucket in buckets_tmp { + for bucket in buckets { for pair in bucket { self.put(pair.key, pair.val); } @@ -119,11 +120,12 @@ impl HashMapChaining { /* 打印哈希表 */ pub fn print(&self) { for bucket in &self.buckets { - let mut res = Vec::new(); + let capacity = bucket.len(); + let mut res = Vec::with_capacity(capacity); for pair in bucket { res.push(format!("{} -> {}", pair.key, pair.val)); } - println!("{:?}", res); + println!("{res:?}"); } } } @@ -140,19 +142,23 @@ fn main() { map.put(16750, "小算".to_string()); map.put(13276, "小法".to_string()); map.put(10583, "小鸭".to_string()); - println!("\n添加完成后,哈希表为\nKey -> Value"); + println!("添加完成后,哈希表为\nKey -> Value"); map.print(); + println!(); + /* 查询操作 */ - // 向哈希表中输入键 key ,得到值 value + // 向哈希表中输入键 key,得到值 value println!( - "\n输入学号 13276,查询到姓名 {}", + "输入学号 13276,查询到姓名 {}", map.get(13276).unwrap_or("Not a valid Key") ); + println!(); + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.remove(12836); - println!("\n删除 12836 后,哈希表为\nKey -> Value"); + println!("删除 12836 后,哈希表为\nKey -> Value"); map.print(); } From ae5855e3a12b25aec734af608c49d07e0a01fc80 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:57:46 +0800 Subject: [PATCH 047/109] refactor: reimplement `HashMapOpenAddressing` with enum `Bucket` --- .../hash_map_open_addressing.rs | 122 +++++++++--------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/codes/rust/chapter_hashing/hash_map_open_addressing.rs b/codes/rust/chapter_hashing/hash_map_open_addressing.rs index 1377ba5e37..459dbe7502 100644 --- a/codes/rust/chapter_hashing/hash_map_open_addressing.rs +++ b/codes/rust/chapter_hashing/hash_map_open_addressing.rs @@ -3,8 +3,17 @@ * Created Time: 2023-07-16 * Author: WSL0809 (wslzzy@outlook.com), night-cruise (2586447362@qq.com) */ -#![allow(non_snake_case)] -#![allow(unused)] + +use std::mem; + +/* 开放寻址哈希表 */ +pub struct HashMapOpenAddressing { + size: usize, // 键值对数量 + capacity: usize, // 哈希表容量 + load_thres: f64, // 触发扩容的负载因子阈值 + extend_ratio: usize, // 扩容倍数 + buckets: Vec, // 桶数组 +} #[derive(Clone, PartialEq)] pub struct Pair { @@ -12,14 +21,11 @@ pub struct Pair { pub val: String, } -/* 开放寻址哈希表 */ -pub struct HashMapOpenAddressing { - size: usize, // 键值对数量 - capacity: usize, // 哈希表容量 - load_thres: f64, // 触发扩容的负载因子阈值 - extend_ratio: usize, // 扩容倍数 - buckets: Vec>, // 桶数组 - TOMBSTONE: Option, // 删除标记 +#[derive(Clone, PartialEq)] +enum Bucket { + Empty, // 空桶 + Tombstone, // 删除标记 + Occupied(Pair), // 占用 } impl HashMapOpenAddressing { @@ -30,17 +36,13 @@ impl HashMapOpenAddressing { capacity: 4, load_thres: 2.0 / 3.0, extend_ratio: 2, - buckets: vec![None; 4], - TOMBSTONE: Some(Pair { - key: -1, - val: "-1".to_string(), - }), + buckets: vec![Bucket::Empty; 4], } } /* 哈希函数 */ fn hash_func(&self, key: i32) -> usize { - (key % self.capacity as i32) as usize + key as usize % self.capacity } /* 负载因子 */ @@ -51,32 +53,30 @@ impl HashMapOpenAddressing { /* 搜索 key 对应的桶索引 */ fn find_bucket(&mut self, key: i32) -> usize { let mut index = self.hash_func(key); - let mut first_tombstone = -1; + let mut first_tombstone = None; // 线性探测,当遇到空桶时跳出 - while self.buckets[index].is_some() { + while self.buckets[index] != Bucket::Empty { // 若遇到 key,返回对应的桶索引 - if self.buckets[index].as_ref().unwrap().key == key { - // 若之前遇到了删除标记,则将建值对移动至该索引 - if first_tombstone != -1 { - self.buckets[first_tombstone as usize] = self.buckets[index].take(); - self.buckets[index] = self.TOMBSTONE.clone(); - return first_tombstone as usize; // 返回移动后的桶索引 + if let Bucket::Occupied(pair) = &self.buckets[index] + && pair.key == key + { + // 若之前遇到了删除标记,则将键值对移动至该索引 + if let Some(first_tombstone) = first_tombstone { + let bucket = mem::replace(&mut self.buckets[index], Bucket::Tombstone); + self.buckets[first_tombstone] = bucket; + return first_tombstone; // 返回移动后的桶索引 } return index; // 返回桶索引 } // 记录遇到的首个删除标记 - if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE { - first_tombstone = index as i32; + if first_tombstone.is_none() && self.buckets[index] == Bucket::Tombstone { + first_tombstone = Some(index); } // 计算桶索引,越过尾部则返回头部 index = (index + 1) % self.capacity; } // 若 key 不存在,则返回添加点的索引 - if first_tombstone == -1 { - index - } else { - first_tombstone as usize - } + first_tombstone.unwrap_or(index) } /* 查询操作 */ @@ -84,8 +84,8 @@ impl HashMapOpenAddressing { // 搜索 key 对应的桶索引 let index = self.find_bucket(key); // 若找到键值对,则返回对应 val - if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE { - return self.buckets[index].as_ref().map(|pair| &pair.val as &str); + if let Bucket::Occupied(pair) = &self.buckets[index] { + return Some(&pair.val); } // 若键值对不存在,则返回 null None @@ -100,12 +100,13 @@ impl HashMapOpenAddressing { // 搜索 key 对应的桶索引 let index = self.find_bucket(key); // 若找到键值对,则覆盖 val 并返回 - if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE { - self.buckets[index].as_mut().unwrap().val = val; + if let Bucket::Occupied(pair) = &mut self.buckets[index] { + pair.val = val; return; } // 若键值对不存在,则添加该键值对 - self.buckets[index] = Some(Pair { key, val }); + let pair = Pair { key, val }; + self.buckets[index] = Bucket::Occupied(pair); self.size += 1; } @@ -114,8 +115,8 @@ impl HashMapOpenAddressing { // 搜索 key 对应的桶索引 let index = self.find_bucket(key); // 若找到键值对,则用删除标记覆盖它 - if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE { - self.buckets[index] = self.TOMBSTONE.clone(); + if let Bucket::Occupied(_) = &mut self.buckets[index] { + self.buckets[index] = Bucket::Tombstone; self.size -= 1; } } @@ -123,32 +124,33 @@ impl HashMapOpenAddressing { /* 扩容哈希表 */ fn extend(&mut self) { // 暂存原哈希表 - let buckets_tmp = self.buckets.clone(); + let buckets = self.buckets.clone(); // 初始化扩容后的新哈希表 self.capacity *= self.extend_ratio; - self.buckets = vec![None; self.capacity]; + self.buckets = vec![Bucket::Empty; self.capacity]; self.size = 0; // 将键值对从原哈希表搬运至新哈希表 - for pair in buckets_tmp { - if pair.is_none() || pair == self.TOMBSTONE { - continue; + for bucket in buckets { + if let Bucket::Occupied(pair) = bucket { + self.put(pair.key, pair.val); } - let pair = pair.unwrap(); - - self.put(pair.key, pair.val); } } + /* 打印哈希表 */ pub fn print(&self) { - for pair in &self.buckets { - if pair.is_none() { - println!("null"); - } else if pair == &self.TOMBSTONE { - println!("TOMBSTONE"); - } else { - let pair = pair.as_ref().unwrap(); - println!("{} -> {}", pair.key, pair.val); + for bucket in &self.buckets { + match bucket { + Bucket::Empty => { + println!("Empty"); + } + Bucket::Tombstone => { + println!("Tombstone"); + } + Bucket::Occupied(pair) => { + println!("{} -> {}", pair.key, pair.val); + } } } } @@ -167,17 +169,21 @@ fn main() { hashmap.put(13276, "小法".to_string()); hashmap.put(10583, "小鸭".to_string()); - println!("\n添加完成后,哈希表为\nKey -> Value"); + println!("添加完成后,哈希表为\nKey -> Value"); hashmap.print(); + println!(); + /* 查询操作 */ - // 向哈希表中输入键 key ,得到值 val + // 向哈希表中输入键 key,得到值 val let name = hashmap.get(13276).unwrap(); - println!("\n输入学号 13276 ,查询到姓名 {}", name); + println!("输入学号 13276 ,查询到姓名 {name}"); + + println!(); /* 删除操作 */ // 在哈希表中删除键值对 (key, val) hashmap.remove(16750); - println!("\n删除 16750 后,哈希表为\nKey -> Value"); + println!("删除 16750 后,哈希表为\nKey -> Value"); hashmap.print(); } From 4b2559f5a0acda1ccbc6c32dda2ec4d50f81c179 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:58:01 +0800 Subject: [PATCH 048/109] refactor: replace fields `load_thres` and `extend_ratio` with associated constants `LOAD_THRES` and `EXTEND_RATIO` respectively --- .../rust/chapter_hashing/hash_map_open_addressing.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/codes/rust/chapter_hashing/hash_map_open_addressing.rs b/codes/rust/chapter_hashing/hash_map_open_addressing.rs index 459dbe7502..31e7f7c9a8 100644 --- a/codes/rust/chapter_hashing/hash_map_open_addressing.rs +++ b/codes/rust/chapter_hashing/hash_map_open_addressing.rs @@ -10,8 +10,6 @@ use std::mem; pub struct HashMapOpenAddressing { size: usize, // 键值对数量 capacity: usize, // 哈希表容量 - load_thres: f64, // 触发扩容的负载因子阈值 - extend_ratio: usize, // 扩容倍数 buckets: Vec, // 桶数组 } @@ -29,13 +27,14 @@ enum Bucket { } impl HashMapOpenAddressing { + const LOAD_THRES: f64 = 2.0 / 3.0; // 触发扩容的负载因子阈值 + const EXTEND_RATIO: usize = 2; // 扩容倍数 + /* 构造方法 */ pub fn new() -> Self { Self { size: 0, capacity: 4, - load_thres: 2.0 / 3.0, - extend_ratio: 2, buckets: vec![Bucket::Empty; 4], } } @@ -94,7 +93,7 @@ impl HashMapOpenAddressing { /* 添加操作 */ pub fn put(&mut self, key: i32, val: String) { // 当负载因子超过阈值时,执行扩容 - if self.load_factor() > self.load_thres { + if self.load_factor() > Self::LOAD_THRES { self.extend(); } // 搜索 key 对应的桶索引 @@ -126,7 +125,7 @@ impl HashMapOpenAddressing { // 暂存原哈希表 let buckets = self.buckets.clone(); // 初始化扩容后的新哈希表 - self.capacity *= self.extend_ratio; + self.capacity *= Self::EXTEND_RATIO; self.buckets = vec![Bucket::Empty; self.capacity]; self.size = 0; From 52e41ca1e110b04a5e0d670e9cb6478d20e17e45 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 22:58:22 +0800 Subject: [PATCH 049/109] fix: resolve warning Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_hashing/hash_map_open_addressing.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/codes/rust/chapter_hashing/hash_map_open_addressing.rs b/codes/rust/chapter_hashing/hash_map_open_addressing.rs index 31e7f7c9a8..8ad6f41150 100644 --- a/codes/rust/chapter_hashing/hash_map_open_addressing.rs +++ b/codes/rust/chapter_hashing/hash_map_open_addressing.rs @@ -31,6 +31,7 @@ impl HashMapOpenAddressing { const EXTEND_RATIO: usize = 2; // 扩容倍数 /* 构造方法 */ + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { size: 0, From 81925ae2f95926bdbddeb0a940a3a9e03d464c1f Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:00:31 +0800 Subject: [PATCH 050/109] refactor: simplify formatted output logic --- codes/rust/chapter_hashing/hash_map.rs | 42 ++++++++++++++++++-------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/codes/rust/chapter_hashing/hash_map.rs b/codes/rust/chapter_hashing/hash_map.rs index 81375a891d..cb3452754f 100644 --- a/codes/rust/chapter_hashing/hash_map.rs +++ b/codes/rust/chapter_hashing/hash_map.rs @@ -4,8 +4,6 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; - use std::collections::HashMap; /* Driver Code */ @@ -20,28 +18,46 @@ fn main() { map.insert(16750, "小算"); map.insert(13276, "小法"); map.insert(10583, "小鸭"); - println!("\n添加完成后,哈希表为\nKey -> Value"); - print_util::print_hash_map(&map); + println!("添加完成后,哈希表为\nKey -> Value"); + for (key, value) in &map { + println!("{key} -> {value}"); + } + + println!(); // 查询操作 - // 向哈希表中输入键 key ,得到值 value + // 向哈希表中输入键 key,得到值 value let name = map.get(&15937).copied().unwrap(); - println!("\n输入学号 15937 ,查询到姓名 {name}"); + println!("输入学号 15937 ,查询到姓名 {name}"); + + println!(); // 删除操作 // 在哈希表中删除键值对 (key, value) - _ = map.remove(&10583); - println!("\n删除 10583 后,哈希表为\nKey -> Value"); - print_util::print_hash_map(&map); + map.remove(&10583); + println!("删除 10583 后,哈希表为\nKey -> Value"); + for (key, value) in &map { + println!("{key} -> {value}"); + } + + println!(); // 遍历哈希表 - println!("\n遍历键值对 Key->Value"); - print_util::print_hash_map(&map); - println!("\n单独遍历键 Key"); + println!("遍历键值对 Key -> Value"); + for (key, value) in &map { + println!("{key} -> {value}"); + } + + println!(); + + println!("单独遍历键 Key"); for key in map.keys() { println!("{key}"); } - println!("\n单独遍历值 value"); + + println!(); + + println!("单独遍历值 Value"); for value in map.values() { println!("{value}"); } From ba1825843ab878bc100d502491769b6f4320289b Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:01:06 +0800 Subject: [PATCH 051/109] refactor: improve readability --- codes/rust/chapter_hashing/simple_hash.rs | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/codes/rust/chapter_hashing/simple_hash.rs b/codes/rust/chapter_hashing/simple_hash.rs index 0c78ea79da..581cbf8884 100644 --- a/codes/rust/chapter_hashing/simple_hash.rs +++ b/codes/rust/chapter_hashing/simple_hash.rs @@ -6,11 +6,11 @@ /* 加法哈希 */ pub fn add_hash(key: &str) -> i32 { - let mut hash = 0_i64; const MODULUS: i64 = 1000000007; - for c in key.chars() { - hash = (hash + c as i64) % MODULUS; + let mut hash: i64 = 0; + for char in key.chars() { + hash = (hash + char as i64) % MODULUS; } hash as i32 @@ -18,11 +18,11 @@ pub fn add_hash(key: &str) -> i32 { /* 乘法哈希 */ pub fn mul_hash(key: &str) -> i32 { - let mut hash = 0_i64; const MODULUS: i64 = 1000000007; - for c in key.chars() { - hash = (31 * hash + c as i64) % MODULUS; + let mut hash: i64 = 0; + for char in key.chars() { + hash = (31 * hash + char as i64) % MODULUS; } hash as i32 @@ -30,11 +30,11 @@ pub fn mul_hash(key: &str) -> i32 { /* 异或哈希 */ pub fn xor_hash(key: &str) -> i32 { - let mut hash = 0_i64; const MODULUS: i64 = 1000000007; - for c in key.chars() { - hash ^= c as i64; + let mut hash: i64 = 0; + for char in key.chars() { + hash ^= char as i64; } (hash & MODULUS) as i32 @@ -42,11 +42,11 @@ pub fn xor_hash(key: &str) -> i32 { /* 旋转哈希 */ pub fn rot_hash(key: &str) -> i32 { - let mut hash = 0_i64; const MODULUS: i64 = 1000000007; - for c in key.chars() { - hash = ((hash << 4) ^ (hash >> 28) ^ c as i64) % MODULUS; + let mut hash: i64 = 0; + for char in key.chars() { + hash = ((hash << 4) ^ (hash >> 28) ^ char as i64) % MODULUS; } hash as i32 From abe3aa511167cd9a40d855b4c2decc5d1c232bd1 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:04:14 +0800 Subject: [PATCH 052/109] refactor: replace `hello_algo_rust::include::tree_node::TreeNode` with `hello_algo_rust::binary_tree::TreeNode` --- codes/rust/chapter_tree/binary_tree.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/codes/rust/chapter_tree/binary_tree.rs b/codes/rust/chapter_tree/binary_tree.rs index 277de0ec89..cb0a18ef66 100644 --- a/codes/rust/chapter_tree/binary_tree.rs +++ b/codes/rust/chapter_tree/binary_tree.rs @@ -4,8 +4,8 @@ * Author: xBLACKICEx (xBLACKICE@outlook.com) */ +use hello_algo_rust::binary_tree::{BinaryTree, TreeNode}; use std::rc::Rc; -use hello_algo_rust::include::{print_util, TreeNode}; /* Driver Code */ fn main() { @@ -21,19 +21,15 @@ fn main() { n1.borrow_mut().right = Some(Rc::clone(&n3)); n2.borrow_mut().left = Some(Rc::clone(&n4)); n2.borrow_mut().right = Some(Rc::clone(&n5)); - println!("\n初始化二叉树\n"); - print_util::print_tree(&n1); + println!("初始化二叉树\n{}", n1.display()); // 插入节点与删除节点 let p = TreeNode::new(0); // 在 n1 -> n2 中间插入节点 P p.borrow_mut().left = Some(Rc::clone(&n2)); n1.borrow_mut().left = Some(Rc::clone(&p)); - println!("\n插入节点 P 后\n"); - print_util::print_tree(&n1); + println!("插入节点 P 后\n{}", n1.display()); // 删除节点 P - drop(p); n1.borrow_mut().left = Some(Rc::clone(&n2)); - println!("\n删除节点 P 后\n"); - print_util::print_tree(&n1); + println!("删除节点 P 后\n{}", n1.display()); } From f1beb5878b4a639ce91888532832df0ebe7c7364 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:07:27 +0800 Subject: [PATCH 053/109] refactor: unify `root` types for consistency --- codes/rust/chapter_tree/binary_tree_bfs.rs | 43 +++++++++------ codes/rust/chapter_tree/binary_tree_dfs.rs | 63 +++++++++++----------- 2 files changed, 58 insertions(+), 48 deletions(-) diff --git a/codes/rust/chapter_tree/binary_tree_bfs.rs b/codes/rust/chapter_tree/binary_tree_bfs.rs index 5cb0fa750b..c4d521e2a2 100644 --- a/codes/rust/chapter_tree/binary_tree_bfs.rs +++ b/codes/rust/chapter_tree/binary_tree_bfs.rs @@ -4,42 +4,51 @@ * Author: xBLACKICEx (xBLACKICE@outlook.com) */ -use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; -use hello_algo_rust::op_vec; - +use hello_algo_rust::binary_tree::{BinaryTree, TreeLink}; +use std::cell::RefCell; use std::collections::VecDeque; -use std::{cell::RefCell, rc::Rc}; +use std::rc::Rc; + +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* 层序遍历 */ -pub fn level_order(root: &Rc>) -> Vec { +pub fn level_order(root: &Option>>) -> Vec { + // 若根节点为空,则返回空列表 + let Some(root) = root else { + return Vec::new(); + }; + // 初始化队列,加入根节点 let mut que = VecDeque::new(); - que.push_back(root.clone()); + que.push_back(Rc::clone(root)); // 初始化一个列表,用于保存遍历序列 let mut vec = Vec::new(); + // 队列出队 while let Some(node) = que.pop_front() { - // 队列出队 - vec.push(node.borrow().val); // 保存节点值 - if let Some(left) = node.borrow().left.as_ref() { - que.push_back(left.clone()); // 左子节点入队 + // 保存节点值 + vec.push(node.borrow().val); + if let Some(left) = &node.borrow().left { + // 左子节点入队 + que.push_back(Rc::clone(left)); } - if let Some(right) = node.borrow().right.as_ref() { - que.push_back(right.clone()); // 右子节点入队 + if let Some(right) = &node.borrow().right { + // 右子节点入队 + que.push_back(Rc::clone(right)); }; } + vec } /* Driver Code */ fn main() { /* 初始化二叉树 */ - // 这里借助了一个从数组直接生成二叉树的函数 - let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]).unwrap(); - println!("初始化二叉树\n"); - print_util::print_tree(&root); + let array = [1, 2, 3, 4, 5, 6, 7]; + let root = TreeLink::try_from_array(array.map(Some)).ok(); + println!("初始化二叉树\n{}", root.display()); /* 层序遍历 */ let vec = level_order(&root); - print!("\n层序遍历的节点打印序列 = {:?}", vec); + println!("层序遍历的节点打印序列 = {vec:?}"); } diff --git a/codes/rust/chapter_tree/binary_tree_dfs.rs b/codes/rust/chapter_tree/binary_tree_dfs.rs index c2daa0afcb..66d3b74ae8 100644 --- a/codes/rust/chapter_tree/binary_tree_dfs.rs +++ b/codes/rust/chapter_tree/binary_tree_dfs.rs @@ -4,59 +4,61 @@ * Author: xBLACKICEx (xBLACKICE@outlook.com) */ -use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; -use hello_algo_rust::op_vec; - +use hello_algo_rust::binary_tree::{BinaryTree, TreeLink}; use std::cell::RefCell; use std::rc::Rc; +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; + /* 前序遍历 */ -pub fn pre_order(root: Option<&Rc>>) -> Vec { - let mut result = vec![]; +pub fn pre_order(root: &Option>>) -> Vec { + let mut result = Vec::new(); - fn dfs(root: Option<&Rc>>, res: &mut Vec) { + fn dfs(root: &Option>>, result: &mut Vec) { if let Some(node) = root { // 访问优先级:根节点 -> 左子树 -> 右子树 let node = node.borrow(); - res.push(node.val); - dfs(node.left.as_ref(), res); - dfs(node.right.as_ref(), res); + result.push(node.val); + dfs(&node.left, result); + dfs(&node.right, result); } } + dfs(root, &mut result); result } /* 中序遍历 */ -pub fn in_order(root: Option<&Rc>>) -> Vec { - let mut result = vec![]; +pub fn in_order(root: &Option>>) -> Vec { + let mut result = Vec::new(); - fn dfs(root: Option<&Rc>>, res: &mut Vec) { + fn dfs(root: &Option>>, result: &mut Vec) { if let Some(node) = root { // 访问优先级:左子树 -> 根节点 -> 右子树 let node = node.borrow(); - dfs(node.left.as_ref(), res); - res.push(node.val); - dfs(node.right.as_ref(), res); + dfs(&node.left, result); + result.push(node.val); + dfs(&node.right, result); } } + dfs(root, &mut result); result } /* 后序遍历 */ -pub fn post_order(root: Option<&Rc>>) -> Vec { - let mut result = vec![]; +pub fn post_order(root: &Option>>) -> Vec { + let mut result = Vec::new(); - fn dfs(root: Option<&Rc>>, res: &mut Vec) { + fn dfs(root: &Option>>, result: &mut Vec) { if let Some(node) = root { // 访问优先级:左子树 -> 右子树 -> 根节点 let node = node.borrow(); - dfs(node.left.as_ref(), res); - dfs(node.right.as_ref(), res); - res.push(node.val); + dfs(&node.left, result); + dfs(&node.right, result); + result.push(node.val); } } @@ -68,20 +70,19 @@ pub fn post_order(root: Option<&Rc>>) -> Vec { /* Driver Code */ fn main() { /* 初始化二叉树 */ - // 这里借助了一个从数组直接生成二叉树的函数 - let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]); - println!("初始化二叉树\n"); - print_util::print_tree(root.as_ref().unwrap()); + let array = [1, 2, 3, 4, 5, 6, 7]; + let root = TreeLink::try_from_array(array.map(Some)).ok(); + println!("初始化二叉树\n{}", root.display()); /* 前序遍历 */ - let vec = pre_order(root.as_ref()); - println!("\n前序遍历的节点打印序列 = {:?}", vec); + let vec = pre_order(&root); + println!("前序遍历的节点打印序列 = {vec:?}"); /* 中序遍历 */ - let vec = in_order(root.as_ref()); - println!("\n中序遍历的节点打印序列 = {:?}", vec); + let vec = in_order(&root); + println!("中序遍历的节点打印序列 = {vec:?}"); /* 后序遍历 */ - let vec = post_order(root.as_ref()); - print!("\n后序遍历的节点打印序列 = {:?}", vec); + let vec = post_order(&root); + println!("后序遍历的节点打印序列 = {vec:?}"); } From dd02f9cd688e10b2914edb9403cd17205dfa2f7c Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:30:39 +0800 Subject: [PATCH 054/109] refactor: replace all index types with `usize` Refer to codes/rust/GUIDELINES.md for more information. --- codes/rust/chapter_tree/array_binary_tree.rs | 153 ++++++++----------- 1 file changed, 63 insertions(+), 90 deletions(-) diff --git a/codes/rust/chapter_tree/array_binary_tree.rs b/codes/rust/chapter_tree/array_binary_tree.rs index 3cf65e4e67..047177b158 100644 --- a/codes/rust/chapter_tree/array_binary_tree.rs +++ b/codes/rust/chapter_tree/array_binary_tree.rs @@ -4,7 +4,8 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::{print_util, tree_node}; +use hello_algo_rust::binary_tree::{BinaryTree, TreeLink}; +use std::borrow::Cow; /* 数组表示下的二叉树类 */ pub struct ArrayBinaryTree { @@ -18,59 +19,68 @@ impl ArrayBinaryTree { } /* 列表容量 */ - pub fn size(&self) -> i32 { - self.tree.len() as i32 + pub fn size(&self) -> usize { + self.tree.len() } /* 获取索引为 i 节点的值 */ - pub fn val(&self, i: i32) -> Option { + pub fn val(&self, i: usize) -> Option { // 若索引越界,则返回 None ,代表空位 - if i < 0 || i >= self.size() { - None - } else { - self.tree[i as usize] - } + if i >= self.size() { None } else { self.tree[i] } } /* 获取索引为 i 节点的左子节点的索引 */ - pub fn left(&self, i: i32) -> i32 { + pub fn left(&self, i: usize) -> usize { 2 * i + 1 } /* 获取索引为 i 节点的右子节点的索引 */ - pub fn right(&self, i: i32) -> i32 { + pub fn right(&self, i: usize) -> usize { 2 * i + 2 } /* 获取索引为 i 节点的父节点的索引 */ - pub fn parent(&self, i: i32) -> i32 { + pub fn parent(&self, i: usize) -> usize { (i - 1) / 2 } /* 层序遍历 */ pub fn level_order(&self) -> Vec { - self.tree.iter().filter_map(|&x| x).collect() + self.tree.iter().filter_map(|x| *x).collect() } /* 深度优先遍历 */ - fn dfs(&self, i: i32, order: &'static str, res: &mut Vec) { - if self.val(i).is_none() { - return; - } - let val = self.val(i).unwrap(); - // 前序遍历 - if order == "pre" { - res.push(val); - } - self.dfs(self.left(i), order, res); - // 中序遍历 - if order == "in" { - res.push(val); - } - self.dfs(self.right(i), order, res); - // 后序遍历 - if order == "post" { - res.push(val); + fn dfs(&self, i: usize, order: &str, res: &mut Vec) { + let Some(val) = self.val(i) else { return }; + + // 此处匹配字符串属于不良实践,它也许来自对其他语言实现的模仿。除了只读数据段和 + // 栈空间的额外开销,这还产生了一个冗余的 fallback 分支。一个较好的实现方式是 + // 将 order 定义为枚举,一个更好的实现方式是直接实现 pre_order、in_order + // 和 post_order 方法,因为这里的动态性毫无意义。 + match order { + // 前序遍历 + "pre" => { + res.push(val); + self.dfs(self.left(i), order, res); + self.dfs(self.right(i), order, res); + } + + // 中序遍历 + "in" => { + self.dfs(self.left(i), order, res); + res.push(val); + self.dfs(self.right(i), order, res); + } + + // 后序遍历 + "post" => { + self.dfs(self.left(i), order, res); + self.dfs(self.right(i), order, res); + res.push(val); + } + + // 因私有接口而保证不可达 + _ => unreachable!(), } } @@ -99,7 +109,6 @@ impl ArrayBinaryTree { /* Driver Code */ fn main() { // 初始化二叉树 - // 这里借助了一个从数组直接生成二叉树的函数 let arr = vec![ Some(1), Some(2), @@ -118,22 +127,21 @@ fn main() { Some(15), ]; - let root = tree_node::vec_to_tree(arr.clone()).unwrap(); - println!("\n初始化二叉树\n"); + let root = TreeLink::try_from_slice(&arr).ok(); + + fn repr(val: &Option) -> Cow<'static, str> { + if let Some(v) = val { + Cow::Owned(v.to_string()) + } else { + Cow::Borrowed("null") + } + } + + println!("初始化二叉树"); println!("二叉树的数组表示:"); - println!( - "[{}]", - arr.iter() - .map(|&val| if let Some(val) = val { - format!("{val}") - } else { - "null".to_string() - }) - .collect::>() - .join(", ") - ); + println!("[{}]", arr.iter().map(repr).collect::>().join(", ")); println!("二叉树的链表表示:"); - print_util::print_tree(&root); + println!("{}", root.display()); // 数组表示下的二叉树类 let abt = ArrayBinaryTree::new(arr); @@ -143,50 +151,15 @@ fn main() { let l = abt.left(i); let r = abt.right(i); let p = abt.parent(i); - println!( - "\n当前节点的索引为 {} ,值为 {}", - i, - if let Some(val) = abt.val(i) { - format!("{val}") - } else { - "null".to_string() - } - ); - println!( - "其左子节点的索引为 {} ,值为 {}", - l, - if let Some(val) = abt.val(l) { - format!("{val}") - } else { - "null".to_string() - } - ); - println!( - "其右子节点的索引为 {} ,值为 {}", - r, - if let Some(val) = abt.val(r) { - format!("{val}") - } else { - "null".to_string() - } - ); - println!( - "其父节点的索引为 {} ,值为 {}", - p, - if let Some(val) = abt.val(p) { - format!("{val}") - } else { - "null".to_string() - } - ); + println!("当前节点的索引为 {i} ,值为 {}", repr(&abt.val(i))); + println!("其左子节点的索引为 {l} ,值为 {}", repr(&abt.val(l))); + println!("其右子节点的索引为 {r} ,值为 {}", repr(&abt.val(r))); + println!("其父节点的索引为 {p} ,值为 {}", repr(&abt.val(p))); + println!(); // 遍历树 - let mut res = abt.level_order(); - println!("\n层序遍历为:{:?}", res); - res = abt.pre_order(); - println!("前序遍历为:{:?}", res); - res = abt.in_order(); - println!("中序遍历为:{:?}", res); - res = abt.post_order(); - println!("后序遍历为:{:?}", res); + println!("层序遍历为:{:?}", abt.level_order()); + println!("前序遍历为:{:?}", abt.pre_order()); + println!("中序遍历为:{:?}", abt.in_order()); + println!("后序遍历为:{:?}", abt.post_order()); } From a92c2ecac5ccbf3f505a82ff866c69839e5631c9 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:31:35 +0800 Subject: [PATCH 055/109] fix: resolve warning Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_tree/binary_search_tree.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/codes/rust/chapter_tree/binary_search_tree.rs b/codes/rust/chapter_tree/binary_search_tree.rs index 720d9c642b..5a3516a836 100644 --- a/codes/rust/chapter_tree/binary_search_tree.rs +++ b/codes/rust/chapter_tree/binary_search_tree.rs @@ -21,6 +21,7 @@ pub struct BinarySearchTree { impl BinarySearchTree { /* 构造方法 */ + #[allow(clippy::new_without_default)] pub fn new() -> Self { // 初始化空树 Self { root: None } From b23f33e572101aa8edfbb49b767b801f0bb678ff Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:49:19 +0800 Subject: [PATCH 056/109] perf: eliminate overhead from unnecessary unwraps, Rc cloning/dropping and RefCell borrowing --- codes/rust/chapter_tree/binary_search_tree.rs | 157 +++++++++--------- 1 file changed, 75 insertions(+), 82 deletions(-) diff --git a/codes/rust/chapter_tree/binary_search_tree.rs b/codes/rust/chapter_tree/binary_search_tree.rs index 5a3516a836..e61f47d36f 100644 --- a/codes/rust/chapter_tree/binary_search_tree.rs +++ b/codes/rust/chapter_tree/binary_search_tree.rs @@ -4,19 +4,16 @@ * Author: xBLACKICEx (xBLACKICE@outlook.com)、night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; - +use hello_algo_rust::binary_tree::BinaryTree; use std::cell::RefCell; use std::cmp::Ordering; use std::rc::Rc; -use hello_algo_rust::include::TreeNode; - -type OptionTreeNodeRc = Option>>; +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* 二叉搜索树 */ pub struct BinarySearchTree { - root: OptionTreeNodeRc, + root: Option>>, } impl BinarySearchTree { @@ -28,20 +25,20 @@ impl BinarySearchTree { } /* 获取二叉树根节点 */ - pub fn get_root(&self) -> OptionTreeNodeRc { - self.root.clone() + pub fn get_root(&self) -> &Option>> { + &self.root } /* 查找节点 */ - pub fn search(&self, num: i32) -> OptionTreeNodeRc { + pub fn search(&self, num: i32) -> Option>> { let mut cur = self.root.clone(); // 循环查找,越过叶节点后跳出 while let Some(node) = cur.clone() { match num.cmp(&node.borrow().val) { - // 目标节点在 cur 的右子树中 - Ordering::Greater => cur = node.borrow().right.clone(), // 目标节点在 cur 的左子树中 Ordering::Less => cur = node.borrow().left.clone(), + // 目标节点在 cur 的右子树中 + Ordering::Greater => cur = node.borrow().right.clone(), // 找到目标节点,跳出循环 Ordering::Equal => break, } @@ -63,22 +60,22 @@ impl BinarySearchTree { // 循环查找,越过叶节点后跳出 while let Some(node) = cur.clone() { match num.cmp(&node.borrow().val) { - // 找到重复节点,直接返回 - Ordering::Equal => return, - // 插入位置在 cur 的右子树中 - Ordering::Greater => { - pre = cur.clone(); - cur = node.borrow().right.clone(); - } // 插入位置在 cur 的左子树中 Ordering::Less => { - pre = cur.clone(); + pre = cur.take(); cur = node.borrow().left.clone(); } + // 插入位置在 cur 的右子树中 + Ordering::Greater => { + pre = cur.take(); + cur = node.borrow().right.clone(); + } + // 找到重复节点,直接返回 + Ordering::Equal => return, } } // 插入节点 - let pre = pre.unwrap(); + let pre = pre.unwrap_or_else(|| unreachable!()); let node = Some(TreeNode::new(num)); if num > pre.borrow().val { pre.borrow_mut().right = node; @@ -98,62 +95,66 @@ impl BinarySearchTree { // 循环查找,越过叶节点后跳出 while let Some(node) = cur.clone() { match num.cmp(&node.borrow().val) { - // 找到待删除节点,跳出循环 - Ordering::Equal => break, - // 待删除节点在 cur 的右子树中 - Ordering::Greater => { - pre = cur.clone(); - cur = node.borrow().right.clone(); - } // 待删除节点在 cur 的左子树中 Ordering::Less => { - pre = cur.clone(); + pre = cur.take(); cur = node.borrow().left.clone(); } + // 待删除节点在 cur 的右子树中 + Ordering::Greater => { + pre = cur.take(); + cur = node.borrow().right.clone(); + } + // 找到待删除节点,跳出循环 + Ordering::Equal => break, } } // 若无待删除节点,则直接返回 - if cur.is_none() { - return; + let Some(cur) = cur else { return }; + let borrow = cur.borrow(); + let left_child = borrow.left.as_ref(); + let right_child = borrow.right.as_ref(); + // 当子节点的数量为 0 或 1 时 + if left_child.is_none() || right_child.is_none() { + // 此时 child 为空或 cur 的唯一子节点 + let child = left_child.or(right_child).cloned(); + let Some(pre) = pre else { + // 若 pre 为空,则查找节点的第一轮循环里发生了 break, + // 此时待删除的节点为根节点,应重新指定根节点 + self.root = child; + return; + }; + if borrow.val < pre.borrow().val { + pre.borrow_mut().left = child; + } else { + pre.borrow_mut().right = child; + } } - let cur = cur.unwrap(); - let (left_child, right_child) = (cur.borrow().left.clone(), cur.borrow().right.clone()); - match (left_child.clone(), right_child.clone()) { - // 子节点数量 = 0 or 1 - (None, None) | (Some(_), None) | (None, Some(_)) => { - // 当子节点数量 = 0 / 1 时, child = nullptr / 该子节点 - let child = left_child.or(right_child); - let pre = pre.unwrap(); - // 删除节点 cur - if !Rc::ptr_eq(&cur, self.root.as_ref().unwrap()) { - let left = pre.borrow().left.clone(); - if left.is_some() && Rc::ptr_eq(left.as_ref().unwrap(), &cur) { - pre.borrow_mut().left = child; - } else { - pre.borrow_mut().right = child; - } + // 子节点的数量为 2 时 + else { + // 获取中序遍历中 cur 的下一个节点 + let Some(mut tmp) = right_child.cloned() else { + // cur 的子节点数量为 2,一定存在右子节点,该分支不可达 + unreachable!() + }; + // 相比于 while let,此代码能绕开 tmp 借用的生命周期并减少一次共享指针的克隆; + // 考虑到可读性,也许应该恢复 while let 写法 + loop { + tmp = if let Some(left) = &tmp.borrow().left { + Rc::clone(left) } else { - // 若删除节点为根节点,则重新指定根节点 - self.root = child; - } - } - // 子节点数量 = 2 - (Some(_), Some(_)) => { - // 获取中序遍历中 cur 的下一个节点 - let mut tmp = cur.borrow().right.clone(); - while let Some(node) = tmp.clone() { - if node.borrow().left.is_some() { - tmp = node.borrow().left.clone(); - } else { - break; - } - } - let tmp_val = tmp.unwrap().borrow().val; - // 递归删除节点 tmp - self.remove(tmp_val); - // 用 tmp 覆盖 cur - cur.borrow_mut().val = tmp_val; + break; + }; } + // 这是当前作用域内仍然存活的借用,需要在递归前丢弃,如果保留在调用栈中, + // 可能会因同一节点的可变借用而触发 panic;即使没有发生这种情况,下面对 + // cur 节点的可变借用也会导致 panic + drop(borrow); + let tmp_val = tmp.borrow().val; + // 递归删除节点 tmp + self.remove(tmp_val); + // 用 tmp 覆盖 cur + cur.borrow_mut().val = tmp_val; } } } @@ -167,30 +168,22 @@ fn main() { for &num in &nums { bst.insert(num); } - println!("\n初始化的二叉树为\n"); - print_util::print_tree(bst.get_root().as_ref().unwrap()); + println!("初始化的二叉树为\n{}", bst.get_root().display()); /* 查找结点 */ - let node = bst.search(7); - println!( - "\n查找到的节点对象为 {:?},节点值 = {}", - node.clone().unwrap(), - node.clone().unwrap().borrow().val - ); + let node = bst.search(7).unwrap(); + let val = node.borrow().val; + println!("查找到的节点对象为 {node:?},节点值 = {val}"); /* 插入节点 */ bst.insert(16); - println!("\n插入节点 16 后,二叉树为\n"); - print_util::print_tree(bst.get_root().as_ref().unwrap()); + println!("插入节点 16 后,二叉树为\n{}", bst.get_root().display()); /* 删除节点 */ bst.remove(1); - println!("\n删除节点 1 后,二叉树为\n"); - print_util::print_tree(bst.get_root().as_ref().unwrap()); + println!("删除节点 1 后,二叉树为\n{}", bst.get_root().display()); bst.remove(2); - println!("\n删除节点 2 后,二叉树为\n"); - print_util::print_tree(bst.get_root().as_ref().unwrap()); + println!("删除节点 2 后,二叉树为\n{}", bst.get_root().display()); bst.remove(4); - println!("\n删除节点 4 后,二叉树为\n"); - print_util::print_tree(bst.get_root().as_ref().unwrap()); + println!("删除节点 4 后,二叉树为\n{}", bst.get_root().display()); } From ccd1608532be6cf327c5243301d3706fed8bfdcf Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:49:26 +0800 Subject: [PATCH 057/109] fix: resolve warning Explicitly omitted: - `clippy::new_without_default` --- codes/rust/chapter_tree/avl_tree.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/codes/rust/chapter_tree/avl_tree.rs b/codes/rust/chapter_tree/avl_tree.rs index 908f632d33..18b9b04f9b 100644 --- a/codes/rust/chapter_tree/avl_tree.rs +++ b/codes/rust/chapter_tree/avl_tree.rs @@ -19,6 +19,7 @@ pub struct AVLTree { impl AVLTree { /* 构造方法 */ + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { root: None } } From 4d655eacd502cdef678b218466650dc01af0d27d Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:49:32 +0800 Subject: [PATCH 058/109] perf: eliminate overhead from unnecessary Rc cloning/dropping and RefCell borrowing --- codes/rust/chapter_tree/avl_tree.rs | 341 ++++++++++++++++------------ 1 file changed, 193 insertions(+), 148 deletions(-) diff --git a/codes/rust/chapter_tree/avl_tree.rs b/codes/rust/chapter_tree/avl_tree.rs index 18b9b04f9b..a65c895f57 100644 --- a/codes/rust/chapter_tree/avl_tree.rs +++ b/codes/rust/chapter_tree/avl_tree.rs @@ -4,17 +4,16 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::{print_util, TreeNode}; - +use hello_algo_rust::binary_tree::BinaryTree; use std::cell::RefCell; use std::cmp::Ordering; use std::rc::Rc; -type OptionTreeNodeRc = Option>>; +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* AVL 树 */ pub struct AVLTree { - root: OptionTreeNodeRc, // 根节点 + root: Option>>, // 根节点 } impl AVLTree { @@ -25,107 +24,146 @@ impl AVLTree { } /* 获取节点高度 */ - pub fn height(node: OptionTreeNodeRc) -> i32 { - // 空节点高度为 -1 ,叶节点高度为 0 - match node { - Some(node) => node.borrow().height, - None => -1, - } + pub fn height(node: Option>>) -> Option { + // 这里我们遵循 Rust 类型系统的惯例,定义空节点高度为 None ,叶节点高度为 Some(0) + Some(node?.borrow().height) } /* 更新节点高度 */ - fn update_height(node: OptionTreeNodeRc) { + fn update_height(node: Option>>) { if let Some(node) = node { - let left = node.borrow().left.clone(); - let right = node.borrow().right.clone(); - // 节点高度等于最高子树高度 + 1 - node.borrow_mut().height = std::cmp::max(Self::height(left), Self::height(right)) + 1; + // 节点高度等于最高子树高度 + 1,如果没有子节点,则高度为 0 + let mut height = 0; + if let Some(left) = &node.borrow().left { + height = left.borrow().height + 1; + } + if let Some(right) = &node.borrow().right { + height = height.max(right.borrow().height + 1); + } + node.borrow_mut().height = height; } } /* 获取平衡因子 */ - fn balance_factor(node: OptionTreeNodeRc) -> i32 { - match node { - // 空节点平衡因子为 0 - None => 0, - // 节点平衡因子 = 左子树高度 - 右子树高度 - Some(node) => { - Self::height(node.borrow().left.clone()) - Self::height(node.borrow().right.clone()) + fn balance_factor(node: Option>>) -> i8 { + // 节点平衡因子 = 左子树高度 - 右子树高度 + // 平衡时取值为 -1 、 0 或 1,失衡时取值为 -2 或 2,不会出现其他值 + + let Some(node) = node else { + // 空节点的平衡因子为 0 + return 0; + }; + + match (&node.borrow().left, &node.borrow().right) { + (None, None) => 0, + + (None, Some(right)) => { + if right.borrow().height == 0 { + -1 + } else { + -2 + } + } + + (Some(left), None) => { + if left.borrow().height == 0 { + 1 + } else { + 2 + } + } + + (Some(left), Some(right)) => { + let left_height = left.borrow().height; + let right_height = right.borrow().height; + if left_height + 1 < right_height { + -2 + } else if left_height + 1 == right_height { + -1 + } else if left_height == right_height { + 0 + } else if left_height == right_height + 1 { + 1 + } else { + 2 + } } } } /* 右旋操作 */ - fn right_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc { - match node { - Some(node) => { - let child = node.borrow().left.clone().unwrap(); - let grand_child = child.borrow().right.clone(); - // 以 child 为原点,将 node 向右旋转 - child.borrow_mut().right = Some(node.clone()); - node.borrow_mut().left = grand_child; - // 更新节点高度 - Self::update_height(Some(node)); - Self::update_height(Some(child.clone())); - // 返回旋转后子树的根节点 - Some(child) - } - None => None, - } + fn right_rotate(node: Option>>) -> Option>> { + let node = node?; + let child = node + .borrow_mut() + .left + .take() + .expect("该方法仅可在左子树失衡时调用,左子节点不应为空"); + let grand_child = child.borrow_mut().right.take(); + // 以 child 为原点,将 node 向右旋转 + child.borrow_mut().right = Some(Rc::clone(&node)); + node.borrow_mut().left = grand_child; + // 更新节点高度 + Self::update_height(Some(node)); + Self::update_height(Some(Rc::clone(&child))); + // 返回旋转后子树的根节点 + Some(child) } /* 左旋操作 */ - fn left_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc { - match node { - Some(node) => { - let child = node.borrow().right.clone().unwrap(); - let grand_child = child.borrow().left.clone(); - // 以 child 为原点,将 node 向左旋转 - child.borrow_mut().left = Some(node.clone()); - node.borrow_mut().right = grand_child; - // 更新节点高度 - Self::update_height(Some(node)); - Self::update_height(Some(child.clone())); - // 返回旋转后子树的根节点 - Some(child) - } - None => None, - } + fn left_rotate(node: Option>>) -> Option>> { + let node = node?; + let child = node + .borrow_mut() + .right + .take() + .expect("该方法仅可在右子树失衡时调用,右子节点不应为空"); + let grand_child = child.borrow_mut().left.take(); + // 以 child 为原点,将 node 向左旋转 + child.borrow_mut().left = Some(Rc::clone(&node)); + node.borrow_mut().right = grand_child; + // 更新节点高度 + Self::update_height(Some(node)); + Self::update_height(Some(Rc::clone(&child))); + // 返回旋转后子树的根节点 + Some(child) } /* 执行旋转操作,使该子树重新恢复平衡 */ - fn rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc { + fn rotate(node: Option>>) -> Option>> { // 获取节点 node 的平衡因子 let balance_factor = Self::balance_factor(node.clone()); + // 左偏树 if balance_factor > 1 { - let node = node.unwrap(); + // 根据定义,node 仅在平衡因子为 0 的情况下可能为空节点 + let node = node.unwrap_or_else(|| unreachable!()); if Self::balance_factor(node.borrow().left.clone()) >= 0 { // 右旋 - Self::right_rotate(Some(node)) - } else { - // 先左旋后右旋 - let left = node.borrow().left.clone(); - node.borrow_mut().left = Self::left_rotate(left); - Self::right_rotate(Some(node)) + return Self::right_rotate(Some(node)); } + // 先左旋后右旋 + let left = node.borrow().left.clone(); + node.borrow_mut().left = Self::left_rotate(left); + return Self::right_rotate(Some(node)); } + // 右偏树 - else if balance_factor < -1 { - let node = node.unwrap(); + if balance_factor < -1 { + // 根据定义,node 仅在平衡因子为 0 的情况下可能为空节点 + let node = node.unwrap_or_else(|| unreachable!()); if Self::balance_factor(node.borrow().right.clone()) <= 0 { // 左旋 - Self::left_rotate(Some(node)) - } else { - // 先右旋后左旋 - let right = node.borrow().right.clone(); - node.borrow_mut().right = Self::right_rotate(right); - Self::left_rotate(Some(node)) + return Self::left_rotate(Some(node)); } - } else { - // 平衡树,无须旋转,直接返回 - node + // 先右旋后左旋 + let right = node.borrow().right.clone(); + node.borrow_mut().right = Self::right_rotate(right); + return Self::left_rotate(Some(node)); } + + // 平衡树,无须旋转,直接返回 + node } /* 插入节点 */ @@ -134,37 +172,37 @@ impl AVLTree { } /* 递归插入节点(辅助方法) */ - fn insert_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc { - match node { - Some(mut node) => { - /* 1. 查找插入位置并插入节点 */ - match { - let node_val = node.borrow().val; - node_val - } - .cmp(&val) - { - Ordering::Greater => { - let left = node.borrow().left.clone(); - node.borrow_mut().left = Self::insert_helper(left, val); - } - Ordering::Less => { - let right = node.borrow().right.clone(); - node.borrow_mut().right = Self::insert_helper(right, val); - } - Ordering::Equal => { - return Some(node); // 重复节点不插入,直接返回 - } - } - Self::update_height(Some(node.clone())); // 更新节点高度 + fn insert_helper( + node: Option>>, + val: i32, + ) -> Option>> { + let Some(mut node) = node else { + return Some(TreeNode::new(val)); + }; - /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = Self::rotate(Some(node)).unwrap(); - // 返回子树的根节点 - Some(node) + // 查找插入位置并插入节点 + let node_val = node.borrow().val; + match val.cmp(&node_val) { + Ordering::Less => { + let left = node.borrow_mut().left.take(); + node.borrow_mut().left = Self::insert_helper(left, val); + } + Ordering::Greater => { + let right = node.borrow_mut().right.take(); + node.borrow_mut().right = Self::insert_helper(right, val); } - None => Some(TreeNode::new(val)), + // 重复节点不插入,直接返回 + Ordering::Equal => return Some(node), } + + // 更新节点高度 + Self::update_height(Some(node.clone())); + + // 执行旋转操作,使该子树重新恢复平衡 + node = Self::rotate(Some(node)).unwrap_or_else(|| unreachable!()); + + // 返回子树的根节点 + Some(node) } /* 删除节点 */ @@ -173,73 +211,82 @@ impl AVLTree { } /* 递归删除节点(辅助方法) */ - fn remove_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc { - match node { - Some(mut node) => { - /* 1. 查找节点并删除 */ - if val < node.borrow().val { - let left = node.borrow().left.clone(); - node.borrow_mut().left = Self::remove_helper(left, val); - } else if val > node.borrow().val { - let right = node.borrow().right.clone(); - node.borrow_mut().right = Self::remove_helper(right, val); - } else if node.borrow().left.is_none() || node.borrow().right.is_none() { - let child = if node.borrow().left.is_some() { - node.borrow().left.clone() - } else { - node.borrow().right.clone() - }; + fn remove_helper( + node: Option>>, + val: i32, + ) -> Option>> { + let mut node = node?; + + // 查找节点并删除 + let node_val = node.borrow().val; + match val.cmp(&node_val) { + Ordering::Less => { + let left = node.borrow().left.clone(); + node.borrow_mut().left = Self::remove_helper(left, val); + } + Ordering::Greater => { + let right = node.borrow().right.clone(); + node.borrow_mut().right = Self::remove_helper(right, val); + } + Ordering::Equal => { + let borrow = node.borrow(); + let left_child = borrow.left.as_ref(); + let right_child = borrow.right.as_ref(); + if left_child.is_none() || right_child.is_none() { + let child = left_child.or(right_child).cloned(); + drop(borrow); match child { // 子节点数量 = 0 ,直接删除 node 并返回 - None => { - return None; - } + None => return None, // 子节点数量 = 1 ,直接删除 node Some(child) => node = child, } } else { // 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节点 - let mut temp = node.borrow().right.clone().unwrap(); + let Some(mut temp) = node.borrow().right.clone() else { + unreachable!() + }; loop { - let temp_left = temp.borrow().left.clone(); - if temp_left.is_none() { + temp = if let Some(temp_left) = &temp.borrow().left { + Rc::clone(temp_left) + } else { break; - } - temp = temp_left.unwrap(); + }; } - let right = node.borrow().right.clone(); + drop(borrow); + let right = node.borrow_mut().right.take(); node.borrow_mut().right = Self::remove_helper(right, temp.borrow().val); node.borrow_mut().val = temp.borrow().val; } - Self::update_height(Some(node.clone())); // 更新节点高度 - - /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = Self::rotate(Some(node)).unwrap(); - // 返回子树的根节点 - Some(node) } - None => None, } + + // 更新节点高度 + Self::update_height(Some(node.clone())); + + // 执行旋转操作,使该子树重新恢复平衡 + node = Self::rotate(Some(node)).unwrap_or_else(|| unreachable!()); + + // 返回子树的根节点 + Some(node) } /* 查找节点 */ - pub fn search(&self, val: i32) -> OptionTreeNodeRc { + pub fn search(&self, val: i32) -> Option>> { let mut cur = self.root.clone(); // 循环查找,越过叶节点后跳出 while let Some(current) = cur.clone() { - match current.borrow().val.cmp(&val) { - // 目标节点在 cur 的右子树中 + match val.cmp(¤t.borrow().val) { + // 目标节点在 cur 的左子树中 Ordering::Less => { - cur = current.borrow().right.clone(); + cur = current.borrow().left.clone(); } - // 目标节点在 cur 的左子树中 + // 目标节点在 cur 的右子树中 Ordering::Greater => { - cur = current.borrow().left.clone(); + cur = current.borrow().right.clone(); } // 找到目标节点,跳出循环 - Ordering::Equal => { - break; - } + Ordering::Equal => break, } } // 返回目标节点 @@ -251,14 +298,12 @@ impl AVLTree { fn main() { fn test_insert(tree: &mut AVLTree, val: i32) { tree.insert(val); - println!("\n插入节点 {} 后,AVL 树为", val); - print_util::print_tree(&tree.root.clone().unwrap()); + println!("插入节点 {val} 后,AVL 树为\n{}", tree.root.display()); } fn test_remove(tree: &mut AVLTree, val: i32) { tree.remove(val); - println!("\n删除节点 {} 后,AVL 树为", val); - print_util::print_tree(&tree.root.clone().unwrap()); + println!("删除节点 {val} 后,AVL 树为\n{}", tree.root.display()); } /* 初始化空 AVL 树 */ @@ -290,8 +335,8 @@ fn main() { let node = avl_tree.search(7); if let Some(node) = node { println!( - "\n查找到的节点对象为 {:?},节点值 = {}", - &*node.borrow(), + "查找到的节点对象为 {:?},节点值 = {}", + node.borrow(), node.borrow().val ); } From ab7ef42b6b5eded10f9292f6589d71ffa64d4937 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:51:04 +0800 Subject: [PATCH 059/109] refactor: simplify formatted output logic --- codes/rust/chapter_heap/heap.rs | 37 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/codes/rust/chapter_heap/heap.rs b/codes/rust/chapter_heap/heap.rs index 7281865a48..c582037c15 100644 --- a/codes/rust/chapter_heap/heap.rs +++ b/codes/rust/chapter_heap/heap.rs @@ -4,33 +4,35 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; - -use std::{cmp::Reverse, collections::BinaryHeap}; +use hello_algo_rust::heap::Heap; +use std::cmp::Reverse; +use std::collections::BinaryHeap; fn test_push_max(heap: &mut BinaryHeap, val: i32) { heap.push(val); // 元素入堆 - println!("\n元素 {} 入堆后", val); - print_util::print_heap(heap.iter().map(|&val| val).collect()); + println!("元素 {val} 入堆后"); + println!("堆的数组表示:{}", heap.display_as_array()); + println!("堆的树状表示:\n{}", heap.display_as_tree()); } fn test_pop_max(heap: &mut BinaryHeap) { let val = heap.pop().unwrap(); - println!("\n堆顶元素 {} 出堆后", val); - print_util::print_heap(heap.iter().map(|&val| val).collect()); + println!("堆顶元素 {val} 出堆后"); + println!("堆的数组表示:{}", heap.display_as_array()); + println!("堆的树状表示:\n{}", heap.display_as_tree()); } /* Driver Code */ +#[allow(unused_assignments)] fn main() { /* 初始化堆 */ // 初始化小顶堆 - #[allow(unused_assignments)] let mut min_heap = BinaryHeap::new(); // Rust 的 BinaryHeap 是大顶堆,小顶堆一般会“套上”Reverse // 初始化大顶堆 let mut max_heap = BinaryHeap::new(); - println!("\n以下测试样例为大顶堆"); + println!("以下测试样例为大顶堆"); /* 元素入堆 */ test_push_max(&mut max_heap, 1); @@ -41,7 +43,7 @@ fn main() { /* 获取堆顶元素 */ let peek = max_heap.peek().unwrap(); - println!("\n堆顶元素为 {}", peek); + println!("堆顶元素为 {peek}"); /* 堆顶元素出堆 */ test_pop_max(&mut max_heap); @@ -52,20 +54,23 @@ fn main() { /* 获取堆大小 */ let size = max_heap.len(); - println!("\n堆元素数量为 {}", size); + println!("堆元素数量为 {size}"); /* 判断堆是否为空 */ let is_empty = max_heap.is_empty(); - println!("\n堆是否为空 {}", is_empty); + println!("堆是否为空 {is_empty}"); /* 输入列表并建堆 */ // 时间复杂度为 O(n) ,而非 O(nlogn) min_heap = BinaryHeap::from( vec![1, 3, 2, 5, 4] .into_iter() - .map(|val| Reverse(val)) - .collect::>>(), + .map(Reverse) + .collect::>(), ); - println!("\n输入列表并建立小顶堆后"); - print_util::print_heap(min_heap.iter().map(|&val| val.0).collect()); + + let vec = min_heap.iter().map(|val| val.0).collect::>(); + println!("输入列表并建立小顶堆后"); + println!("堆的数组表示:{}", vec.display_as_array()); + println!("堆的树状表示:\n{}", vec.display_as_tree()); } From fb251497cb0c45b051adbce523a38f70d3f0cd73 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Thu, 5 Feb 2026 23:54:44 +0800 Subject: [PATCH 060/109] refactor: improve readability --- codes/rust/chapter_heap/my_heap.rs | 50 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/codes/rust/chapter_heap/my_heap.rs b/codes/rust/chapter_heap/my_heap.rs index 05b1fb09cb..a341191bf0 100644 --- a/codes/rust/chapter_heap/my_heap.rs +++ b/codes/rust/chapter_heap/my_heap.rs @@ -4,7 +4,7 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; +use hello_algo_rust::heap::Heap; /* 大顶堆 */ pub struct MaxHeap { @@ -36,7 +36,8 @@ impl MaxHeap { /* 获取父节点的索引 */ fn parent(i: usize) -> usize { - (i - 1) / 2 // 向下整除 + // 向下整除 + (i - 1) / 2 } /* 交换元素 */ @@ -76,7 +77,7 @@ impl MaxHeap { } // 获取节点 i 的父节点 let p = Self::parent(i); - // 当“节点无须修复”时,结束堆化 + // 当节点无需修复时,结束堆化 if self.max_heap[i] <= self.max_heap[p] { break; } @@ -88,10 +89,10 @@ impl MaxHeap { } /* 元素出堆 */ - pub fn pop(&mut self) -> i32 { + pub fn pop(&mut self) -> Option { // 判空处理 if self.is_empty() { - panic!("index out of bounds"); + return None; } // 交换根节点与最右叶节点(交换首元素与尾元素) self.swap(0, self.size() - 1); @@ -100,34 +101,37 @@ impl MaxHeap { // 从顶至底堆化 self.sift_down(0); // 返回堆顶元素 - val + Some(val) } /* 从节点 i 开始,从顶至底堆化 */ fn sift_down(&mut self, mut i: usize) { loop { - // 判断节点 i, l, r 中值最大的节点,记为 ma - let (l, r, mut ma) = (Self::left(i), Self::right(i), i); - if l < self.size() && self.max_heap[l] > self.max_heap[ma] { - ma = l; + // 判断节点 i, l, r 中值最大的节点,记为 max + let l = Self::left(i); + let r = Self::right(i); + let mut max = i; + if l < self.size() && self.max_heap[l] > self.max_heap[max] { + max = l; } - if r < self.size() && self.max_heap[r] > self.max_heap[ma] { - ma = r; + if r < self.size() && self.max_heap[r] > self.max_heap[max] { + max = r; } // 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出 - if ma == i { + if max == i { break; } // 交换两节点 - self.swap(i, ma); + self.swap(i, max); // 循环向下堆化 - i = ma; + i = max; } } /* 打印堆(二叉树) */ pub fn print(&self) { - print_util::print_heap(self.max_heap.clone()); + println!("堆的数组表示:{}", self.max_heap.display_as_array()); + println!("堆的树状表示:\n{}", self.max_heap.display_as_tree()); } } @@ -135,31 +139,31 @@ impl MaxHeap { fn main() { /* 初始化大顶堆 */ let mut max_heap = MaxHeap::new(vec![9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]); - println!("\n输入列表并建堆后"); + println!("输入列表并建堆后"); max_heap.print(); /* 获取堆顶元素 */ let peek = max_heap.peek(); if let Some(peek) = peek { - println!("\n堆顶元素为 {}", peek); + println!("堆顶元素为 {peek}"); } /* 元素入堆 */ let val = 7; max_heap.push(val); - println!("\n元素 {} 入堆后", val); + println!("元素 {val} 入堆后"); max_heap.print(); /* 堆顶元素出堆 */ - let peek = max_heap.pop(); - println!("\n堆顶元素 {} 出堆后", peek); + let peek = max_heap.pop().unwrap(); + println!("堆顶元素 {peek} 出堆后"); max_heap.print(); /* 获取堆大小 */ let size = max_heap.size(); - println!("\n堆元素数量为 {}", size); + println!("堆元素数量为 {size}"); /* 判断堆是否为空 */ let is_empty = max_heap.is_empty(); - println!("\n堆是否为空 {}", is_empty); + println!("堆是否为空 {is_empty}"); } From 6abcb05a9b7407e4e09548a9cdfca8b2f1bd3d9f Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:02:10 +0800 Subject: [PATCH 061/109] fix: prevent `top_k_heap` from panicking when `k` is zero --- codes/rust/chapter_heap/top_k.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/codes/rust/chapter_heap/top_k.rs b/codes/rust/chapter_heap/top_k.rs index 15c2c0ac9a..cc9393ab95 100644 --- a/codes/rust/chapter_heap/top_k.rs +++ b/codes/rust/chapter_heap/top_k.rs @@ -4,8 +4,7 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; - +use hello_algo_rust::heap::Heap; use std::cmp::Reverse; use std::collections::BinaryHeap; @@ -13,6 +12,10 @@ use std::collections::BinaryHeap; pub fn top_k_heap(nums: Vec, k: usize) -> BinaryHeap> { // BinaryHeap 是大顶堆,使用 Reverse 将元素取反,从而实现小顶堆 let mut heap = BinaryHeap::>::new(); + // 确保之后的代码路径不会操作空堆 + if nums.is_empty() || k == 0 { + return heap; + } // 将数组的前 k 个元素入堆 for &num in nums.iter().take(k) { heap.push(Reverse(num)); @@ -20,7 +23,11 @@ pub fn top_k_heap(nums: Vec, k: usize) -> BinaryHeap> { // 从第 k+1 个元素开始,保持堆的长度为 k for &num in nums.iter().skip(k) { // 若当前元素大于堆顶元素,则将堆顶元素出堆、当前元素入堆 - if num > heap.peek().unwrap().0 { + let Some(&Reverse(peek)) = heap.peek() else { + // 空堆已提前返回,此处不可达 + unreachable!() + }; + if num > peek { heap.pop(); heap.push(Reverse(num)); } @@ -33,7 +40,11 @@ fn main() { let nums = vec![1, 7, 6, 3, 2]; let k = 3; - let res = top_k_heap(nums, k); - println!("最大的 {} 个元素为", k); - print_util::print_heap(res.into_iter().map(|item| item.0).collect()); + let res = top_k_heap(nums, k) + .iter() + .map(|val| val.0) // Reverse 没有实现 std::fmt::Display + .collect::>(); + println!("最大的 {k} 个元素为"); + println!("数组表示:{}", res.display_as_array()); + println!("树状表示:\n{}", res.display_as_tree()); } From 749b3f8e24c4c391bdda5532265561207e0ef5d3 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:05:56 +0800 Subject: [PATCH 062/109] refactor: change matrix element type to `bool` --- .../chapter_graph/graph_adjacency_matrix.rs | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/codes/rust/chapter_graph/graph_adjacency_matrix.rs b/codes/rust/chapter_graph/graph_adjacency_matrix.rs index 6770526702..ec9071f089 100644 --- a/codes/rust/chapter_graph/graph_adjacency_matrix.rs +++ b/codes/rust/chapter_graph/graph_adjacency_matrix.rs @@ -8,16 +8,17 @@ pub struct GraphAdjMat { // 顶点列表,元素代表“顶点值”,索引代表“顶点索引” vertices: Vec, - // 邻接矩阵,行列索引对应“顶点索引” - adj_mat: Vec>, + // 邻接矩阵,元素值代表两顶点是否相邻,行列索引对应“顶点索引” + adj_mat: Vec>, } impl GraphAdjMat { /* 构造方法 */ pub fn new(vertices: Vec, edges: Vec<[usize; 2]>) -> Self { + let capacity = vertices.len(); let mut graph = GraphAdjMat { - vertices: vec![], - adj_mat: vec![], + vertices: Vec::with_capacity(capacity), + adj_mat: Vec::with_capacity(capacity), }; // 添加顶点 for val in vertices { @@ -43,10 +44,10 @@ impl GraphAdjMat { // 向顶点列表中添加新顶点的值 self.vertices.push(val); // 在邻接矩阵中添加一行 - self.adj_mat.push(vec![0; n]); + self.adj_mat.push(vec![false; n]); // 在邻接矩阵中添加一列 for row in self.adj_mat.iter_mut() { - row.push(0); + row.push(false); } } @@ -73,20 +74,19 @@ impl GraphAdjMat { panic!("index error") } // 在无向图中,邻接矩阵关于主对角线对称,即满足 (i, j) == (j, i) - self.adj_mat[i][j] = 1; - self.adj_mat[j][i] = 1; + self.adj_mat[i][j] = true; + self.adj_mat[j][i] = true; } /* 删除边 */ - // 参数 i, j 对应 vertices 元素索引 pub fn remove_edge(&mut self, i: usize, j: usize) { // 参数 i, j 对应 vertices 元素索引 // 索引越界与相等处理 if i >= self.size() || j >= self.size() || i == j { panic!("index error") } - self.adj_mat[i][j] = 0; - self.adj_mat[j][i] = 0; + self.adj_mat[i][j] = false; + self.adj_mat[j][i] = false; } /* 打印邻接矩阵 */ @@ -95,9 +95,18 @@ impl GraphAdjMat { println!("邻接矩阵 ="); println!("["); for row in &self.adj_mat { - println!(" {:?},", row); + let mut iter = row.iter(); + let Some(&first) = iter.next() else { + println!(" [],"); + continue; + }; + print!(" [{}", first as u8); + for &element in iter { + print!(", {}", element as u8); + } + println!("],"); } - println!("]") + println!("]"); } } @@ -108,29 +117,37 @@ fn main() { let vertices = vec![1, 3, 2, 5, 4]; let edges = vec![[0, 1], [0, 3], [1, 2], [2, 3], [2, 4], [3, 4]]; let mut graph = GraphAdjMat::new(vertices, edges); - println!("\n初始化后,图为"); + println!("初始化后,图为"); graph.print(); + println!(); + /* 添加边 */ // 顶点 1, 2 的索引分别为 0, 2 graph.add_edge(0, 2); - println!("\n添加边 1-2 后,图为"); + println!("添加边 1-2 后,图为"); graph.print(); + println!(); + /* 删除边 */ // 顶点 1, 3 的索引分别为 0, 1 graph.remove_edge(0, 1); - println!("\n删除边 1-3 后,图为"); + println!("删除边 1-3 后,图为"); graph.print(); + println!(); + /* 添加顶点 */ graph.add_vertex(6); - println!("\n添加顶点 6 后,图为"); + println!("添加顶点 6 后,图为"); graph.print(); + println!(); + /* 删除顶点 */ // 顶点 3 的索引为 1 graph.remove_vertex(1); - println!("\n删除顶点 3 后,图为"); + println!("删除顶点 3 后,图为"); graph.print(); } From 635504825bd01ba059d03fbad917554f759d3dbc Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:08:27 +0800 Subject: [PATCH 063/109] refactor: decouple binary crates --- codes/rust/chapter_graph/graph_bfs.rs | 33 +++++++++++++++------------ codes/rust/chapter_graph/graph_dfs.rs | 32 ++++++++++++++------------ 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/codes/rust/chapter_graph/graph_bfs.rs b/codes/rust/chapter_graph/graph_bfs.rs index 1d47161d15..69249bec9f 100644 --- a/codes/rust/chapter_graph/graph_bfs.rs +++ b/codes/rust/chapter_graph/graph_bfs.rs @@ -4,12 +4,11 @@ * Author: night-cruise (2586447362@qq.com) */ -mod graph_adjacency_list; - -use graph_adjacency_list::GraphAdjList; -use graph_adjacency_list::{vals_to_vets, vets_to_vals, Vertex}; use std::collections::{HashSet, VecDeque}; +pub type Vertex = i32; +pub type GraphAdjList = hello_algo_rust::graph_adjacency_list::GraphAdjList; + /* 广度优先遍历 */ // 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点 pub fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { @@ -23,16 +22,20 @@ pub fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { que.push_back(start_vet); // 以顶点 vet 为起点,循环直至访问完所有顶点 while let Some(vet) = que.pop_front() { - res.push(vet); // 记录访问顶点 + // 记录访问顶点 + res.push(vet); // 遍历该顶点的所有邻接顶点 - if let Some(adj_vets) = graph.adj_list.get(&vet) { + if let Some(adj_vets) = graph.get(&vet) { for &adj_vet in adj_vets { if visited.contains(&adj_vet) { - continue; // 跳过已被访问的顶点 + // 跳过已被访问的顶点 + continue; } - que.push_back(adj_vet); // 只入队未访问的顶点 - visited.insert(adj_vet); // 标记该顶点已被访问 + // 只入队未访问的顶点 + que.push_back(adj_vet); + // 标记该顶点已被访问 + visited.insert(adj_vet); } } } @@ -43,7 +46,7 @@ pub fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { /* Driver Code */ fn main() { /* 初始化无向图 */ - let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + let v = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let edges = vec![ [v[0], v[1]], [v[0], v[3]], @@ -59,11 +62,13 @@ fn main() { [v[7], v[8]], ]; let graph = GraphAdjList::new(edges); - println!("\n初始化后,图为"); - graph.print(); + println!("初始化后,图为"); + println!("{graph}"); + + println!(); /* 广度优先遍历 */ let res = graph_bfs(graph, v[0]); - println!("\n广度优先遍历(BFS)顶点序列为"); - println!("{:?}", vets_to_vals(res)); + println!("广度优先遍历(BFS)顶点序列为"); + println!("{res:?}"); } diff --git a/codes/rust/chapter_graph/graph_dfs.rs b/codes/rust/chapter_graph/graph_dfs.rs index d01a52ff22..fbd5dac734 100644 --- a/codes/rust/chapter_graph/graph_dfs.rs +++ b/codes/rust/chapter_graph/graph_dfs.rs @@ -4,21 +4,23 @@ * Author: night-cruise (2586447362@qq.com) */ -mod graph_adjacency_list; - -use graph_adjacency_list::GraphAdjList; -use graph_adjacency_list::{vals_to_vets, vets_to_vals, Vertex}; use std::collections::HashSet; +pub type Vertex = i32; +pub type GraphAdjList = hello_algo_rust::graph_adjacency_list::GraphAdjList; + /* 深度优先遍历辅助函数 */ fn dfs(graph: &GraphAdjList, visited: &mut HashSet, res: &mut Vec, vet: Vertex) { - res.push(vet); // 记录访问顶点 - visited.insert(vet); // 标记该顶点已被访问 - // 遍历该顶点的所有邻接顶点 - if let Some(adj_vets) = graph.adj_list.get(&vet) { + // 记录访问顶点 + res.push(vet); + // 标记该顶点已被访问 + visited.insert(vet); + // 遍历该顶点的所有邻接顶点 + if let Some(adj_vets) = graph.get(&vet) { for &adj_vet in adj_vets { if visited.contains(&adj_vet) { - continue; // 跳过已被访问的顶点 + // 跳过已被访问的顶点 + continue; } // 递归访问邻接顶点 dfs(graph, visited, res, adj_vet); @@ -41,7 +43,7 @@ pub fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { /* Driver Code */ fn main() { /* 初始化无向图 */ - let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6]); + let v = [0, 1, 2, 3, 4, 5, 6]; let edges = vec![ [v[0], v[1]], [v[0], v[3]], @@ -51,11 +53,13 @@ fn main() { [v[5], v[6]], ]; let graph = GraphAdjList::new(edges); - println!("\n初始化后,图为"); - graph.print(); + println!("初始化后,图为"); + println!("{graph}"); + + println!(); /* 深度优先遍历 */ let res = graph_dfs(graph, v[0]); - println!("\n深度优先遍历(DFS)顶点序列为"); - println!("{:?}", vets_to_vals(res)); + println!("深度优先遍历(DFS)顶点序列为"); + println!("{res:?}"); } From 0e11434e1ddd1111cb11be24e28edf2845859805 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:11:43 +0800 Subject: [PATCH 064/109] refactor: change neighbor list to `HashSet` --- .../chapter_graph/graph_adjacency_list.rs | 127 +++++++++++------- 1 file changed, 78 insertions(+), 49 deletions(-) diff --git a/codes/rust/chapter_graph/graph_adjacency_list.rs b/codes/rust/chapter_graph/graph_adjacency_list.rs index 4fc6321671..dcab866499 100644 --- a/codes/rust/chapter_graph/graph_adjacency_list.rs +++ b/codes/rust/chapter_graph/graph_adjacency_list.rs @@ -4,98 +4,119 @@ * Author: night-cruise (2586447362@qq.com) */ -pub use hello_algo_rust::include::{vals_to_vets, vets_to_vals, Vertex}; +use std::collections::{HashMap, HashSet}; -use std::collections::HashMap; +pub type Vertex = i32; /* 基于邻接表实现的无向图类型 */ pub struct GraphAdjList { - // 邻接表,key:顶点,value:该顶点的所有邻接顶点 - pub adj_list: HashMap>, // maybe HashSet for value part is better? + // 邻接表,key: 顶点,value: 该顶点的所有邻接顶点 + // 这里不使用 Vec,因为 HashSet 可以自动去重,且添加和删除顶点的时间复杂度为 O(1)。 + // 而使用 Vec 时,如果不去重,添加顶点的时间复杂度为 O(1),但空间开销会增大,如果去重, + // 添加顶点的时间复杂度为 O(n),不管哪种情况,其删除顶点的时间复杂度都为 O(n)。 + adj_list: HashMap>, } impl GraphAdjList { /* 构造方法 */ pub fn new(edges: Vec<[Vertex; 2]>) -> Self { - let mut graph = GraphAdjList { - adj_list: HashMap::new(), - }; + let adj_list = HashMap::new(); + let mut graph = Self { adj_list }; // 添加所有顶点和边 - for edge in edges { - graph.add_vertex(edge[0]); - graph.add_vertex(edge[1]); - graph.add_edge(edge[0], edge[1]); + for [vet1, vet2] in edges { + // 添加边的时候会自动添加顶点 + graph.add_edge(vet1, vet2); } - graph } /* 获取顶点数量 */ - #[allow(unused)] pub fn size(&self) -> usize { self.adj_list.len() } + /* 获取顶点的所有邻居的引用 */ + pub fn get(&self, vet: &Vertex) -> Option<&HashSet> { + self.adj_list.get(vet) + } + + /* 获取顶点的所有邻居的可变引用 */ + pub fn get_mut(&mut self, vet: &Vertex) -> Option<&mut HashSet> { + self.adj_list.get_mut(vet) + } + /* 添加边 */ pub fn add_edge(&mut self, vet1: Vertex, vet2: Vertex) { if vet1 == vet2 { - panic!("value error"); + // 相等时不应视为错误,而应视为 noop + return; } // 添加边 vet1 - vet2 - self.adj_list.entry(vet1).or_default().push(vet2); - self.adj_list.entry(vet2).or_default().push(vet1); + self.adj_list.entry(vet1).or_default().insert(vet2); + self.adj_list.entry(vet2).or_default().insert(vet1); } /* 删除边 */ - #[allow(unused)] - pub fn remove_edge(&mut self, vet1: Vertex, vet2: Vertex) { + pub fn remove_edge(&mut self, vet1: &Vertex, vet2: &Vertex) { if vet1 == vet2 { - panic!("value error"); + return; } // 删除边 vet1 - vet2 - self.adj_list - .entry(vet1) - .and_modify(|v| v.retain(|&e| e != vet2)); - self.adj_list - .entry(vet2) - .and_modify(|v| v.retain(|&e| e != vet1)); + if let Some(neighbors) = self.adj_list.get_mut(vet1) { + neighbors.remove(vet2); + } + if let Some(neighbors) = self.adj_list.get_mut(vet2) { + neighbors.remove(vet1); + } } /* 添加顶点 */ pub fn add_vertex(&mut self, vet: Vertex) { - if self.adj_list.contains_key(&vet) { - return; - } // 在邻接表中添加一个新链表 - self.adj_list.insert(vet, vec![]); + self.adj_list.entry(vet).or_default(); } /* 删除顶点 */ - #[allow(unused)] - pub fn remove_vertex(&mut self, vet: Vertex) { + pub fn remove_vertex(&mut self, vet: &Vertex) { // 在邻接表中删除顶点 vet 对应的链表 - self.adj_list.remove(&vet); - // 遍历其他顶点的链表,删除所有包含 vet 的边 - for list in self.adj_list.values_mut() { - list.retain(|&v| v != vet); + if let Some(neighbors) = self.adj_list.remove(vet) { + for neighbor in &neighbors { + // 遍历 vet 的邻居,删除所有包含 vet 的边 + if let Some(neighbors) = self.adj_list.get_mut(neighbor) { + neighbors.remove(vet); + } + } } } /* 打印邻接表 */ pub fn print(&self) { - println!("邻接表 ="); - for (vertex, list) in &self.adj_list { - let list = list.iter().map(|vertex| vertex.val).collect::>(); - println!("{}: {:?},", vertex.val, list); + if self.adj_list.is_empty() { + println!("[]"); + return; + } + println!("["); + for (vet, neighbors) in &self.adj_list { + print!(" {vet}: "); + let mut iter = neighbors.iter(); + let Some(first) = iter.next() else { + println!("[]"); + continue; + }; + print!("[{first}"); + for neighbor in iter { + print!(", {neighbor}"); + } + println!("]"); } + println!("]"); } } /* Driver Code */ -#[allow(unused)] fn main() { /* 初始化无向图 */ - let v = vals_to_vets(vec![1, 3, 2, 5, 4]); + let v = [1, 3, 2, 5, 4]; let edges = vec![ [v[0], v[1]], [v[0], v[3]], @@ -106,30 +127,38 @@ fn main() { ]; let mut graph = GraphAdjList::new(edges); - println!("\n初始化后,图为"); + println!("初始化后,图为"); graph.print(); + println!(); + /* 添加边 */ // 顶点 1, 2 即 v[0], v[2] graph.add_edge(v[0], v[2]); - println!("\n添加边 1-2 后,图为"); + println!("添加边 1-2 后,图为"); graph.print(); + println!(); + /* 删除边 */ // 顶点 1, 3 即 v[0], v[1] - graph.remove_edge(v[0], v[1]); - println!("\n删除边 1-3 后,图为"); + graph.remove_edge(&v[0], &v[1]); + println!("删除边 1-3 后,图为"); graph.print(); + println!(); + /* 添加顶点 */ - let v5 = Vertex { val: 6 }; + let v5 = 6; graph.add_vertex(v5); - println!("\n添加顶点 6 后,图为"); + println!("添加顶点 6 后,图为"); graph.print(); + println!(); + /* 删除顶点 */ // 顶点 3 即 v[1] - graph.remove_vertex(v[1]); - println!("\n删除顶点 3 后,图为"); + graph.remove_vertex(&v[1]); + println!("删除顶点 3 后,图为"); graph.print(); } From 6e448b7432ec39a8375c911324c47f3a43f25c39 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:22:33 +0800 Subject: [PATCH 065/109] refactor: decouple binary crates --- .../chapter_searching/binary_search_edge.rs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/codes/rust/chapter_searching/binary_search_edge.rs b/codes/rust/chapter_searching/binary_search_edge.rs index 7e2e21edcc..42dc543e19 100644 --- a/codes/rust/chapter_searching/binary_search_edge.rs +++ b/codes/rust/chapter_searching/binary_search_edge.rs @@ -4,10 +4,6 @@ * Author: night-cruise (2586447362@qq.com) */ -mod binary_search_insertion; - -use binary_search_insertion::binary_search_insertion; - /* 二分查找最左一个 target */ pub fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 { // 等价于查找 target 的插入点 @@ -34,6 +30,24 @@ pub fn binary_search_right_edge(nums: &[i32], target: i32) -> i32 { j } +// 在之前的代码里,这个函数导入自 binary_search_insertion.rs 文件。 +// 然而,binary_search_insertion.rs 是一个 bin crate,不应被当作 +// 模块使用,这是一种不良实践。为了方便起见,我们将该函数直接复制过来。 +fn binary_search_insertion(nums: &[i32], target: i32) -> i32 { + let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] + while i <= j { + let m = i + (j - i) / 2; + if nums[m as usize] < target { + i = m + 1; + } else if nums[m as usize] > target { + j = m - 1; + } else { + j = m - 1; + } + } + i +} + /* Driver Code */ fn main() { // 包含重复元素的数组 From 41f700447d85f79e33f21c925fa68b144a6bb724 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:22:46 +0800 Subject: [PATCH 066/109] fix: resolve warning Removed: - `clippy::needless_return` --- codes/rust/chapter_searching/binary_search.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codes/rust/chapter_searching/binary_search.rs b/codes/rust/chapter_searching/binary_search.rs index 06a85ff38d..edf37502ab 100644 --- a/codes/rust/chapter_searching/binary_search.rs +++ b/codes/rust/chapter_searching/binary_search.rs @@ -24,7 +24,7 @@ pub fn binary_search(nums: &[i32], target: i32) -> i32 { } } // 未找到目标元素,返回 -1 - return -1; + -1 } /* 二分查找(左闭右开区间) */ @@ -47,7 +47,7 @@ pub fn binary_search_lcro(nums: &[i32], target: i32) -> i32 { } } // 未找到目标元素,返回 -1 - return -1; + -1 } /* Driver Code */ From 16289f14c31ae9565fada40f5d38d52ab06c7517 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:29:26 +0800 Subject: [PATCH 067/109] refactor: decouple binary crates and replace all return types with `Option` Refer to codes/rust/GUIDELINES.md for more information. --- codes/rust/chapter_searching/binary_search.rs | 69 +++++++++------- .../chapter_searching/binary_search_edge.rs | 63 +++++++++------ .../binary_search_insertion.rs | 80 +++++++++++++------ codes/rust/chapter_searching/linear_search.rs | 32 ++++---- 4 files changed, 151 insertions(+), 93 deletions(-) diff --git a/codes/rust/chapter_searching/binary_search.rs b/codes/rust/chapter_searching/binary_search.rs index edf37502ab..366d58c40c 100644 --- a/codes/rust/chapter_searching/binary_search.rs +++ b/codes/rust/chapter_searching/binary_search.rs @@ -4,50 +4,57 @@ * Author: codingonion (coderonion@gmail.com) */ +use std::cmp::Ordering; + /* 二分查找(双闭区间) */ -pub fn binary_search(nums: &[i32], target: i32) -> i32 { +pub fn binary_search(nums: &[i32], target: i32) -> Option { + // 数组为空时,返回 None + if nums.is_empty() { + return None; + } // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 let mut i = 0; - let mut j = nums.len() as i32 - 1; + // 数组不为空,不会发生减法溢出 + let mut j = nums.len() - 1; // 循环,当搜索区间为空时跳出(当 i > j 时为空) while i <= j { - let m = i + (j - i) / 2; // 计算中点索引 m - if nums[m as usize] < target { - // 此情况说明 target 在区间 [m+1, j] 中 - i = m + 1; - } else if nums[m as usize] > target { - // 此情况说明 target 在区间 [i, m-1] 中 - j = m - 1; - } else { + // 计算中点索引 m + let m = i + (j - i) / 2; + match target.cmp(&nums[m]) { + // target 在区间 [i, m - 1] 中 + // 如果 m.checked_sub(1) 返回 None,说明 m == 0, + // 所以 target < nums[0],未找到目标元素,返回 None + Ordering::Less => j = m.checked_sub(1)?, + // target 在区间 [m + 1, j] 中 + Ordering::Greater => i = m + 1, // 找到目标元素,返回其索引 - return m; + Ordering::Equal => return Some(m), } } - // 未找到目标元素,返回 -1 - -1 + // 未找到目标元素,返回 None + None } /* 二分查找(左闭右开区间) */ -pub fn binary_search_lcro(nums: &[i32], target: i32) -> i32 { - // 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 +pub fn binary_search_lcro(nums: &[i32], target: i32) -> Option { + // 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素 + 1 let mut i = 0; - let mut j = nums.len() as i32; + let mut j = nums.len(); // 循环,当搜索区间为空时跳出(当 i = j 时为空) while i < j { - let m = i + (j - i) / 2; // 计算中点索引 m - if nums[m as usize] < target { - // 此情况说明 target 在区间 [m+1, j) 中 - i = m + 1; - } else if nums[m as usize] > target { - // 此情况说明 target 在区间 [i, m) 中 - j = m; - } else { + // 计算中点索引 m + let m = i + (j - i) / 2; + match target.cmp(&nums[m]) { + // target 在区间 [i, m) 中 + Ordering::Less => j = m, + // target 在区间 [m + 1, j) 中 + Ordering::Greater => i = m + 1, // 找到目标元素,返回其索引 - return m; + Ordering::Equal => return Some(m), } } - // 未找到目标元素,返回 -1 - -1 + // 未找到目标元素,返回 None + None } /* Driver Code */ @@ -56,10 +63,10 @@ fn main() { let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; // 二分查找(双闭区间) - let mut index = binary_search(&nums, target); - println!("目标元素 6 的索引 = {index}"); + let index = binary_search(&nums, target); + println!("目标元素 6 的索引 = {index:?}"); // 二分查找(左闭右开区间) - index = binary_search_lcro(&nums, target); - println!("目标元素 6 的索引 = {index}"); + let index = binary_search_lcro(&nums, target); + println!("目标元素 6 的索引 = {index:?}"); } diff --git a/codes/rust/chapter_searching/binary_search_edge.rs b/codes/rust/chapter_searching/binary_search_edge.rs index 42dc543e19..3b385978db 100644 --- a/codes/rust/chapter_searching/binary_search_edge.rs +++ b/codes/rust/chapter_searching/binary_search_edge.rs @@ -4,45 +4,62 @@ * Author: night-cruise (2586447362@qq.com) */ +use std::cmp::Ordering; + /* 二分查找最左一个 target */ -pub fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 { +pub fn binary_search_left_edge(nums: &[i32], target: i32) -> Option { // 等价于查找 target 的插入点 let i = binary_search_insertion(nums, target); - // 未找到 target ,返回 -1 - if i == nums.len() as i32 || nums[i as usize] != target { - return -1; + // 未找到 target ,返回 None + if i == nums.len() || nums[i] != target { + return None; } // 找到 target ,返回索引 i - i + Some(i) } /* 二分查找最右一个 target */ -pub fn binary_search_right_edge(nums: &[i32], target: i32) -> i32 { +pub fn binary_search_right_edge(nums: &[i32], target: i32) -> Option { // 转化为查找最左一个 target + 1 - let i = binary_search_insertion(nums, target + 1); - // j 指向最右一个 target ,i 指向首个大于 target 的元素 + let Some(next) = target.checked_add(1) else { + return nums.len().checked_sub(1); + }; + let i = binary_search_insertion(nums, next); + // i 指向首个大于 target 的元素,如果 i == 0 ,说明数组中不存在 target + if i == 0 { + return None; + } + // j 指向最右一个 target let j = i - 1; - // 未找到 target ,返回 -1 - if j == -1 || nums[j as usize] != target { - return -1; + // 未找到 target ,返回 None + if nums[j] != target { + return None; } // 找到 target ,返回索引 j - j + Some(j) } // 在之前的代码里,这个函数导入自 binary_search_insertion.rs 文件。 // 然而,binary_search_insertion.rs 是一个 bin crate,不应被当作 // 模块使用,这是一种不良实践。为了方便起见,我们将该函数直接复制过来。 -fn binary_search_insertion(nums: &[i32], target: i32) -> i32 { - let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] +fn binary_search_insertion(nums: &[i32], target: i32) -> usize { + if nums.is_empty() { + return 0; + } + let mut i = 0; + let mut j = nums.len() - 1; while i <= j { let m = i + (j - i) / 2; - if nums[m as usize] < target { - i = m + 1; - } else if nums[m as usize] > target { - j = m - 1; - } else { - j = m - 1; + match target.cmp(&nums[m]) { + Ordering::Less => match m.checked_sub(1) { + None => return 0, + Some(v) => j = v, + }, + Ordering::Greater => i = m + 1, + Ordering::Equal => match m.checked_sub(1) { + None => return 0, + Some(v) => j = v, + }, } } i @@ -52,13 +69,13 @@ fn binary_search_insertion(nums: &[i32], target: i32) -> i32 { fn main() { // 包含重复元素的数组 let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; - println!("\n数组 nums = {:?}", nums); + println!("数组 nums = {nums:?}"); // 二分查找左边界和右边界 for target in [6, 7] { let index = binary_search_left_edge(&nums, target); - println!("最左一个元素 {} 的索引为 {}", target, index); + println!("最左一个元素 {target} 的索引为 {index:?}"); let index = binary_search_right_edge(&nums, target); - println!("最右一个元素 {} 的索引为 {}", target, index); + println!("最右一个元素 {target} 的索引为 {index:?}"); } } diff --git a/codes/rust/chapter_searching/binary_search_insertion.rs b/codes/rust/chapter_searching/binary_search_insertion.rs index 67a9d94221..f5dace9b3b 100644 --- a/codes/rust/chapter_searching/binary_search_insertion.rs +++ b/codes/rust/chapter_searching/binary_search_insertion.rs @@ -3,19 +3,34 @@ * Created Time: 2023-08-30 * Author: night-cruise (2586447362@qq.com) */ -#![allow(unused)] + +use std::cmp::Ordering; /* 二分查找插入点(无重复元素) */ -pub fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 { - let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] +pub fn binary_search_insertion_simple(nums: &[i32], target: i32) -> usize { + // 数组为空时,返回索引位置 0 作为插入点 + if nums.is_empty() { + return 0; + } + // 初始化双闭区间 [0, n - 1] + let mut i = 0; + // 数组不为空,不会发生减法溢出 + let mut j = nums.len() - 1; while i <= j { - let m = i + (j - i) / 2; // 计算中点索引 m - if nums[m as usize] < target { - i = m + 1; // target 在区间 [m+1, j] 中 - } else if nums[m as usize] > target { - j = m - 1; // target 在区间 [i, m-1] 中 - } else { - return m; + // 计算中点索引 m + let m = i + (j - i) / 2; + match target.cmp(&nums[m]) { + // target 在区间 [i, m - 1] 中 + Ordering::Less => match m.checked_sub(1) { + // 如果 m.checked_sub(1) 返回 None,说明 m == 0, + // 所以 target < nums[0],返回索引位置 0 作为插入点 + None => return 0, + Some(v) => j = v, + }, + // target 在区间 [m + 1, j] 中 + Ordering::Greater => i = m + 1, + // target 在索引 m 处,返回插入点 m + Ordering::Equal => return m, } } // 未找到 target ,返回插入点 i @@ -23,16 +38,35 @@ pub fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 { } /* 二分查找插入点(存在重复元素) */ -pub fn binary_search_insertion(nums: &[i32], target: i32) -> i32 { - let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] +pub fn binary_search_insertion(nums: &[i32], target: i32) -> usize { + // 数组为空时,返回索引位置 0 作为插入点 + if nums.is_empty() { + return 0; + } + // 初始化双闭区间 [0, n - 1] + let mut i = 0; + // 数组不为空,不会发生减法溢出 + let mut j = nums.len() - 1; while i <= j { - let m = i + (j - i) / 2; // 计算中点索引 m - if nums[m as usize] < target { - i = m + 1; // target 在区间 [m+1, j] 中 - } else if nums[m as usize] > target { - j = m - 1; // target 在区间 [i, m-1] 中 - } else { - j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 + // 计算中点索引 m + let m = i + (j - i) / 2; + match target.cmp(&nums[m]) { + // target 在区间 [i, m - 1] 中 + Ordering::Less => match m.checked_sub(1) { + // 如果 m.checked_sub(1) 返回 None,说明 m == 0, + // 所以 target < nums[0],返回索引位置 0 作为插入点 + None => return 0, + Some(v) => j = v, + }, + // target 在区间 [m + 1, j] 中 + Ordering::Greater => i = m + 1, + // 索引 m 处存在 target,继续向左查找索引最小的 target + Ordering::Equal => match m.checked_sub(1) { + // 如果 m.checked_sub(1) 返回 None,说明 m == 0, + // 所以最左 target 在数组起点,返回索引位置 0 作为插入点 + None => return 0, + Some(v) => j = v, + }, } } // 返回插入点 i @@ -43,19 +77,19 @@ pub fn binary_search_insertion(nums: &[i32], target: i32) -> i32 { fn main() { // 无重复元素的数组 let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; - println!("\n数组 nums = {:?}", nums); + println!("数组 nums = {nums:?}"); // 二分查找插入点 for target in [6, 9] { let index = binary_search_insertion_simple(&nums, target); - println!("元素 {} 的插入点的索引为 {}", target, index); + println!("元素 {target} 的插入点的索引为 {index}"); } // 包含重复元素的数组 let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; - println!("\n数组 nums = {:?}", nums); + println!("数组 nums = {nums:?}"); // 二分查找插入点 for target in [2, 6, 20] { let index = binary_search_insertion(&nums, target); - println!("元素 {} 的插入点的索引为 {}", target, index); + println!("元素 {target} 的插入点的索引为 {index}"); } } diff --git a/codes/rust/chapter_searching/linear_search.rs b/codes/rust/chapter_searching/linear_search.rs index 63d6521109..25a290c3c5 100644 --- a/codes/rust/chapter_searching/linear_search.rs +++ b/codes/rust/chapter_searching/linear_search.rs @@ -4,38 +4,38 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::ListNode; +use hello_algo_rust::linked_list::{LinkedList, ListLink, ListNode}; use std::cell::RefCell; use std::rc::Rc; /* 线性查找(数组) */ -pub fn linear_search_array(nums: &[i32], target: i32) -> i32 { +pub fn linear_search_array(nums: &[i32], target: i32) -> Option { // 遍历数组 - for (i, num) in nums.iter().enumerate() { + for (i, &num) in nums.iter().enumerate() { // 找到目标元素,返回其索引 - if num == &target { - return i as i32; + if num == target { + return Some(i); } } - // 未找到目标元素,返回 -1 - return -1; + // 未找到目标元素,返回 None + None } /* 线性查找(链表) */ pub fn linear_search_linked_list( - head: Rc>>, + head: &Rc>>, target: i32, ) -> Option>>> { // 找到目标节点,返回之 if head.borrow().val == target { - return Some(head); + return Some(Rc::clone(head)); }; // 找到目标节点,返回之 - if let Some(node) = &head.borrow_mut().next { - return linear_search_linked_list(node.clone(), target); + if let Some(node) = &head.borrow().next { + return linear_search_linked_list(node, target); } // 未找到目标节点,返回 None - return None; + None } /* Driver Code */ @@ -45,10 +45,10 @@ fn main() { /* 在数组中执行线性查找 */ let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; let index = linear_search_array(&nums, target); - println!("目标元素 3 的索引 = {}", index); + println!("目标元素 3 的索引 = {index:?}"); /* 在链表中执行线性查找 */ - let head = ListNode::arr_to_linked_list(&nums); - let node = linear_search_linked_list(head.unwrap(), target); - println!("目标节点值 3 的对应节点对象为 {:?}", node); + let head = ListLink::try_from_array(nums).unwrap(); + let node = linear_search_linked_list(&head, target); + println!("目标节点值 3 的对应节点对象为 {node:?}"); } From 4f05b1776a15b953538ba96271d48d0e54de74b6 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:30:55 +0800 Subject: [PATCH 068/109] fix: resolve warning Removed: - `clippy::needless_lifetimes` --- .../rust/chapter_searching/hashing_search.rs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/codes/rust/chapter_searching/hashing_search.rs b/codes/rust/chapter_searching/hashing_search.rs index 891e675099..80bf8a15bf 100644 --- a/codes/rust/chapter_searching/hashing_search.rs +++ b/codes/rust/chapter_searching/hashing_search.rs @@ -4,15 +4,15 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::ListNode; +use hello_algo_rust::linked_list::{LinkedList, ListNode}; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; /* 哈希查找(数组) */ -pub fn hashing_search_array<'a>(map: &'a HashMap, target: i32) -> Option<&'a usize> { +pub fn hashing_search_array(map: &HashMap, target: i32) -> Option<&usize> { // 哈希表的 key: 目标元素,value: 索引 - // 若哈希表中无此 key ,返回 None + // 若哈希表中无此 key,返回 None map.get(&target) } @@ -22,7 +22,7 @@ pub fn hashing_search_linked_list( target: i32, ) -> Option<&Rc>>> { // 哈希表的 key: 目标节点值,value: 节点对象 - // 若哈希表中无此 key ,返回 None + // 若哈希表中无此 key,返回 None map.get(&target) } @@ -34,17 +34,16 @@ fn main() { let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; // 初始化哈希表 let mut map = HashMap::new(); - for (i, num) in nums.iter().enumerate() { - map.insert(*num, i); // key: 元素,value: 索引 + for (i, &num) in nums.iter().enumerate() { + map.insert(num, i); // key: 元素,value: 索引 } - let index = hashing_search_array(&map, target); - println!("目标元素 3 的索引 = {}", index.unwrap()); + let index = hashing_search_array(&map, target).unwrap(); + println!("目标元素 3 的索引 = {index}"); /* 哈希查找(链表) */ - let head = ListNode::arr_to_linked_list(&nums); + let head = ListNode::try_from_array(nums).unwrap(); // 初始化哈希表 - // let mut map1 = HashMap::new(); - let map1 = ListNode::linked_list_to_hashmap(head); + let map1 = HashMap::from(head); let node = hashing_search_linked_list(&map1, target); - println!("目标节点值 3 的对应节点对象为 {:?}", node); + println!("目标节点值 3 的对应节点对象为 {node:?}"); } From 555c99f99b886d425f418361ae2957dadd7ac725 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:34:03 +0800 Subject: [PATCH 069/109] fix: resolve warning Removed: - `clippy::ptr_arg` --- codes/rust/chapter_searching/two_sum.rs | 29 +++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/codes/rust/chapter_searching/two_sum.rs b/codes/rust/chapter_searching/two_sum.rs index 5f38d372ab..a0d3aac6eb 100644 --- a/codes/rust/chapter_searching/two_sum.rs +++ b/codes/rust/chapter_searching/two_sum.rs @@ -4,17 +4,16 @@ * Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; use std::collections::HashMap; /* 方法一:暴力枚举 */ -pub fn two_sum_brute_force(nums: &Vec, target: i32) -> Option> { +pub fn two_sum_brute_force(nums: &[i32], target: i32) -> Option<[usize; 2]> { let size = nums.len(); // 两层循环,时间复杂度为 O(n^2) - for i in 0..size - 1 { - for j in i + 1..size { + for i in 0..(size - 1) { + for j in (i + 1)..size { if nums[i] + nums[j] == target { - return Some(vec![i as i32, j as i32]); + return Some([i, j]); } } } @@ -22,31 +21,29 @@ pub fn two_sum_brute_force(nums: &Vec, target: i32) -> Option> { } /* 方法二:辅助哈希表 */ -pub fn two_sum_hash_table(nums: &Vec, target: i32) -> Option> { +pub fn two_sum_hash_table(nums: &[i32], target: i32) -> Option<[usize; 2]> { // 辅助哈希表,空间复杂度为 O(n) let mut dic = HashMap::new(); // 单层循环,时间复杂度为 O(n) for (i, num) in nums.iter().enumerate() { - match dic.get(&(target - num)) { - Some(v) => return Some(vec![*v as i32, i as i32]), - None => dic.insert(num, i as i32), - }; + if let Some(&j) = dic.get(&(target - num)) { + // j 在前以确保增序输出 + return Some([j, i]); + } + dic.insert(num, i); } None } +/* Driver Code */ fn main() { - // ======= Test Case ======= let nums = vec![2, 7, 11, 15]; let target = 13; - // ====== Driver Code ====== // 方法一 let res = two_sum_brute_force(&nums, target).unwrap(); - print!("方法一 res = "); - print_util::print_array(&res); + println!("方法一 res = {res:?}"); // 方法二 let res = two_sum_hash_table(&nums, target).unwrap(); - print!("\n方法二 res = "); - print_util::print_array(&res); + println!("方法二 res = {res:?}"); } From 9c44cdbcc98e90fe6615736ceb16120819f86ad1 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:38:37 +0800 Subject: [PATCH 070/109] refactor: adjust comments and simplify formatted output logic --- codes/rust/chapter_sorting/bubble_sort.rs | 23 ++++++++++---------- codes/rust/chapter_sorting/selection_sort.rs | 12 +++++----- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/codes/rust/chapter_sorting/bubble_sort.rs b/codes/rust/chapter_sorting/bubble_sort.rs index 9ac4615511..f4baaf6e21 100644 --- a/codes/rust/chapter_sorting/bubble_sort.rs +++ b/codes/rust/chapter_sorting/bubble_sort.rs @@ -4,8 +4,6 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::print_util; - /* 冒泡排序 */ pub fn bubble_sort(nums: &mut [i32]) { // 外循环:未排序区间为 [0, i] @@ -24,18 +22,21 @@ pub fn bubble_sort(nums: &mut [i32]) { pub fn bubble_sort_with_flag(nums: &mut [i32]) { // 外循环:未排序区间为 [0, i] for i in (1..nums.len()).rev() { - let mut flag = false; // 初始化标志位 + // 初始化标志位 + let mut flag = false; // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in 0..i { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] nums.swap(j, j + 1); - flag = true; // 记录交换元素 + // 记录交换元素 + flag = true; } } if !flag { - break; // 此轮“冒泡”未交换任何元素,直接跳出 - }; + // 此轮“冒泡”未交换任何元素,直接跳出 + break; + } } } @@ -43,11 +44,9 @@ pub fn bubble_sort_with_flag(nums: &mut [i32]) { fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; bubble_sort(&mut nums); - print!("冒泡排序完成后 nums = "); - print_util::print_array(&nums); + println!("冒泡排序完成后 nums = {nums:?}"); - let mut nums1 = [4, 1, 3, 1, 5, 2]; - bubble_sort_with_flag(&mut nums1); - print!("\n冒泡排序完成后 nums1 = "); - print_util::print_array(&nums1); + let mut nums = [4, 1, 3, 1, 5, 2]; + bubble_sort_with_flag(&mut nums); + println!("冒泡排序完成后 nums = {nums:?}"); } diff --git a/codes/rust/chapter_sorting/selection_sort.rs b/codes/rust/chapter_sorting/selection_sort.rs index ab75b67e24..779106f55a 100644 --- a/codes/rust/chapter_sorting/selection_sort.rs +++ b/codes/rust/chapter_sorting/selection_sort.rs @@ -4,8 +4,6 @@ * Author: WSL0809 (wslzzy@outlook.com) */ -use hello_algo_rust::include::print_util; - /* 选择排序 */ pub fn selection_sort(nums: &mut [i32]) { if nums.is_empty() { @@ -13,12 +11,13 @@ pub fn selection_sort(nums: &mut [i32]) { } let n = nums.len(); // 外循环:未排序区间为 [i, n-1] - for i in 0..n - 1 { + for i in 0..(n - 1) { // 内循环:找到未排序区间内的最小元素 let mut k = i; - for j in i + 1..n { + for j in (i + 1)..n { if nums[j] < nums[k] { - k = j; // 记录最小元素的索引 + // 记录最小元素的索引 + k = j; } } // 将该最小元素与未排序区间的首个元素交换 @@ -30,6 +29,5 @@ pub fn selection_sort(nums: &mut [i32]) { fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; selection_sort(&mut nums); - print!("\n选择排序完成后 nums = "); - print_util::print_array(&nums); + println!("选择排序完成后 nums = {nums:?}"); } From 4b4a9ad4d792070132c2244d21780257132705ab Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:40:00 +0800 Subject: [PATCH 071/109] refactor: replace all index types with `usize` Refer to codes/rust/GUIDELINES.md for more information. --- codes/rust/chapter_sorting/insertion_sort.rs | 25 ++++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/codes/rust/chapter_sorting/insertion_sort.rs b/codes/rust/chapter_sorting/insertion_sort.rs index e433f5c9a2..4b916a77bc 100644 --- a/codes/rust/chapter_sorting/insertion_sort.rs +++ b/codes/rust/chapter_sorting/insertion_sort.rs @@ -4,19 +4,25 @@ * Author: xBLACKICEx (xBLACKICEx@outlook.com) */ -use hello_algo_rust::include::print_util; - /* 插入排序 */ pub fn insertion_sort(nums: &mut [i32]) { // 外循环:已排序区间为 [0, i-1] for i in 1..nums.len() { - let (base, mut j) = (nums[i], (i - 1) as i32); - // 内循环:将 base 插入到已排序区间 [0, i-1] 中的正确位置 - while j >= 0 && nums[j as usize] > base { - nums[(j + 1) as usize] = nums[j as usize]; // 将 nums[j] 向右移动一位 - j -= 1; + let base = nums[i]; + let mut j = i - 1; + // 内循环:将 base 插入到已排序区间 [0, i - 1] 中的正确位置 + while nums[j] > base { + // 将 nums[j] 向右移动一位 + nums[j + 1] = nums[j]; + j = j.wrapping_sub(1); + // j 越界回绕,此时 [0, i - 1] 已全部左移, + // 索引 0 处逻辑上留空,可以直接插入 base + if j == usize::MAX { + break; + } } - nums[(j + 1) as usize] = base; // 将 base 赋值到正确位置 + // 将 base 赋值到正确位置 + nums[j.wrapping_add(1)] = base; } } @@ -24,6 +30,5 @@ pub fn insertion_sort(nums: &mut [i32]) { fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; insertion_sort(&mut nums); - print!("插入排序完成后 nums = "); - print_util::print_array(&nums); + println!("插入排序完成后 nums = {nums:?}"); } From 5f58d0e5d3cb6001181d66a0d76518d0f7b7a079 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:42:49 +0800 Subject: [PATCH 072/109] refactor: change method signatures to prevent out-of-bounds errors --- codes/rust/chapter_sorting/quick_sort.rs | 192 +++++++++++++++-------- 1 file changed, 130 insertions(+), 62 deletions(-) diff --git a/codes/rust/chapter_sorting/quick_sort.rs b/codes/rust/chapter_sorting/quick_sort.rs index f521769602..e32145ddef 100644 --- a/codes/rust/chapter_sorting/quick_sort.rs +++ b/codes/rust/chapter_sorting/quick_sort.rs @@ -4,38 +4,62 @@ * Author: xBLACKICEx (xBLACKICE@outlook.com) */ +// 快速排序没有状态,本应实现为函数,此处却为结构体的关联函数(类似于类的静态方法), +// 实属面向对象风味代码。究其原因,当前版本的《Hello 算法》一书中以如下方式链接了 +// 快速排序代码: +// +// [file]{quick_sort}-[class]{quick_sort}-[func]{quick_sort} +// +// 其影响甚广,涉及所有语言的实现,故暂时维持原状。 + /* 快速排序 */ pub struct QuickSort; impl QuickSort { /* 哨兵划分 */ - fn partition(nums: &mut [i32], left: usize, right: usize) -> usize { - // 以 nums[left] 为基准数 - let (mut i, mut j) = (left, right); + fn partition(nums: &mut [i32]) -> usize { + // 以数组最左侧为基准数 + let mut i = 0; + // 注意:目前 nums.len() >= 1 由 Self::quick_sort 保证; + // 作为一个独立的函数,此处应当增加对空数组的处理以提升健壮性, + // 否则应该内联到 Self::quick_sort 中 + let mut j = nums.len() - 1; while i < j { - while i < j && nums[j] >= nums[left] { - j -= 1; // 从右向左找首个小于基准数的元素 + // 从右向左找首个小于基准数的元素 + while i < j && nums[j] >= nums[0] { + j -= 1; } - while i < j && nums[i] <= nums[left] { - i += 1; // 从左向右找首个大于基准数的元素 + // 从左向右找首个大于基准数的元素 + while i < j && nums[i] <= nums[0] { + i += 1; } - nums.swap(i, j); // 交换这两个元素 + // 交换这两个元素 + nums.swap(i, j); } - nums.swap(i, left); // 将基准数交换至两子数组的分界线 - i // 返回基准数的索引 + // 将基准数交换至两子数组的分界线 + nums.swap(i, 0); + // 返回基准数的索引 + i } /* 快速排序 */ - pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) { - // 子数组长度为 1 时终止递归 - if left >= right { + pub fn quick_sort(nums: &mut [i32]) { + // 子数组长度小于等于 1 时终止递归 + if nums.len() <= 1 { return; } // 哨兵划分 - let pivot = Self::partition(nums, left as usize, right as usize) as i32; - // 递归左子数组、右子数组 - Self::quick_sort(left, pivot - 1, nums); - Self::quick_sort(pivot + 1, right, nums); + let pivot = Self::partition(nums); + + // 相比直接传递原数组的切片和左右索引,这里传入子数组切片更安全, + // 因为它不会因为调用者传入错误索引而越界 panic + + // 递归排序左子数组 [0, pivot - 1] + // 注意,这里不能使用 0..=(pivot - 1), 因为 pivot == 0 时 + // 会发生减法溢出(可以通过构造升序序列观察到这一行为) + Self::quick_sort(&mut nums[0..pivot]); + // 递归排序右子数组 [pivot + 1, nums.len() - 1] + Self::quick_sort(&mut nums[(pivot + 1)..]); } } @@ -44,49 +68,71 @@ pub struct QuickSortMedian; impl QuickSortMedian { /* 选取三个候选元素的中位数 */ - fn median_three(nums: &mut [i32], left: usize, mid: usize, right: usize) -> usize { + fn median_three(nums: &mut [i32]) -> usize { + let left = 0; + // 注意:目前 nums.len() >= 1 由 Self::quick_sort 保证; + // 作为一个独立的函数,此处应当增加对空数组的处理以提升健壮性, + // 否则应该内联到 Self::quick_sort 中 + let right = nums.len() - 1; + let mid = right / 2; + let (l, m, r) = (nums[left], nums[mid], nums[right]); if (l <= m && m <= r) || (r <= m && m <= l) { - return mid; // m 在 l 和 r 之间 + // m 在 l 和 r 之间 + return mid; } if (m <= l && l <= r) || (r <= l && l <= m) { - return left; // l 在 m 和 r 之间 + // l 在 r 和 m 之间 + return left; } + // r 在 m 和 l 之间 right } /* 哨兵划分(三数取中值) */ - fn partition(nums: &mut [i32], left: usize, right: usize) -> usize { + fn partition(nums: &mut [i32]) -> usize { // 选取三个候选元素的中位数 - let med = Self::median_three(nums, left, (left + right) / 2, right); + let med = Self::median_three(nums); // 将中位数交换至数组最左端 - nums.swap(left, med); - // 以 nums[left] 为基准数 - let (mut i, mut j) = (left, right); + nums.swap(0, med); + // 以数组最左侧为基准数 + let mut i = 0; + // 注意:目前 nums.len() >= 1 由 Self::quick_sort 保证; + // 作为一个独立的函数,此处应当增加对空数组的处理以提升健壮性, + // 否则应该内联到 Self::quick_sort 中 + let mut j = nums.len() - 1; while i < j { - while i < j && nums[j] >= nums[left] { - j -= 1; // 从右向左找首个小于基准数的元素 + // 从右向左找首个小于基准数的元素 + while i < j && nums[j] >= nums[0] { + j -= 1; } - while i < j && nums[i] <= nums[left] { - i += 1; // 从左向右找首个大于基准数的元素 + // 从左向右找首个大于基准数的元素 + while i < j && nums[i] <= nums[0] { + i += 1; } - nums.swap(i, j); // 交换这两个元素 + // 交换这两个元素 + nums.swap(i, j); } - nums.swap(i, left); // 将基准数交换至两子数组的分界线 - i // 返回基准数的索引 + // 将基准数交换至两子数组的分界线 + nums.swap(i, 0); + // 返回基准数的索引 + i } /* 快速排序 */ - pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) { - // 子数组长度为 1 时终止递归 - if left >= right { + pub fn quick_sort(nums: &mut [i32]) { + // 子数组长度小于等于 1 时终止递归 + if nums.len() <= 1 { return; } // 哨兵划分 - let pivot = Self::partition(nums, left as usize, right as usize) as i32; - // 递归左子数组、右子数组 - Self::quick_sort(left, pivot - 1, nums); - Self::quick_sort(pivot + 1, right, nums); + let pivot = Self::partition(nums); + // 递归排序左子数组 [0, pivot - 1] + // 注意,这里不能使用 left..=(pivot - 1), 因为 pivot == 0 时 + // 会发生减法溢出(可以通过构造等值序列观察到这一行为) + Self::quick_sort(&mut nums[0..pivot]); + // 递归排序右子数组 [pivot + 1, nums.len() - 1] + Self::quick_sort(&mut nums[(pivot + 1)..]); } } @@ -95,35 +141,57 @@ pub struct QuickSortTailCall; impl QuickSortTailCall { /* 哨兵划分 */ - fn partition(nums: &mut [i32], left: usize, right: usize) -> usize { - // 以 nums[left] 为基准数 - let (mut i, mut j) = (left, right); + fn partition(nums: &mut [i32]) -> usize { + // 以数组最左侧为基准数 + let mut i = 0; + // 注意:目前 nums.len() >= 1 由 Self::quick_sort 保证; + // 作为一个独立的函数,此处应当增加对空数组的处理以提升健壮性, + // 否则应该内联到 Self::quick_sort 中 + let mut j = nums.len() - 1; while i < j { - while i < j && nums[j] >= nums[left] { - j -= 1; // 从右向左找首个小于基准数的元素 + // 从右向左找首个小于基准数的元素 + while i < j && nums[j] >= nums[0] { + j -= 1; } - while i < j && nums[i] <= nums[left] { - i += 1; // 从左向右找首个大于基准数的元素 + // 从左向右找首个大于基准数的元素 + while i < j && nums[i] <= nums[0] { + i += 1; } - nums.swap(i, j); // 交换这两个元素 + // 交换这两个元素 + nums.swap(i, j); } - nums.swap(i, left); // 将基准数交换至两子数组的分界线 - i // 返回基准数的索引 + // 将基准数交换至两子数组的分界线 + nums.swap(i, 0); + // 返回基准数的索引 + i } /* 快速排序(递归深度优化) */ - pub fn quick_sort(mut left: i32, mut right: i32, nums: &mut [i32]) { - // 子数组长度为 1 时终止 + pub fn quick_sort(nums: &mut [i32]) { + // 子数组长度小于等于 1 时终止递归 + if nums.len() <= 1 { + return; + } + let mut left = 0; + let mut right = nums.len() - 1; while left < right { // 哨兵划分操作 - let pivot = Self::partition(nums, left as usize, right as usize) as i32; + let pivot = left + Self::partition(&mut nums[left..=right]); // 对两个子数组中较短的那个执行快速排序 if pivot - left < right - pivot { - Self::quick_sort(left, pivot - 1, nums); // 递归排序左子数组 - left = pivot + 1; // 剩余未排序区间为 [pivot + 1, right] + // 递归排序左子数组 [left, pivot - 1] + // 注意,这里不能使用 left..=(pivot - 1), 因为 pivot == 0 时 + // 会发生减法溢出(可以通过构造升序序列观察到这一行为) + Self::quick_sort(&mut nums[left..pivot]); + // 剩余未排序区间为 [pivot + 1, right] + left = pivot + 1; } else { - Self::quick_sort(pivot + 1, right, nums); // 递归排序右子数组 - right = pivot - 1; // 剩余未排序区间为 [left, pivot - 1] + // 递归排序右子数组 [pivot + 1, right] + Self::quick_sort(&mut nums[(pivot + 1)..=right]); + // 剩余未排序区间为 [left, pivot - 1] + // 如果 pivot == 0,则 left == 0,不会进入此分支, + // 所以,此处不会发生减法溢出 + right = pivot - 1; } } } @@ -133,16 +201,16 @@ impl QuickSortTailCall { fn main() { /* 快速排序 */ let mut nums = [2, 4, 1, 0, 3, 5]; - QuickSort::quick_sort(0, (nums.len() - 1) as i32, &mut nums); - println!("快速排序完成后 nums = {:?}", nums); + QuickSort::quick_sort(&mut nums); + println!("快速排序完成后 nums = {nums:?}"); /* 快速排序(中位基准数优化) */ let mut nums = [2, 4, 1, 0, 3, 5]; - QuickSortMedian::quick_sort(0, (nums.len() - 1) as i32, &mut nums); - println!("快速排序(中位基准数优化)完成后 nums = {:?}", nums); + QuickSortMedian::quick_sort(&mut nums); + println!("快速排序(中位基准数优化)完成后 nums = {nums:?}"); /* 快速排序(递归深度优化) */ let mut nums = [2, 4, 1, 0, 3, 5]; - QuickSortTailCall::quick_sort(0, (nums.len() - 1) as i32, &mut nums); - println!("快速排序(递归深度优化)完成后 nums = {:?}", nums); + QuickSortTailCall::quick_sort(&mut nums); + println!("快速排序(递归深度优化)完成后 nums = {nums:?}"); } From d5a50efc2a781a7bb38abb8cc55998cd30c5d1f1 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:44:55 +0800 Subject: [PATCH 073/109] fix: resolve warning Removed: - `clippy::manual_memcpy` --- codes/rust/chapter_sorting/merge_sort.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/codes/rust/chapter_sorting/merge_sort.rs b/codes/rust/chapter_sorting/merge_sort.rs index a97bb3cc64..287cf96b11 100644 --- a/codes/rust/chapter_sorting/merge_sort.rs +++ b/codes/rust/chapter_sorting/merge_sort.rs @@ -35,9 +35,7 @@ fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) { j += 1; } // 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间 - for k in 0..tmp_size { - nums[left + k] = tmp[k]; - } + nums[left..(tmp_size + left)].copy_from_slice(&tmp[..tmp_size]) } /* 归并排序 */ From d65039fdc6bfbb3f5dabc9eb608cb68ba4015bc3 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:45:58 +0800 Subject: [PATCH 074/109] refactor: change method signatures to prevent out-of-bounds errors --- codes/rust/chapter_sorting/merge_sort.rs | 67 ++++++++++++++---------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/codes/rust/chapter_sorting/merge_sort.rs b/codes/rust/chapter_sorting/merge_sort.rs index 287cf96b11..9e92de5295 100644 --- a/codes/rust/chapter_sorting/merge_sort.rs +++ b/codes/rust/chapter_sorting/merge_sort.rs @@ -5,60 +5,69 @@ */ /* 合并左子数组和右子数组 */ -fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) { - // 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right] - // 创建一个临时数组 tmp ,用于存放合并后的结果 - let tmp_size = right - left + 1; - let mut tmp = vec![0; tmp_size]; +fn merge(nums: &mut [i32]) { + // 计算右子数组区间的起始索引 + // 注意:目前 nums.len() >= 1 由 merge_sort 保证; + // 作为一个独立的函数,此处应当增加对空数组的处理以提升健壮性, + // 否则应该内联到 merge_sort 中 + let mid = (nums.len() - 1) / 2; + let right_start = mid + 1; + // 左子数组区间为 [0, mid], 右子数组区间为 [mid + 1, nums.len() - 1] + // 创建一个临时数组 tmp,用于存放合并后的结果 + let mut tmp = Vec::with_capacity(nums.len()); // 初始化左子数组和右子数组的起始索引 - let (mut i, mut j, mut k) = (left, mid + 1, 0); + let mut i = 0; + let mut j = right_start; // 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中 - while i <= mid && j <= right { + while i < right_start && j < nums.len() { if nums[i] <= nums[j] { - tmp[k] = nums[i]; + tmp.push(nums[i]); i += 1; } else { - tmp[k] = nums[j]; + tmp.push(nums[j]); j += 1; } - k += 1; } // 将左子数组和右子数组的剩余元素复制到临时数组中 - while i <= mid { - tmp[k] = nums[i]; - k += 1; + while i < right_start { + tmp.push(nums[i]); i += 1; } - while j <= right { - tmp[k] = nums[j]; - k += 1; + while j < nums.len() { + tmp.push(nums[j]); j += 1; } - // 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间 - nums[left..(tmp_size + left)].copy_from_slice(&tmp[..tmp_size]) + // 将临时数组 tmp 中的元素复制回当前子数组 + nums.copy_from_slice(&tmp); } /* 归并排序 */ -pub fn merge_sort(nums: &mut [i32], left: usize, right: usize) { - // 终止条件 - if left >= right { - return; // 当子数组长度为 1 时终止递归 +pub fn merge_sort(nums: &mut [i32]) { + // 当子数组长度小于等于 1 时终止递归 + if nums.len() <= 1 { + return; } // 划分阶段 - let mid = left + (right - left) / 2; // 计算中点 - merge_sort(nums, left, mid); // 递归左子数组 - merge_sort(nums, mid + 1, right); // 递归右子数组 + // 计算中点 + let mid = (nums.len() - 1) / 2; + + // 相比直接传递原数组的切片和左右索引,这里传入子数组切片更安全, + // 因为它不会因为调用者传入错误索引而越界 panic + + // 递归左子数组 + merge_sort(&mut nums[0..=mid]); + // 递归右子数组 + merge_sort(&mut nums[(mid + 1)..]); // 合并阶段 - merge(nums, left, mid, right); + merge(nums); } /* Driver Code */ fn main() { /* 归并排序 */ let mut nums = [7, 3, 2, 6, 0, 1, 5, 4]; - let right = nums.len() - 1; - merge_sort(&mut nums, 0, right); - println!("归并排序完成后 nums = {:?}", nums); + merge_sort(&mut nums); + println!("归并排序完成后 nums = {nums:?}"); } From 89bd4a5351fc44176ea58a7bca9cf1c3795a6a78 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:47:04 +0800 Subject: [PATCH 075/109] refactor: change method signatures to prevent out-of-bounds errors --- codes/rust/chapter_sorting/heap_sort.rs | 32 ++++++++++++------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/codes/rust/chapter_sorting/heap_sort.rs b/codes/rust/chapter_sorting/heap_sort.rs index 209c9f924c..b086130645 100644 --- a/codes/rust/chapter_sorting/heap_sort.rs +++ b/codes/rust/chapter_sorting/heap_sort.rs @@ -4,44 +4,43 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; - /* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ -fn sift_down(nums: &mut [i32], n: usize, mut i: usize) { +fn sift_down(nums: &mut [i32], mut i: usize) { + let n = nums.len(); loop { - // 判断节点 i, l, r 中值最大的节点,记为 ma + // 判断节点 i, l, r 中值最大的节点,记为 max let l = 2 * i + 1; let r = 2 * i + 2; - let mut ma = i; - if l < n && nums[l] > nums[ma] { - ma = l; + let mut max = i; + if l < n && nums[l] > nums[max] { + max = l; } - if r < n && nums[r] > nums[ma] { - ma = r; + if r < n && nums[r] > nums[max] { + max = r; } // 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出 - if ma == i { + if max == i { break; } // 交换两节点 - nums.swap(i, ma); + nums.swap(i, max); // 循环向下堆化 - i = ma; + i = max; } } /* 堆排序 */ pub fn heap_sort(nums: &mut [i32]) { // 建堆操作:堆化除叶节点以外的其他所有节点 - for i in (0..nums.len() / 2).rev() { - sift_down(nums, nums.len(), i); + for i in (0..(nums.len() / 2)).rev() { + sift_down(nums, i); } // 从堆中提取最大元素,循环 n-1 轮 for i in (1..nums.len()).rev() { // 交换根节点与最右叶节点(交换首元素与尾元素) nums.swap(0, i); // 以根节点为起点,从顶至底进行堆化 - sift_down(nums, i, 0); + sift_down(&mut nums[0..i], 0); } } @@ -49,6 +48,5 @@ pub fn heap_sort(nums: &mut [i32]) { fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; heap_sort(&mut nums); - print!("堆排序完成后 nums = "); - print_util::print_array(&nums); + println!("堆排序完成后 nums = {nums:?}"); } From 5db98b318d529e9b9a34b8c3600ab9d15e6ebf9e Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:50:34 +0800 Subject: [PATCH 076/109] refactor: use `f64::total_cmp`for float sorting to follow best practices --- codes/rust/chapter_sorting/bucket_sort.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/codes/rust/chapter_sorting/bucket_sort.rs b/codes/rust/chapter_sorting/bucket_sort.rs index 3c87e0f0cf..10b4c14f17 100644 --- a/codes/rust/chapter_sorting/bucket_sort.rs +++ b/codes/rust/chapter_sorting/bucket_sort.rs @@ -4,11 +4,12 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; - /* 桶排序 */ pub fn bucket_sort(nums: &mut [f64]) { - // 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素 + // 为了提高健壮性,应遍历并断言所有输入均在 [0, 1) 范围内, + // 此处省略该步骤,假设输入均符合要求 + + // 初始化 k = n / 2 个桶,预期向每个桶分配 2 个元素 let k = nums.len() / 2; let mut buckets = vec![vec![]; k]; // 1. 将数组元素分配到各个桶中 @@ -21,7 +22,7 @@ pub fn bucket_sort(nums: &mut [f64]) { // 2. 对各个桶执行排序 for bucket in &mut buckets { // 使用内置排序函数,也可以替换成其他排序算法 - bucket.sort_by(|a, b| a.partial_cmp(b).unwrap()); + bucket.sort_by(f64::total_cmp); } // 3. 遍历桶合并结果 let mut i = 0; @@ -38,6 +39,5 @@ fn main() { // 设输入数据为浮点数,范围为 [0, 1) let mut nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37]; bucket_sort(&mut nums); - print!("桶排序完成后 nums = "); - print_util::print_array(&nums); + println!("桶排序完成后 nums = {nums:?}"); } From 88de84588f9114c785ff163819944785f97ae977 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 00:58:14 +0800 Subject: [PATCH 077/109] refactor: replace num type with `u32` to prevent invalid inputs --- codes/rust/chapter_sorting/counting_sort.rs | 57 +++++++++++++-------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/codes/rust/chapter_sorting/counting_sort.rs b/codes/rust/chapter_sorting/counting_sort.rs index b59eb2b2cd..f5e84f026e 100644 --- a/codes/rust/chapter_sorting/counting_sort.rs +++ b/codes/rust/chapter_sorting/counting_sort.rs @@ -4,24 +4,30 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; - /* 计数排序 */ // 简单实现,无法用于排序对象 -pub fn counting_sort_naive(nums: &mut [i32]) { +pub fn counting_sort_naive(nums: &mut [u32]) { // 1. 统计数组最大元素 m - let m = *nums.iter().max().unwrap(); + let Some(m) = nums.iter().max().copied() else { + // 数组为空,直接返回 + return; + }; // 2. 统计各数字的出现次数 // counter[num] 代表 num 的出现次数 - let mut counter = vec![0; m as usize + 1]; + // m 过大会导致内存溢出,即使无限内存,当 m == isize::MAX / size_of::() 时 + // 也会发生容量溢出;在 64 位平台,这种情况不会发生,但 32 位及以下平台上可能发生。因此, + // 该实现仅适用于 m 较小的场景。 + let mut counter = vec![0_usize; m as usize + 1]; for &num in nums.iter() { counter[num as usize] += 1; } // 3. 遍历 counter ,将各元素填入原数组 nums let mut i = 0; - for num in 0..m + 1 { - for _ in 0..counter[num as usize] { - nums[i] = num; + for (num, &count) in counter.iter().enumerate() { + for _ in 0..count { + // num 来自合法的 u32 类型,除非当前是 16 位及以下平台(那很罕见了), + // 以下 cast 总是安全的。 + nums[i] = num as u32; i += 1; } } @@ -29,28 +35,41 @@ pub fn counting_sort_naive(nums: &mut [i32]) { /* 计数排序 */ // 完整实现,可排序对象,并且是稳定排序 -pub fn counting_sort(nums: &mut [i32]) { +pub fn counting_sort(nums: &mut [u32]) { // 1. 统计数组最大元素 m - let m = *nums.iter().max().unwrap() as usize; + let Some(m) = nums.iter().max().copied() else { + // 数组为空,直接返回 + return; + }; // 2. 统计各数字的出现次数 // counter[num] 代表 num 的出现次数 - let mut counter = vec![0; m + 1]; + // m 过大会导致内存溢出,即使无限内存,当 m == isize::MAX / size_of::() 时 + // 也会发生容量溢出;在 64 位平台,这种情况不会发生,但 32 位及以下平台上可能发生。因此, + // 该实现仅适用于 m 较小的场景。 + let mut counter = vec![0; m as usize + 1]; for &num in nums.iter() { counter[num as usize] += 1; } // 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引” // 即 counter[num]-1 是 num 在 res 中最后一次出现的索引 - for i in 0..m { + for i in 0..(m as usize) { counter[i + 1] += counter[i]; } // 4. 倒序遍历 nums ,将各元素填入结果数组 res // 初始化数组 res 用于记录结果 let n = nums.len(); let mut res = vec![0; n]; - for i in (0..n).rev() { - let num = nums[i]; - res[counter[num as usize] - 1] = num; // 将 num 放置到对应索引处 - counter[num as usize] -= 1; // 令前缀和自减 1 ,得到下次放置 num 的索引 + // 倒序遍历保证排序稳定性 + for &num in nums.iter().rev() { + // 将 num 放置到对应索引处 + // 这个减法是安全的,因为 counter[num] 不小于 num 的出现次数, + let index = counter[num as usize] - 1; + res[index] = num; + // 令前缀和自减 1 ,得到下次放置 num 的索引 + // 可令 counter[num as usize] = index, + // 但为了代码可读性,保持与前缀和的语义一致, + // 此处使用自减操作 + counter[num as usize] -= 1; } // 使用结果数组 res 覆盖原数组 nums nums.copy_from_slice(&res) @@ -60,11 +79,9 @@ pub fn counting_sort(nums: &mut [i32]) { fn main() { let mut nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; counting_sort_naive(&mut nums); - print!("计数排序(无法排序对象)完成后 nums = "); - print_util::print_array(&nums); + println!("计数排序(无法排序对象)完成后 nums = {nums:?}"); let mut nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; counting_sort(&mut nums1); - print!("\n计数排序完成后 nums1 = "); - print_util::print_array(&nums1); + println!("计数排序完成后 nums1 = {nums1:?}"); } From 34c117ffa357cc4edf5fd3a150bf1361f2d87651 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:05:59 +0800 Subject: [PATCH 078/109] fix: resolve warnings Removed: - `clippy::needless_return` - `clippy::needless_range_loop` - `clippy::into_iter_on_ref` --- codes/rust/chapter_sorting/radix_sort.rs | 43 ++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/codes/rust/chapter_sorting/radix_sort.rs b/codes/rust/chapter_sorting/radix_sort.rs index 91dd069cf7..1e9b69e23e 100644 --- a/codes/rust/chapter_sorting/radix_sort.rs +++ b/codes/rust/chapter_sorting/radix_sort.rs @@ -4,23 +4,26 @@ * Author: night-cruise (2586447362@qq.com) */ -use hello_algo_rust::include::print_util; - /* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */ -fn digit(num: i32, exp: i32) -> usize { +fn digit(num: u32, exp: u32) -> usize { // 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算 - return ((num / exp) % 10) as usize; + ((num / exp) % 10) as usize } /* 计数排序(根据 nums 第 k 位排序) */ -fn counting_sort_digit(nums: &mut [i32], exp: i32) { +fn counting_sort_digit(nums: &mut [u32], exp: u32) { + // 基数排序实际应该使用 2 的幂次,其计算更高效 + // 此处十进制只是为了便于理解 + // 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组 let mut counter = [0; 10]; let n = nums.len(); // 统计 0~9 各数字的出现次数 - for i in 0..n { - let d = digit(nums[i], exp); // 获取 nums[i] 第 k 位,记为 d - counter[d] += 1; // 统计数字 d 的出现次数 + for &num in nums.iter() { + // 获取 num 第 k 位,记为 d + let d = digit(num, exp); + // 统计数字 d 的出现次数 + counter[d] += 1; } // 求前缀和,将“出现个数”转换为“数组索引” for i in 1..10 { @@ -28,20 +31,27 @@ fn counting_sort_digit(nums: &mut [i32], exp: i32) { } // 倒序遍历,根据桶内统计结果,将各元素填入 res let mut res = vec![0; n]; - for i in (0..n).rev() { - let d = digit(nums[i], exp); - let j = counter[d] - 1; // 获取 d 在数组中的索引 j - res[j] = nums[i]; // 将当前元素填入索引 j - counter[d] -= 1; // 将 d 的数量减 1 + // 倒序遍历保证排序稳定性 + for &num in nums.iter().rev() { + let d = digit(num, exp); + // 获取 d 在数组中的索引 i + let i = counter[d] - 1; + // 将当前元素填入索引 i + res[i] = num; + // 将 d 的数量减 1 + counter[d] -= 1; } // 使用结果覆盖原数组 nums nums.copy_from_slice(&res); } /* 基数排序 */ -pub fn radix_sort(nums: &mut [i32]) { +pub fn radix_sort(nums: &mut [u32]) { // 获取数组的最大元素,用于判断最大位数 - let m = *nums.into_iter().max().unwrap(); + let Some(m) = nums.iter().max().copied() else { + // 数组为空,直接返回 + return; + }; // 按照从低位到高位的顺序遍历 let mut exp = 1; while exp <= m { @@ -58,6 +68,5 @@ fn main() { 63832996, ]; radix_sort(&mut nums); - print!("基数排序完成后 nums = "); - print_util::print_array(&nums); + println!("基数排序完成后 nums = {nums:?}"); } From 819aeeae009633eb5be76ccdff696d5fac834098 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:08:43 +0800 Subject: [PATCH 079/109] fix: resolve warning Removed: - `clippy::needless_return` --- .../rust/chapter_divide_and_conquer/binary_search_recur.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs b/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs index 88b0dab33f..0c4843b840 100644 --- a/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs +++ b/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs @@ -13,13 +13,13 @@ fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 { let m: i32 = i + (j - i) / 2; if nums[m as usize] < target { // 递归子问题 f(m+1, j) - return dfs(nums, target, m + 1, j); + dfs(nums, target, m + 1, j) } else if nums[m as usize] > target { // 递归子问题 f(i, m-1) - return dfs(nums, target, i, m - 1); + dfs(nums, target, i, m - 1) } else { // 找到目标元素,返回其索引 - return m; + m } } From 32e6dd68641c7affbbc4141b34da8757ca06e743 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:10:28 +0800 Subject: [PATCH 080/109] refactor: replace all index types with `usize` Refer to codes/rust/GUIDELINES.md for more information. --- .../binary_search_recur.rs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs b/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs index 0c4843b840..05456c6b4b 100644 --- a/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs +++ b/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs @@ -4,29 +4,34 @@ * Author: codingonion (coderonion@gmail.com) */ +use std::cmp::Ordering; + /* 二分查找:问题 f(i, j) */ -fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 { - // 若区间为空,代表无目标元素,则返回 -1 +fn dfs(nums: &[i32], target: i32, i: usize, j: usize) -> Option { + // 若区间为空,代表无目标元素,则返回 None if i > j { - return -1; + return None; } - let m: i32 = i + (j - i) / 2; - if nums[m as usize] < target { - // 递归子问题 f(m+1, j) - dfs(nums, target, m + 1, j) - } else if nums[m as usize] > target { - // 递归子问题 f(i, m-1) - dfs(nums, target, i, m - 1) - } else { + let m = i + (j - i) / 2; + match target.cmp(&nums[m]) { + // 递归子问题 f(i, m - 1) + // 如果 m.checked_sub(1) 返回 None,说明 m == 0, + // 所以 target < nums[0],未找到目标元素,返回 None + Ordering::Less => dfs(nums, target, i, m.checked_sub(1)?), + // 递归子问题 f(m + 1, j) + Ordering::Greater => dfs(nums, target, m + 1, j), // 找到目标元素,返回其索引 - m + Ordering::Equal => Some(m), } } /* 二分查找 */ -pub fn binary_search(nums: &[i32], target: i32) -> i32 { - let n = nums.len() as i32; - // 求解问题 f(0, n-1) +pub fn binary_search(nums: &[i32], target: i32) -> Option { + if nums.is_empty() { + return None; + } + let n = nums.len(); + // 求解问题 f(0, n - 1) dfs(nums, target, 0, n - 1) } @@ -37,5 +42,5 @@ fn main() { // 二分查找(双闭区间) let index = binary_search(&nums, target); - println!("目标元素 6 的索引 = {index}"); + println!("目标元素 6 的索引 = {index:?}"); } From 824b5f2d1ed8b22ad1bec80fa1683204d8554005 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:28:28 +0800 Subject: [PATCH 081/109] refactor: replace all index types with `usize` Refer to codes/rust/GUIDELINES.md for more information. --- .../chapter_divide_and_conquer/build_tree.rs | 67 ++++++++++++++----- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/codes/rust/chapter_divide_and_conquer/build_tree.rs b/codes/rust/chapter_divide_and_conquer/build_tree.rs index 9eeb9cec1c..a0f7f13ce3 100644 --- a/codes/rust/chapter_divide_and_conquer/build_tree.rs +++ b/codes/rust/chapter_divide_and_conquer/build_tree.rs @@ -4,42 +4,74 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, TreeNode}; +use hello_algo_rust::binary_tree::BinaryTree; +use std::cell::RefCell; use std::collections::HashMap; -use std::{cell::RefCell, rc::Rc}; +use std::rc::Rc; + +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* 构建二叉树:分治 */ fn dfs( preorder: &[i32], - inorder_map: &HashMap, - i: i32, - l: i32, - r: i32, + inorder_map: &HashMap, + i: usize, + l: usize, + r: usize, ) -> Option>> { // 子树区间为空时终止 - if r - l < 0 { + if r < l { return None; } + // 初始化根节点 - let root = TreeNode::new(preorder[i as usize]); + let val = preorder[i]; + let root = TreeNode::new(val); + // 查询 m ,从而划分左右子树 - let m = inorder_map.get(&preorder[i as usize]).unwrap(); + let m = inorder_map.get(&val).expect("preorder 与 inorder 不匹配"); + // 子问题:构建左子树 - root.borrow_mut().left = dfs(preorder, inorder_map, i + 1, l, m - 1); + { + let i = i + 1; + // 如果 m == 0,说明左子树区间为空,停止压栈 + if let Some(r) = m.checked_sub(1) { + root.borrow_mut().left = dfs(preorder, inorder_map, i, l, r); + }; + } + // 子问题:构建右子树 - root.borrow_mut().right = dfs(preorder, inorder_map, i + 1 + m - l, m + 1, r); + { + // m 恒大于等于 l ,不会发生减法溢出 + let i = i + 1 + (m - l); + let l = m + 1; + root.borrow_mut().right = dfs(preorder, inorder_map, i, l, r); + } + // 返回根节点 Some(root) } /* 构建二叉树 */ pub fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option>> { + // preorder 和 inorder 要维持如下不变量: + // + // - 长度相等 + // - 元素相同 + // - 各数组都无重复元素 + // + // 为简洁起见,此处不对上述条件进行校验。 + + if inorder.is_empty() { + return None; + } + // 初始化哈希表,存储 inorder 元素到索引的映射 - let mut inorder_map: HashMap = HashMap::new(); + let mut inorder_map: HashMap = HashMap::new(); for i in 0..inorder.len() { - inorder_map.insert(inorder[i], i as i32); + inorder_map.insert(inorder[i], i); } - let root = dfs(preorder, &inorder_map, 0, 0, inorder.len() as i32 - 1); + let root = dfs(preorder, &inorder_map, 0, 0, inorder.len() - 1); root } @@ -47,10 +79,9 @@ pub fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option Date: Fri, 6 Feb 2026 01:28:56 +0800 Subject: [PATCH 082/109] fix: resolve warnings Removed: - `clippy::needless_range_loop` - `clippy::let_and_return` --- .../rust/chapter_divide_and_conquer/build_tree.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/codes/rust/chapter_divide_and_conquer/build_tree.rs b/codes/rust/chapter_divide_and_conquer/build_tree.rs index a0f7f13ce3..2a9b5e6a8f 100644 --- a/codes/rust/chapter_divide_and_conquer/build_tree.rs +++ b/codes/rust/chapter_divide_and_conquer/build_tree.rs @@ -67,12 +67,14 @@ pub fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option = HashMap::new(); - for i in 0..inorder.len() { - inorder_map.insert(inorder[i], i); - } - let root = dfs(preorder, &inorder_map, 0, 0, inorder.len() - 1); - root + let inorder_map: HashMap = inorder + .iter() + .enumerate() + .map(|(index, &value)| (value, index)) + .collect(); + + // inorder.len() > 0,不会发生减法溢出 + dfs(preorder, &inorder_map, 0, 0, inorder.len() - 1) } /* Driver Code */ From 573939beb41e486463b3091fc502e42f967847c5 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:37:24 +0800 Subject: [PATCH 083/109] refactor: replace the type of `i` with `usize` to avoid truncation --- codes/rust/chapter_divide_and_conquer/hanota.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/codes/rust/chapter_divide_and_conquer/hanota.rs b/codes/rust/chapter_divide_and_conquer/hanota.rs index 87a65ed7a1..a10f5089d2 100644 --- a/codes/rust/chapter_divide_and_conquer/hanota.rs +++ b/codes/rust/chapter_divide_and_conquer/hanota.rs @@ -8,30 +8,32 @@ /* 移动一个圆盘 */ fn move_pan(src: &mut Vec, tar: &mut Vec) { + // pan for pancake? i'd prefer donut for at least it has a hole ngl + // 从 src 顶部拿出一个圆盘 - let pan = src.pop().unwrap(); + let pan = src.pop().unwrap_or_else(|| unreachable!()); // 将圆盘放入 tar 顶部 tar.push(pan); } /* 求解汉诺塔问题 f(i) */ -fn dfs(i: i32, src: &mut Vec, buf: &mut Vec, tar: &mut Vec) { +fn dfs(i: usize, src: &mut Vec, buf: &mut Vec, tar: &mut Vec) { // 若 src 只剩下一个圆盘,则直接将其移到 tar if i == 1 { move_pan(src, tar); return; } - // 子问题 f(i-1) :将 src 顶部 i-1 个圆盘借助 tar 移到 buf + // 子问题 f(i - 1): 将 src 顶部 i - 1 个圆盘借助 tar 移到 buf dfs(i - 1, src, tar, buf); - // 子问题 f(1) :将 src 剩余一个圆盘移到 tar + // 子问题 f(1): 将 src 剩余一个圆盘移到 tar move_pan(src, tar); - // 子问题 f(i-1) :将 buf 顶部 i-1 个圆盘借助 src 移到 tar + // 子问题 f(i - 1): 将 buf 顶部 i - 1 个圆盘借助 src 移到 tar dfs(i - 1, buf, src, tar); } /* 求解汉诺塔问题 */ pub fn solve_hanota(A: &mut Vec, B: &mut Vec, C: &mut Vec) { - let n = A.len() as i32; + let n = A.len(); // 将 A 顶部 n 个圆盘借助 B 移到 C dfs(n, A, B, C); } From 961ca9696a3f5cc6e27031ff4d01b9933e091e86 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:42:00 +0800 Subject: [PATCH 084/109] refactor: simplify code and improve consistency --- .../preorder_traversal_i_compact.rs | 41 +++++++-------- .../preorder_traversal_ii_compact.rs | 52 +++++++++---------- .../preorder_traversal_iii_compact.rs | 51 +++++++++--------- 3 files changed, 69 insertions(+), 75 deletions(-) diff --git a/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs b/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs index 1b80c030aa..17b9eee8d1 100644 --- a/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs +++ b/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs @@ -4,38 +4,33 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; -use std::{cell::RefCell, rc::Rc}; +use hello_algo_rust::binary_tree::{BinaryTree, TreeLink}; +use std::cell::RefCell; +use std::rc::Rc; + +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* 前序遍历:例题一 */ -pub fn pre_order(res: &mut Vec>>, root: Option<&Rc>>) { - if root.is_none() { - return; - } - if let Some(node) = root { - if node.borrow().val == 7 { - // 记录解 - res.push(node.clone()); - } - pre_order(res, node.borrow().left.as_ref()); - pre_order(res, node.borrow().right.as_ref()); +pub fn pre_order(res: &mut Vec>>, root: &Option>>) { + let Some(node) = root else { return }; + if node.borrow().val == 7 { + // 记录解 + res.push(node.clone()); } + pre_order(res, &node.borrow().left); + pre_order(res, &node.borrow().right); } /* Driver Code */ fn main() { - let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); - println!("初始化二叉树"); - print_util::print_tree(root.as_ref().unwrap()); + let root = TreeLink::try_from_array([1, 7, 3, 4, 5, 6, 7].map(Some)).ok(); + println!("初始化二叉树\n{}", root.display()); // 前序遍历 let mut res = Vec::new(); - pre_order(&mut res, root.as_ref()); + pre_order(&mut res, &root); - println!("\n输出所有值为 7 的节点"); - let mut vals = Vec::new(); - for node in res { - vals.push(node.borrow().val) - } - println!("{:?}", vals); + println!("输出所有值为 7 的节点"); + let vals = res.iter().map(|node| node.borrow().val).collect::>(); + println!("{vals:?}"); } diff --git a/codes/rust/chapter_backtracking/preorder_traversal_ii_compact.rs b/codes/rust/chapter_backtracking/preorder_traversal_ii_compact.rs index f39f95546f..44b6dba3f2 100644 --- a/codes/rust/chapter_backtracking/preorder_traversal_ii_compact.rs +++ b/codes/rust/chapter_backtracking/preorder_traversal_ii_compact.rs @@ -4,49 +4,47 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; -use std::{cell::RefCell, rc::Rc}; +use hello_algo_rust::binary_tree::{BinaryTree, TreeLink}; +use std::cell::RefCell; +use std::rc::Rc; + +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* 前序遍历:例题二 */ pub fn pre_order( res: &mut Vec>>>, path: &mut Vec>>, - root: Option<&Rc>>, + root: &Option>>, ) { - if root.is_none() { - return; - } - if let Some(node) = root { - // 尝试 - path.push(node.clone()); - if node.borrow().val == 7 { - // 记录解 - res.push(path.clone()); - } - pre_order(res, path, node.borrow().left.as_ref()); - pre_order(res, path, node.borrow().right.as_ref()); - // 回退 - path.pop(); + let Some(node) = root else { return }; + // 尝试 + path.push(node.clone()); + if node.borrow().val == 7 { + // 记录解 + res.push(path.clone()); } + pre_order(res, path, &node.borrow().left); + pre_order(res, path, &node.borrow().right); + // 回退 + path.pop(); } /* Driver Code */ fn main() { - let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); - println!("初始化二叉树"); - print_util::print_tree(root.as_ref().unwrap()); + let root = TreeLink::try_from_array([1, 7, 3, 4, 5, 6, 7].map(Some)).ok(); + println!("初始化二叉树\n{}", root.display()); // 前序遍历 let mut path = Vec::new(); let mut res = Vec::new(); - pre_order(&mut res, &mut path, root.as_ref()); + pre_order(&mut res, &mut path, &root); - println!("\n输出所有根节点到节点 7 的路径"); + println!("输出所有根节点到节点 7 的路径"); for path in res { - let mut vals = Vec::new(); - for node in path { - vals.push(node.borrow().val) - } - println!("{:?}", vals); + let vals = path + .iter() + .map(|node| node.borrow().val) + .collect::>(); + println!("{vals:?}"); } } diff --git a/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs b/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs index b6b9b9ec5b..e3de9208cb 100644 --- a/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs +++ b/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs @@ -4,50 +4,51 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; -use std::{cell::RefCell, rc::Rc}; +use hello_algo_rust::binary_tree::{BinaryTree, TreeLink}; +use std::cell::RefCell; +use std::rc::Rc; + +pub type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* 前序遍历:例题三 */ pub fn pre_order( res: &mut Vec>>>, path: &mut Vec>>, - root: Option<&Rc>>, + root: &Option>>, ) { // 剪枝 - if root.is_none() || root.as_ref().unwrap().borrow().val == 3 { + let Some(node) = root else { return }; + if node.borrow().val == 3 { return; } - if let Some(node) = root { - // 尝试 - path.push(node.clone()); - if node.borrow().val == 7 { - // 记录解 - res.push(path.clone()); - } - pre_order(res, path, node.borrow().left.as_ref()); - pre_order(res, path, node.borrow().right.as_ref()); - // 回退 - path.pop(); + // 尝试 + path.push(node.clone()); + if node.borrow().val == 7 { + // 记录解 + res.push(path.clone()); } + pre_order(res, path, &node.borrow().left); + pre_order(res, path, &node.borrow().right); + // 回退 + path.pop(); } /* Driver Code */ fn main() { - let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); - println!("初始化二叉树"); - print_util::print_tree(root.as_ref().unwrap()); + let root = TreeLink::try_from_array([1, 7, 3, 4, 5, 6, 7].map(Some)).ok(); + println!("初始化二叉树\n{}", root.display()); // 前序遍历 let mut path = Vec::new(); let mut res = Vec::new(); - pre_order(&mut res, &mut path, root.as_ref()); + pre_order(&mut res, &mut path, &root); - println!("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点"); + println!("输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点"); for path in res { - let mut vals = Vec::new(); - for node in path { - vals.push(node.borrow().val) - } - println!("{:?}", vals); + let vals = path + .iter() + .map(|node| node.borrow().val) + .collect::>(); + println!("{vals:?}"); } } From 4870225adbfd101330895f196ce3d59ea8514dc0 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:44:05 +0800 Subject: [PATCH 085/109] refactor: rewrite to conform to template code --- .../preorder_traversal_iii_template.rs | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs b/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs index 1e0426a65d..f365f05630 100644 --- a/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs +++ b/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs @@ -4,85 +4,97 @@ * Author: codingonion (coderonion@gmail.com) */ -use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; -use std::{cell::RefCell, rc::Rc}; +use hello_algo_rust::binary_tree::{BinaryTree, TreeLink}; +use std::cell::RefCell; +use std::rc::Rc; + +type State = Vec; +type Choice = Option>>; +type TreeNode = hello_algo_rust::binary_tree::TreeNode; /* 判断当前状态是否为解 */ -fn is_solution(state: &mut Vec>>) -> bool { - return !state.is_empty() && state.last().unwrap().borrow().val == 7; +fn is_solution(state: &mut State) -> bool { + state + .last() + .and_then(|node| node.as_ref()) + .map(|node| node.borrow().val == 7) + .unwrap_or(false) } /* 记录解 */ -fn record_solution( - state: &mut Vec>>, - res: &mut Vec>>>, -) { +fn record_solution(state: &mut State, res: &mut Vec) { res.push(state.clone()); } /* 判断在当前状态下,该选择是否合法 */ -fn is_valid(_: &mut Vec>>, choice: Option<&Rc>>) -> bool { - return choice.is_some() && choice.unwrap().borrow().val != 3; +fn is_valid(_state: &mut State, choice: Choice) -> bool { + choice + .as_ref() + .map(|node| node.borrow().val != 3) + .unwrap_or(false) } /* 更新状态 */ -fn make_choice(state: &mut Vec>>, choice: Rc>) { +fn make_choice(state: &mut State, choice: Choice) { state.push(choice); } /* 恢复状态 */ -fn undo_choice(state: &mut Vec>>, _: Rc>) { +fn undo_choice(state: &mut State, _choice: Choice) { state.pop(); } /* 回溯算法:例题三 */ -fn backtrack( - state: &mut Vec>>, - choices: &Vec>>>, - res: &mut Vec>>>, -) { - // 检查是否为解 +fn backtrack(state: &mut State, choices: &Vec, res: &mut Vec) { + // 类型别名说明: + // + // type State = Vec; + // type Choice = Option>>; + // + // 注意,这是一套满足《Hello 算法》一书中回溯模板的类型体操, + // 因此存在一些不必要的分支跳转、克隆和析构开销。 + + // 判断是否为解 if is_solution(state) { // 记录解 record_solution(state, res); + // 不再继续搜索 + return; } // 遍历所有选择 - for &choice in choices.iter() { - // 剪枝:检查选择是否合法 - if is_valid(state, choice) { + for choice in choices { + // 剪枝:判断选择是否合法 + if is_valid(state, choice.clone()) { // 尝试:做出选择,更新状态 - make_choice(state, choice.unwrap().clone()); - // 进行下一轮选择 - backtrack( - state, - &vec![ - choice.unwrap().borrow().left.as_ref(), - choice.unwrap().borrow().right.as_ref(), - ], - res, - ); + make_choice(state, choice.clone()); + // 完全按照回溯模板,choices 将会保持不变,除非在 Choice 类型中额外包含一个共享状态; + // 但这属于违背框架语义的 hack,因此暂时手动创建新的 choices 列表。 + let borrow = choice.as_ref().unwrap_or_else(|| unreachable!()).borrow(); + let left = borrow.left.clone(); + let right = borrow.right.clone(); + let choices = &vec![left, right]; + backtrack(state, choices, res); // 回退:撤销选择,恢复到之前的状态 - undo_choice(state, choice.unwrap().clone()); + undo_choice(state, choice.clone()); } } } /* Driver Code */ fn main() { - let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); - println!("初始化二叉树"); - print_util::print_tree(root.as_ref().unwrap()); + let root = TreeLink::try_from_array([1, 7, 3, 4, 5, 6, 7].map(Some)).ok(); + println!("初始化二叉树\n{}", root.display()); // 回溯算法 let mut res = Vec::new(); - backtrack(&mut Vec::new(), &mut vec![root.as_ref()], &mut res); + backtrack(&mut Vec::new(), &vec![root], &mut res); - println!("\n输出所有根节点到节点 7 的路径,要求路径中不包含值为 3 的节点"); + println!("输出所有根节点到节点 7 的路径,要求路径中不包含值为 3 的节点"); for path in res { - let mut vals = Vec::new(); - for node in path { - vals.push(node.borrow().val) - } - println!("{:?}", vals); + let vals = path + .iter() + .map(|node| node.as_ref().unwrap().borrow().val) + .collect::>(); + println!("{vals:?}"); } } From 9ff5ba3b31e4ad57a6836f8cde1764bf5fc637dc Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:46:54 +0800 Subject: [PATCH 086/109] refactor: improve readability --- .../rust/chapter_backtracking/permutations_i.rs | 14 ++++++++------ .../chapter_backtracking/permutations_ii.rs | 17 ++++++++++------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/codes/rust/chapter_backtracking/permutations_i.rs b/codes/rust/chapter_backtracking/permutations_i.rs index 28d2f241c9..00fd8f2b34 100644 --- a/codes/rust/chapter_backtracking/permutations_i.rs +++ b/codes/rust/chapter_backtracking/permutations_i.rs @@ -13,12 +13,12 @@ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: & } // 遍历所有选择 for i in 0..choices.len() { - let choice = choices[i]; // 剪枝:不允许重复选择元素 if !selected[i] { // 尝试:做出选择,更新状态 - selected[i] = true; + let choice = choices[i]; state.push(choice); + selected[i] = true; // 进行下一轮选择 backtrack(state.clone(), choices, selected, res); // 回退:撤销选择,恢复到之前的状态 @@ -30,8 +30,10 @@ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: & /* 全排列 I */ pub fn permutations_i(nums: &mut [i32]) -> Vec> { - let mut res = Vec::new(); // 状态(子集) - backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res); + let state = Vec::new(); + let mut selected = vec![false; nums.len()]; + let mut res = Vec::new(); + backtrack(state, nums, &mut selected, &mut res); res } @@ -41,6 +43,6 @@ fn main() { let res = permutations_i(&mut nums); - println!("输入数组 nums = {:?}", &nums); - println!("所有排列 res = {:?}", &res); + println!("输入数组 nums = {nums:?}"); + println!("所有排列 res = {res:?}"); } diff --git a/codes/rust/chapter_backtracking/permutations_ii.rs b/codes/rust/chapter_backtracking/permutations_ii.rs index d6ad37826a..423abf626f 100644 --- a/codes/rust/chapter_backtracking/permutations_ii.rs +++ b/codes/rust/chapter_backtracking/permutations_ii.rs @@ -14,15 +14,16 @@ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: & return; } // 遍历所有选择 - let mut duplicated = HashSet::::new(); + let mut duplicated = HashSet::new(); for i in 0..choices.len() { let choice = choices[i]; - // 剪枝:不允许重复选择元素 且 不允许重复选择相等元素 + // 剪枝:不允许重复选择相同元素 且 不允许重复选择相等元素 if !selected[i] && !duplicated.contains(&choice) { // 尝试:做出选择,更新状态 - duplicated.insert(choice); // 记录选择过的元素值 - selected[i] = true; + // 记录选择过的元素值 state.push(choice); + selected[i] = true; + duplicated.insert(choice); // 进行下一轮选择 backtrack(state.clone(), choices, selected, res); // 回退:撤销选择,恢复到之前的状态 @@ -34,8 +35,10 @@ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: & /* 全排列 II */ pub fn permutations_ii(nums: &mut [i32]) -> Vec> { + let state = Vec::new(); + let mut selected = vec![false; nums.len()]; let mut res = Vec::new(); - backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res); + backtrack(state, nums, &mut selected, &mut res); res } @@ -45,6 +48,6 @@ fn main() { let res = permutations_ii(&mut nums); - println!("输入数组 nums = {:?}", &nums); - println!("所有排列 res = {:?}", &res); + println!("输入数组 nums = {nums:?}"); + println!("所有排列 res = {res:?}"); } From d8e47e9d73dfcd411bd5fea9f50f4b5054f432ef Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:48:08 +0800 Subject: [PATCH 087/109] refactor: trivial changes --- codes/rust/chapter_backtracking/subset_sum_i.rs | 16 ++++++++++------ .../chapter_backtracking/subset_sum_i_naive.rs | 13 ++++++++----- codes/rust/chapter_backtracking/subset_sum_ii.rs | 16 ++++++++++------ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/codes/rust/chapter_backtracking/subset_sum_i.rs b/codes/rust/chapter_backtracking/subset_sum_i.rs index 755cb09c1a..abb97ccc8a 100644 --- a/codes/rust/chapter_backtracking/subset_sum_i.rs +++ b/codes/rust/chapter_backtracking/subset_sum_i.rs @@ -36,10 +36,14 @@ fn backtrack( /* 求解子集和 I */ pub fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec> { - let mut state = Vec::new(); // 状态(子集) - nums.sort(); // 对 nums 进行排序 - let start = 0; // 遍历起始点 - let mut res = Vec::new(); // 结果列表(子集列表) + // 状态(子集) + let mut state = Vec::new(); + // 对 nums 进行排序 + nums.sort(); + // 遍历起始点 + let start = 0; + // 结果列表(子集列表) + let mut res = Vec::new(); backtrack(&mut state, target, nums, start, &mut res); res } @@ -51,6 +55,6 @@ fn main() { let res = subset_sum_i(&mut nums, target); - println!("输入数组 nums = {:?}, target = {}", &nums, target); - println!("所有和等于 {} 的子集 res = {:?}", target, &res); + println!("输入数组 nums = {nums:?}, target = {target}"); + println!("所有和等于 {target} 的子集 res = {res:?}"); } diff --git a/codes/rust/chapter_backtracking/subset_sum_i_naive.rs b/codes/rust/chapter_backtracking/subset_sum_i_naive.rs index 550fe0b241..a2d64c8ac4 100644 --- a/codes/rust/chapter_backtracking/subset_sum_i_naive.rs +++ b/codes/rust/chapter_backtracking/subset_sum_i_naive.rs @@ -34,9 +34,12 @@ fn backtrack( /* 求解子集和 I(包含重复子集) */ pub fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec> { - let mut state = Vec::new(); // 状态(子集) - let total = 0; // 子集和 - let mut res = Vec::new(); // 结果列表(子集列表) + // 状态(子集) + let mut state = Vec::new(); + // 子集和 + let total = 0; + // 结果列表(子集列表) + let mut res = Vec::new(); backtrack(&mut state, target, total, nums, &mut res); res } @@ -48,7 +51,7 @@ fn main() { let res = subset_sum_i_naive(&nums, target); - println!("输入数组 nums = {:?}, target = {}", &nums, target); - println!("所有和等于 {} 的子集 res = {:?}", target, &res); + println!("输入数组 nums = {nums:?}, target = {target}"); + println!("所有和等于 {target} 的子集 res = {res:?}"); println!("请注意,该方法输出的结果包含重复集合"); } diff --git a/codes/rust/chapter_backtracking/subset_sum_ii.rs b/codes/rust/chapter_backtracking/subset_sum_ii.rs index b88cb0f2c2..822dfdd247 100644 --- a/codes/rust/chapter_backtracking/subset_sum_ii.rs +++ b/codes/rust/chapter_backtracking/subset_sum_ii.rs @@ -41,10 +41,14 @@ fn backtrack( /* 求解子集和 II */ pub fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec> { - let mut state = Vec::new(); // 状态(子集) - nums.sort(); // 对 nums 进行排序 - let start = 0; // 遍历起始点 - let mut res = Vec::new(); // 结果列表(子集列表) + // 状态(子集) + let mut state = Vec::new(); + // 对 nums 进行排序 + nums.sort(); + // 遍历起始点 + let start = 0; + // 结果列表(子集列表) + let mut res = Vec::new(); backtrack(&mut state, target, nums, start, &mut res); res } @@ -56,6 +60,6 @@ fn main() { let res = subset_sum_ii(&mut nums, target); - println!("输入数组 nums = {:?}, target = {}", &nums, target); - println!("所有和等于 {} 的子集 res = {:?}", target, &res); + println!("输入数组 nums = {nums:?}, target = {target}"); + println!("所有和等于 {target} 的子集 res = {res:?}"); } From cc2a684405f86f670d29324192b63eb6858d6b07 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:50:05 +0800 Subject: [PATCH 088/109] perf: eliminate unnecessary heap allocation for strings --- codes/rust/chapter_backtracking/n_queens.rs | 29 ++++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/codes/rust/chapter_backtracking/n_queens.rs b/codes/rust/chapter_backtracking/n_queens.rs index f37e2435f5..66cb5197a6 100644 --- a/codes/rust/chapter_backtracking/n_queens.rs +++ b/codes/rust/chapter_backtracking/n_queens.rs @@ -8,8 +8,8 @@ fn backtrack( row: usize, n: usize, - state: &mut Vec>, - res: &mut Vec>>, + state: &mut Vec>, + res: &mut Vec>>, cols: &mut [bool], diags1: &mut [bool], diags2: &mut [bool], @@ -27,25 +27,28 @@ fn backtrack( // 剪枝:不允许该格子所在列、主对角线、次对角线上存在皇后 if !cols[col] && !diags1[diag1] && !diags2[diag2] { // 尝试:将皇后放置在该格子 - state[row][col] = "Q".into(); + state[row][col] = 'Q'; (cols[col], diags1[diag1], diags2[diag2]) = (true, true, true); // 放置下一行 backtrack(row + 1, n, state, res, cols, diags1, diags2); // 回退:将该格子恢复为空位 - state[row][col] = "#".into(); + state[row][col] = '#'; (cols[col], diags1[diag1], diags2[diag2]) = (false, false, false); } } } /* 求解 n 皇后 */ -pub fn n_queens(n: usize) -> Vec>> { - // 初始化 n*n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位 - let mut state: Vec> = vec![vec!["#".to_string(); n]; n]; - let mut cols = vec![false; n]; // 记录列是否有皇后 - let mut diags1 = vec![false; 2 * n - 1]; // 记录主对角线上是否有皇后 - let mut diags2 = vec![false; 2 * n - 1]; // 记录次对角线上是否有皇后 - let mut res: Vec>> = Vec::new(); +pub fn n_queens(n: usize) -> Vec>> { + // 初始化 n * n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位 + let mut state = vec![vec!['#'; n]; n]; + let mut res = Vec::new(); + // 记录列是否有皇后 + let mut cols = vec![false; n]; + // 记录主对角线上是否有皇后 + let mut diags1 = vec![false; 2 * n - 1]; + // 记录次对角线上是否有皇后 + let mut diags2 = vec![false; 2 * n - 1]; backtrack( 0, @@ -62,7 +65,7 @@ pub fn n_queens(n: usize) -> Vec>> { /* Driver Code */ fn main() { - let n: usize = 4; + let n = 4; let res = n_queens(n); println!("输入棋盘长宽为 {n}"); @@ -70,7 +73,7 @@ fn main() { for state in res.iter() { println!("--------------------"); for row in state.iter() { - println!("{:?}", row); + println!("{row:?}"); } } } From 2591f4203a537847fe33f47b415dfd8dccf3d17a Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:52:36 +0800 Subject: [PATCH 089/109] fix: resolve warning Removed: - `clippy::assign_op_pattern` --- .../chapter_dynamic_programming/climbing_stairs_backtrack.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs index 5637111822..84dfb8eb42 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs @@ -8,7 +8,7 @@ fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) { // 当爬到第 n 阶时,方案数量加 1 if state == n { - res[0] = res[0] + 1; + res[0] += 1; } // 遍历所有选择 for &choice in choices { From 79f744faf79a026fae090d22f1806bd36144c0c0 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 01:59:20 +0800 Subject: [PATCH 090/109] refactor: replace all integer types with `u32` --- .../climbing_stairs_backtrack.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs index 84dfb8eb42..4bb7d69cc5 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs @@ -5,7 +5,7 @@ */ /* 回溯 */ -fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) { +fn backtrack(choices: &[u32], state: u32, n: u32, res: &mut Vec) { // 当爬到第 n 阶时,方案数量加 1 if state == n { res[0] += 1; @@ -23,18 +23,20 @@ fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) { } /* 爬楼梯:回溯 */ -pub fn climbing_stairs_backtrack(n: usize) -> i32 { - let choices = vec![1, 2]; // 可选择向上爬 1 阶或 2 阶 - let state = 0; // 从第 0 阶开始爬 - let mut res = Vec::new(); - res.push(0); // 使用 res[0] 记录方案数量 - backtrack(&choices, state, n as i32, &mut res); +pub fn climbing_stairs_backtrack(n: u32) -> u32 { + // 可选择向上爬 1 阶或 2 阶 + let choices = vec![1, 2]; + // 从第 0 阶开始爬 + let state = 0; + // 使用 res[0] 记录方案数量 + let mut res = vec![0]; + backtrack(&choices, state, n, &mut res); res[0] } /* Driver Code */ fn main() { - let n: usize = 9; + let n = 9; let res = climbing_stairs_backtrack(n); println!("爬 {n} 阶楼梯共有 {res} 种方案"); From 84121e394f2a8bb54807f4c13da162118e6b0e53 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:00:22 +0800 Subject: [PATCH 091/109] perf: eliminate unnecessary heap allocations --- .../climbing_stairs_backtrack.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs index 4bb7d69cc5..2b7c3a4b46 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs @@ -5,10 +5,10 @@ */ /* 回溯 */ -fn backtrack(choices: &[u32], state: u32, n: u32, res: &mut Vec) { +fn backtrack(choices: &[u32], state: u32, n: u32, res: &mut u32) { // 当爬到第 n 阶时,方案数量加 1 if state == n { - res[0] += 1; + *res += 1; } // 遍历所有选择 for &choice in choices { @@ -25,13 +25,13 @@ fn backtrack(choices: &[u32], state: u32, n: u32, res: &mut Vec) { /* 爬楼梯:回溯 */ pub fn climbing_stairs_backtrack(n: u32) -> u32 { // 可选择向上爬 1 阶或 2 阶 - let choices = vec![1, 2]; + let choices = [1, 2]; // 从第 0 阶开始爬 let state = 0; - // 使用 res[0] 记录方案数量 - let mut res = vec![0]; + // 使用 res 记录方案数量 + let mut res = 0; backtrack(&choices, state, n, &mut res); - res[0] + res } /* Driver Code */ From 00a2f3afb83b71b8c74804da4c5c1b089a9de74e Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:02:30 +0800 Subject: [PATCH 092/109] fix: resolve warning Removed: - `clippy::let_and_return` --- codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs index 1c97124c1c..bce3905c9c 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs @@ -11,8 +11,7 @@ fn dfs(i: usize) -> i32 { return i as i32; } // dp[i] = dp[i-1] + dp[i-2] - let count = dfs(i - 1) + dfs(i - 2); - count + dfs(i - 1) + dfs(i - 2) } /* 爬楼梯:搜索 */ From 933b783f4f7f5350470eac9cc75ab1d050a325e5 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:31:07 +0800 Subject: [PATCH 093/109] fix: resolve warning Removed: - `clippy::needless_range_loop` --- .../min_cost_climbing_stairs_dp.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs b/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs index d54d776888..09c05b177a 100644 --- a/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs +++ b/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs @@ -31,10 +31,8 @@ pub fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { return cost[n]; }; let (mut a, mut b) = (cost[1], cost[2]); - for i in 3..=n { - let tmp = b; - b = cmp::min(a, tmp) + cost[i]; - a = tmp; + for c in &cost[3..] { + (a, b) = (b, cmp::min(a, b) + c); } b } From 10d0b0b6d0fb09015238d8923e3592d1ad87042a Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:32:15 +0800 Subject: [PATCH 094/109] refactor: replace all integer types with `u32` --- .../climbing_stairs_constraint_dp.rs | 37 +++++++++++++------ .../climbing_stairs_dfs.rs | 12 +++--- .../climbing_stairs_dfs_mem.rs | 31 ++++++++++------ .../climbing_stairs_dp.rs | 27 +++++++++----- .../min_cost_climbing_stairs_dp.rs | 10 ++--- 5 files changed, 74 insertions(+), 43 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs index 68213d7119..d8956884b7 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs @@ -5,28 +5,43 @@ */ /* 带约束爬楼梯:动态规划 */ -pub fn climbing_stairs_constraint_dp(n: usize) -> i32 { +pub fn climbing_stairs_constraint_dp(n: u32) -> u32 { + // 出于语义考虑,此处令参数和返回值的类型为 u32 而非 usize, + // 因为 u32 是天然的非负整数类型,而 usize 则用于索引和内存 + // 分配,属于抽象层次更低的底层细节。 + if n == 1 || n == 2 { return 1; - }; + } + + // 这里转换为 usize 类型以便于索引访问,这个转换在 32 位及 + // 以上平台是安全且零开销的,但在 16 位及以下平台上可能发生 + // 截断,此时程序不健全,应退而求其次,使用 usize 类型作为参 + // 数和返回值。 + let n = n as usize; + // 初始化 dp 表,用于存储子问题的解 - let mut dp = vec![vec![-1; 3]; n + 1]; + // 内层如果使用数组 [u32; 3] 会浪费 4 个字节的空间,如果使 + // 用 [u32; 2],索引偏移虽然因为编译期求值而没有开销,但可 + // 读性会下降。这里使用元组并令字段 0 为零大小类型,可以节省 + // 空间并保持良好的可读性。 + let mut dp = vec![((), 0, 0); n + 1]; // 初始状态:预设最小子问题的解 - dp[1][1] = 1; - dp[1][2] = 0; - dp[2][1] = 0; - dp[2][2] = 1; + dp[1].1 = 1; + dp[1].2 = 0; + dp[2].1 = 0; + dp[2].2 = 1; // 状态转移:从较小子问题逐步求解较大子问题 for i in 3..=n { - dp[i][1] = dp[i - 1][2]; - dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; + dp[i].1 = dp[i - 1].2; + dp[i].2 = dp[i - 2].1 + dp[i - 2].2; } - dp[n][1] + dp[n][2] + dp[n].1 + dp[n].2 } /* Driver Code */ fn main() { - let n: usize = 9; + let n = 9; let res = climbing_stairs_constraint_dp(n); println!("爬 {n} 阶楼梯共有 {res} 种方案"); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs index bce3905c9c..06a9953109 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs @@ -5,23 +5,23 @@ */ /* 搜索 */ -fn dfs(i: usize) -> i32 { - // 已知 dp[1] 和 dp[2] ,返回之 +fn dfs(i: u32) -> u32 { + // 已知 dp[1] 和 dp[2],返回之 if i == 1 || i == 2 { - return i as i32; + return i; } - // dp[i] = dp[i-1] + dp[i-2] + // dp[i] = dp[i - 1] + dp[i - 2] dfs(i - 1) + dfs(i - 2) } /* 爬楼梯:搜索 */ -pub fn climbing_stairs_dfs(n: usize) -> i32 { +pub fn climbing_stairs_dfs(n: u32) -> u32 { dfs(n) } /* Driver Code */ fn main() { - let n: usize = 9; + let n = 9; let res = climbing_stairs_dfs(n); println!("爬 {n} 阶楼梯共有 {res} 种方案"); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs index e54204ad63..4ebabf17e3 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs @@ -5,32 +5,39 @@ */ /* 记忆化搜索 */ -fn dfs(i: usize, mem: &mut [i32]) -> i32 { - // 已知 dp[1] 和 dp[2] ,返回之 +fn dfs(i: u32, mem: &mut [Option]) -> u32 { + // 已知 dp[1] 和 dp[2],返回之 + // 实际上,这一处理会导致 mem 的前三个元素永远是 None,可以考虑 + // 将 mem 的大小设为 n - 2 并通过偏移索引来访问以节省空间;然而, + // 索引偏移本身存在时间开销,一般我们认为应该用空间换时间,所以这 + // 种优化并不值得。此外,Option 因为对齐原因占据 8 个字节, + // 可以考虑用 u32::MAX 来代表无记录,但这会带来可读性的下降。 if i == 1 || i == 2 { - return i as i32; + return i; } - // 若存在记录 dp[i] ,则直接返回之 - if mem[i] != -1 { - return mem[i]; + + // 若存在记录 dp[i],则直接返回之 + if let Some(count) = mem[i as usize] { + return count; } - // dp[i] = dp[i-1] + dp[i-2] + + // dp[i] = dp[i - 1] + dp[i - 2] let count = dfs(i - 1, mem) + dfs(i - 2, mem); // 记录 dp[i] - mem[i] = count; + mem[i as usize] = Some(count); count } /* 爬楼梯:记忆化搜索 */ -pub fn climbing_stairs_dfs_mem(n: usize) -> i32 { - // mem[i] 记录爬到第 i 阶的方案总数,-1 代表无记录 - let mut mem = vec![-1; n + 1]; +pub fn climbing_stairs_dfs_mem(n: u32) -> u32 { + // mem[i] 记录爬到第 i 阶的方案总数,None 代表无记录 + let mut mem = vec![None; n as usize + 1]; dfs(n, &mut mem) } /* Driver Code */ fn main() { - let n: usize = 9; + let n = 9; let res = climbing_stairs_dfs_mem(n); println!("爬 {n} 阶楼梯共有 {res} 种方案"); diff --git a/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs b/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs index 8863338d3f..2b8352e7a8 100644 --- a/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs +++ b/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs @@ -5,13 +5,24 @@ */ /* 爬楼梯:动态规划 */ -pub fn climbing_stairs_dp(n: usize) -> i32 { +pub fn climbing_stairs_dp(n: u32) -> u32 { + // 出于语义考虑,此处令参数和返回值的类型为 u32 而非 usize, + // 因为 u32 是天然的非负整数类型,而 usize 则用于索引和内存 + // 分配,属于抽象层次更低的底层细节。 + // 已知 dp[1] 和 dp[2] ,返回之 if n == 1 || n == 2 { - return n as i32; + return n; } + + // 这里转换为 usize 类型以便于索引访问,这个转换在 32 位及 + // 以上平台是安全且零开销的,但在 16 位及以下平台上可能发生 + // 截断,此时程序不健全,应退而求其次,使用 usize 类型作为参 + // 数和返回值。 + let n = n as usize; + // 初始化 dp 表,用于存储子问题的解 - let mut dp = vec![-1; n + 1]; + let mut dp = vec![0; n + 1]; // 初始状态:预设最小子问题的解 dp[1] = 1; dp[2] = 2; @@ -23,22 +34,20 @@ pub fn climbing_stairs_dp(n: usize) -> i32 { } /* 爬楼梯:空间优化后的动态规划 */ -pub fn climbing_stairs_dp_comp(n: usize) -> i32 { +pub fn climbing_stairs_dp_comp(n: u32) -> u32 { if n == 1 || n == 2 { - return n as i32; + return n; } let (mut a, mut b) = (1, 2); for _ in 3..=n { - let tmp = b; - b = a + b; - a = tmp; + (a, b) = (b, a + b); } b } /* Driver Code */ fn main() { - let n: usize = 9; + let n = 9; let res = climbing_stairs_dp(n); println!("爬 {n} 阶楼梯共有 {res} 种方案"); diff --git a/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs b/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs index 09c05b177a..f10a5db734 100644 --- a/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs +++ b/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs @@ -7,13 +7,13 @@ use std::cmp; /* 爬楼梯最小代价:动态规划 */ -pub fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 { +pub fn min_cost_climbing_stairs_dp(cost: &[u32]) -> u32 { let n = cost.len() - 1; if n == 1 || n == 2 { return cost[n]; } // 初始化 dp 表,用于存储子问题的解 - let mut dp = vec![-1; n + 1]; + let mut dp = vec![0; n + 1]; // 初始状态:预设最小子问题的解 dp[1] = cost[1]; dp[2] = cost[2]; @@ -25,11 +25,11 @@ pub fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 { } /* 爬楼梯最小代价:空间优化后的动态规划 */ -pub fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { +pub fn min_cost_climbing_stairs_dp_comp(cost: &[u32]) -> u32 { let n = cost.len() - 1; if n == 1 || n == 2 { return cost[n]; - }; + } let (mut a, mut b) = (cost[1], cost[2]); for c in &cost[3..] { (a, b) = (b, cmp::min(a, b) + c); @@ -40,7 +40,7 @@ pub fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { /* Driver Code */ fn main() { let cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1]; - println!("输入楼梯的代价列表为 {:?}", &cost); + println!("输入楼梯的代价列表为 {cost:?}"); let res = min_cost_climbing_stairs_dp(&cost); println!("爬完楼梯的最低代价为 {res}"); From 7c2e9995b016172d7b885b947ffbc7ebe7fa005c Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:37:24 +0800 Subject: [PATCH 095/109] fix: resolve warnings Removed: - `clippy::ptr_arg` - `clippy::assign_op_pattern` Explicitly omitted: - `clippy::needless_range_loop` --- .../rust/chapter_dynamic_programming/min_path_sum.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/min_path_sum.rs b/codes/rust/chapter_dynamic_programming/min_path_sum.rs index 4901238576..5bf614a320 100644 --- a/codes/rust/chapter_dynamic_programming/min_path_sum.rs +++ b/codes/rust/chapter_dynamic_programming/min_path_sum.rs @@ -5,7 +5,7 @@ */ /* 最小路径和:暴力搜索 */ -pub fn min_path_sum_dfs(grid: &Vec>, i: i32, j: i32) -> i32 { +pub fn min_path_sum_dfs(grid: &[Vec], i: i32, j: i32) -> i32 { // 若为左上角单元格,则终止搜索 if i == 0 && j == 0 { return grid[0][0]; @@ -22,7 +22,7 @@ pub fn min_path_sum_dfs(grid: &Vec>, i: i32, j: i32) -> i32 { } /* 最小路径和:记忆化搜索 */ -pub fn min_path_sum_dfs_mem(grid: &Vec>, mem: &mut Vec>, i: i32, j: i32) -> i32 { +pub fn min_path_sum_dfs_mem(grid: &[Vec], mem: &mut Vec>, i: i32, j: i32) -> i32 { // 若为左上角单元格,则终止搜索 if i == 0 && j == 0 { return grid[0][0]; @@ -44,7 +44,7 @@ pub fn min_path_sum_dfs_mem(grid: &Vec>, mem: &mut Vec>, i: i3 } /* 最小路径和:动态规划 */ -pub fn min_path_sum_dp(grid: &Vec>) -> i32 { +pub fn min_path_sum_dp(grid: &[Vec]) -> i32 { let (n, m) = (grid.len(), grid[0].len()); // 初始化 dp 表 let mut dp = vec![vec![0; m]; n]; @@ -67,7 +67,8 @@ pub fn min_path_sum_dp(grid: &Vec>) -> i32 { } /* 最小路径和:空间优化后的动态规划 */ -pub fn min_path_sum_dp_comp(grid: &Vec>) -> i32 { +#[allow(clippy::needless_range_loop)] +pub fn min_path_sum_dp_comp(grid: &[Vec]) -> i32 { let (n, m) = (grid.len(), grid[0].len()); // 初始化 dp 表 let mut dp = vec![0; m]; @@ -79,7 +80,7 @@ pub fn min_path_sum_dp_comp(grid: &Vec>) -> i32 { // 状态转移:其余行 for i in 1..n { // 状态转移:首列 - dp[0] = dp[0] + grid[i][0]; + dp[0] += grid[i][0]; // 状态转移:其余列 for j in 1..m { dp[j] = std::cmp::min(dp[j - 1], dp[j]) + grid[i][j]; From 0411e4c2561a8ee69d469f8f1fcaefeaeb5cfdad Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:39:03 +0800 Subject: [PATCH 096/109] refactor: replace cost type with `u32` and index type with `usize` Refer to codes/rust/GUIDELINES.md for more information. --- .../min_path_sum.rs | 89 ++++++++++++------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/min_path_sum.rs b/codes/rust/chapter_dynamic_programming/min_path_sum.rs index 5bf614a320..0f7c2b10b7 100644 --- a/codes/rust/chapter_dynamic_programming/min_path_sum.rs +++ b/codes/rust/chapter_dynamic_programming/min_path_sum.rs @@ -4,50 +4,75 @@ * Author: codingonion (coderonion@gmail.com) */ +use std::cmp; + /* 最小路径和:暴力搜索 */ -pub fn min_path_sum_dfs(grid: &[Vec], i: i32, j: i32) -> i32 { +pub fn min_path_sum_dfs(grid: &[Vec], i: usize, j: usize) -> u32 { + // 由调用者保证 i 和 j 不越界 + // 若为左上角单元格,则终止搜索 if i == 0 && j == 0 { return grid[0][0]; } - // 若行列索引越界,则返回 +∞ 代价 - if i < 0 || j < 0 { - return i32::MAX; - } - // 计算从左上角到 (i-1, j) 和 (i, j-1) 的最小路径代价 - let up = min_path_sum_dfs(grid, i - 1, j); - let left = min_path_sum_dfs(grid, i, j - 1); + // 左边和上边单元格的最小路径代价 + let up = match i.checked_sub(1) { + // 若行索引越界,则代价为 +∞ + None => u32::MAX, + Some(i) => min_path_sum_dfs(grid, i, j), + }; + let left = match j.checked_sub(1) { + // 若列索引越界,则代价为 +∞ + None => u32::MAX, + Some(j) => min_path_sum_dfs(grid, i, j), + }; // 返回从左上角到 (i, j) 的最小路径代价 - std::cmp::min(left, up) + grid[i as usize][j as usize] + cmp::min(left, up) + grid[i][j] } /* 最小路径和:记忆化搜索 */ -pub fn min_path_sum_dfs_mem(grid: &[Vec], mem: &mut Vec>, i: i32, j: i32) -> i32 { +pub fn min_path_sum_dfs_mem( + grid: &[Vec], + mem: &mut Vec>>, + i: usize, + j: usize, +) -> u32 { + // 由调用者保证 i 和 j 不越界 + // 若为左上角单元格,则终止搜索 if i == 0 && j == 0 { return grid[0][0]; } - // 若行列索引越界,则返回 +∞ 代价 - if i < 0 || j < 0 { - return i32::MAX; - } // 若已有记录,则直接返回 - if mem[i as usize][j as usize] != -1 { - return mem[i as usize][j as usize]; + if let Some(cost) = mem[i][j] { + return cost; } // 左边和上边单元格的最小路径代价 - let up = min_path_sum_dfs_mem(grid, mem, i - 1, j); - let left = min_path_sum_dfs_mem(grid, mem, i, j - 1); + let up = match i.checked_sub(1) { + // 若行索引越界,代价为 +∞ + None => u32::MAX, + Some(i) => min_path_sum_dfs_mem(grid, mem, i, j), + }; + let left = match j.checked_sub(1) { + // 若列索引越界,代价为 +∞ + None => u32::MAX, + Some(j) => min_path_sum_dfs_mem(grid, mem, i, j), + }; // 记录并返回左上角到 (i, j) 的最小路径代价 - mem[i as usize][j as usize] = std::cmp::min(left, up) + grid[i as usize][j as usize]; - mem[i as usize][j as usize] + let cost = cmp::min(left, up) + grid[i][j]; + mem[i][j] = Some(cost); + cost } /* 最小路径和:动态规划 */ -pub fn min_path_sum_dp(grid: &[Vec]) -> i32 { +pub fn min_path_sum_dp(grid: &[Vec]) -> u32 { let (n, m) = (grid.len(), grid[0].len()); + if n == 0 || m == 0 { + // grid 为空,提前返回 + return 0; + } // 初始化 dp 表 let mut dp = vec![vec![0; m]; n]; + // dp 和 grid 保证不为空,此处不会越界 dp[0][0] = grid[0][0]; // 状态转移:首行 for j in 1..m { @@ -60,7 +85,7 @@ pub fn min_path_sum_dp(grid: &[Vec]) -> i32 { // 状态转移:其余行和列 for i in 1..n { for j in 1..m { - dp[i][j] = std::cmp::min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; + dp[i][j] = cmp::min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; } } dp[n - 1][m - 1] @@ -68,12 +93,17 @@ pub fn min_path_sum_dp(grid: &[Vec]) -> i32 { /* 最小路径和:空间优化后的动态规划 */ #[allow(clippy::needless_range_loop)] -pub fn min_path_sum_dp_comp(grid: &[Vec]) -> i32 { +pub fn min_path_sum_dp_comp(grid: &[Vec]) -> u32 { let (n, m) = (grid.len(), grid[0].len()); + if n == 0 || m == 0 { + // grid 为空,提前返回 + return 0; + } // 初始化 dp 表 let mut dp = vec![0; m]; - // 状态转移:首行 + // dp 和 grid 保证不为空,此处不会越界 dp[0] = grid[0][0]; + // 状态转移:首行 for j in 1..m { dp[j] = dp[j - 1] + grid[0][j]; } @@ -83,7 +113,7 @@ pub fn min_path_sum_dp_comp(grid: &[Vec]) -> i32 { dp[0] += grid[i][0]; // 状态转移:其余列 for j in 1..m { - dp[j] = std::cmp::min(dp[j - 1], dp[j]) + grid[i][j]; + dp[j] = cmp::min(dp[j - 1], dp[j]) + grid[i][j]; } } dp[m - 1] @@ -100,15 +130,12 @@ fn main() { let (n, m) = (grid.len(), grid[0].len()); // 暴力搜索 - let res = min_path_sum_dfs(&grid, n as i32 - 1, m as i32 - 1); + let res = min_path_sum_dfs(&grid, n - 1, m - 1); println!("从左上角到右下角的最小路径和为 {res}"); // 记忆化搜索 - let mut mem = vec![vec![0; m]; n]; - for row in mem.iter_mut() { - row.fill(-1); - } - let res = min_path_sum_dfs_mem(&grid, &mut mem, n as i32 - 1, m as i32 - 1); + let mut mem = vec![vec![None; m]; n]; + let res = min_path_sum_dfs_mem(&grid, &mut mem, n - 1, m - 1); println!("从左上角到右下角的最小路径和为 {res}"); // 动态规划 From 7b9a668d683b7a58a2fb956ed89bf2a9aa4257fe Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:42:52 +0800 Subject: [PATCH 097/109] fix: resolve warning Removed: - `clippy::needless_return` - `clippy::self_assignment` --- codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs b/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs index b12d2c7a46..f5bd60ffb3 100644 --- a/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs +++ b/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs @@ -21,7 +21,7 @@ pub fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { } } } - return dp[n][cap]; + dp[n][cap] } /* 完全背包:空间优化后的动态规划 */ @@ -34,7 +34,6 @@ pub fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { for c in 1..=cap { if wgt[i - 1] > c as i32 { // 若超过背包容量,则不选物品 i - dp[c] = dp[c]; } else { // 不选和选物品 i 这两种方案的较大值 dp[c] = std::cmp::max(dp[c], dp[c - wgt[i - 1] as usize] + val[i - 1]); From ce698aab54c8ab120038216ad782c37883550071 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 02:44:45 +0800 Subject: [PATCH 098/109] refactor: replace all integer types except indices with `u32` --- .../chapter_dynamic_programming/knapsack.rs | 73 ++++++++++--------- .../unbounded_knapsack.rs | 38 ++++++---- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/knapsack.rs b/codes/rust/chapter_dynamic_programming/knapsack.rs index c7b38c5199..c465e8f13c 100644 --- a/codes/rust/chapter_dynamic_programming/knapsack.rs +++ b/codes/rust/chapter_dynamic_programming/knapsack.rs @@ -4,91 +4,101 @@ * Author: codingonion (coderonion@gmail.com) */ +use std::cmp; + /* 0-1 背包:暴力搜索 */ -pub fn knapsack_dfs(wgt: &[i32], val: &[i32], i: usize, c: usize) -> i32 { +pub fn knapsack_dfs(wgt: &[u32], val: &[u32], i: usize, c: u32) -> u32 { // 若已选完所有物品或背包无剩余容量,则返回价值 0 if i == 0 || c == 0 { return 0; } // 若超过背包容量,则只能选择不放入背包 - if wgt[i - 1] > c as i32 { + if wgt[i - 1] > c { return knapsack_dfs(wgt, val, i - 1, c); } // 计算不放入和放入物品 i 的最大价值 let no = knapsack_dfs(wgt, val, i - 1, c); - let yes = knapsack_dfs(wgt, val, i - 1, c - wgt[i - 1] as usize) + val[i - 1]; + let yes = knapsack_dfs(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; // 返回两种方案中价值更大的那一个 - std::cmp::max(no, yes) + cmp::max(no, yes) } /* 0-1 背包:记忆化搜索 */ -pub fn knapsack_dfs_mem(wgt: &[i32], val: &[i32], mem: &mut Vec>, i: usize, c: usize) -> i32 { +pub fn knapsack_dfs_mem( + wgt: &[u32], + val: &[u32], + mem: &mut Vec>>, + i: usize, + c: u32, +) -> u32 { // 若已选完所有物品或背包无剩余容量,则返回价值 0 if i == 0 || c == 0 { return 0; } // 若已有记录,则直接返回 - if mem[i][c] != -1 { - return mem[i][c]; + if let Some(max) = mem[i][c as usize] { + return max; } // 若超过背包容量,则只能选择不放入背包 - if wgt[i - 1] > c as i32 { + if wgt[i - 1] > c { return knapsack_dfs_mem(wgt, val, mem, i - 1, c); } // 计算不放入和放入物品 i 的最大价值 let no = knapsack_dfs_mem(wgt, val, mem, i - 1, c); - let yes = knapsack_dfs_mem(wgt, val, mem, i - 1, c - wgt[i - 1] as usize) + val[i - 1]; + let yes = knapsack_dfs_mem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; // 记录并返回两种方案中价值更大的那一个 - mem[i][c] = std::cmp::max(no, yes); - mem[i][c] + let max = cmp::max(no, yes); + mem[i][c as usize] = Some(max); + max } /* 0-1 背包:动态规划 */ -pub fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn knapsack_dp(wgt: &[u32], val: &[u32], cap: u32) -> u32 { let n = wgt.len(); // 初始化 dp 表 - let mut dp = vec![vec![0; cap + 1]; n + 1]; + let mut dp = vec![vec![0; cap as usize + 1]; n + 1]; // 状态转移 for i in 1..=n { for c in 1..=cap { - if wgt[i - 1] > c as i32 { - // 若超过背包容量,则不选物品 i - dp[i][c] = dp[i - 1][c]; - } else { - // 不选和选物品 i 这两种方案的较大值 - dp[i][c] = std::cmp::max( - dp[i - 1][c], - dp[i - 1][c - wgt[i - 1] as usize] + val[i - 1], - ); + // 若超过背包容量,则不选物品 i + if wgt[i - 1] > c { + dp[i][c as usize] = dp[i - 1][c as usize]; + continue; } + // 不选和选物品 i 这两种方案的较大值 + let no = dp[i - 1][c as usize]; + let yes = dp[i - 1][(c - wgt[i - 1]) as usize] + val[i - 1]; + dp[i][c as usize] = cmp::max(no, yes); } } - dp[n][cap] + dp[n][cap as usize] } /* 0-1 背包:空间优化后的动态规划 */ -pub fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn knapsack_dp_comp(wgt: &[u32], val: &[u32], cap: u32) -> u32 { let n = wgt.len(); // 初始化 dp 表 - let mut dp = vec![0; cap + 1]; + let mut dp = vec![0; cap as usize + 1]; // 状态转移 for i in 1..=n { // 倒序遍历 for c in (1..=cap).rev() { - if wgt[i - 1] <= c as i32 { + if wgt[i - 1] <= c { // 不选和选物品 i 这两种方案的较大值 - dp[c] = std::cmp::max(dp[c], dp[c - wgt[i - 1] as usize] + val[i - 1]); + let no = dp[c as usize]; + let yes = dp[(c - wgt[i - 1]) as usize] + val[i - 1]; + dp[c as usize] = cmp::max(no, yes); } } } - dp[cap] + dp[cap as usize] } /* Driver Code */ fn main() { let wgt = [10, 20, 30, 40, 50]; let val = [50, 120, 150, 210, 240]; - let cap: usize = 50; + let cap = 50; let n = wgt.len(); // 暴力搜索 @@ -96,10 +106,7 @@ fn main() { println!("不超过背包容量的最大物品价值为 {res}"); // 记忆搜索 - let mut mem = vec![vec![0; cap + 1]; n + 1]; - for row in mem.iter_mut() { - row.fill(-1); - } + let mut mem = vec![vec![None; cap as usize + 1]; n + 1]; let res = knapsack_dfs_mem(&wgt, &val, &mut mem, n, cap); println!("不超过背包容量的最大物品价值为 {res}"); diff --git a/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs b/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs index f5bd60ffb3..e88f07b4d8 100644 --- a/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs +++ b/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs @@ -4,50 +4,56 @@ * Author: codingonion (coderonion@gmail.com) */ +use std::cmp; + /* 完全背包:动态规划 */ -pub fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn unbounded_knapsack_dp(wgt: &[u32], val: &[u32], cap: u32) -> u32 { let n = wgt.len(); // 初始化 dp 表 - let mut dp = vec![vec![0; cap + 1]; n + 1]; + let mut dp = vec![vec![0; cap as usize + 1]; n + 1]; // 状态转移 for i in 1..=n { for c in 1..=cap { - if wgt[i - 1] > c as i32 { + if wgt[i - 1] > c { // 若超过背包容量,则不选物品 i - dp[i][c] = dp[i - 1][c]; - } else { - // 不选和选物品 i 这两种方案的较大值 - dp[i][c] = std::cmp::max(dp[i - 1][c], dp[i][c - wgt[i - 1] as usize] + val[i - 1]); + dp[i][c as usize] = dp[i - 1][c as usize]; + continue; } + // 不选和选物品 i 这两种方案的较大值 + let no = dp[i - 1][c as usize]; + let yes = dp[i][(c - wgt[i - 1]) as usize] + val[i - 1]; + dp[i][c as usize] = cmp::max(no, yes); } } - dp[n][cap] + dp[n][cap as usize] } /* 完全背包:空间优化后的动态规划 */ -pub fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { +pub fn unbounded_knapsack_dp_comp(wgt: &[u32], val: &[u32], cap: u32) -> u32 { let n = wgt.len(); // 初始化 dp 表 - let mut dp = vec![0; cap + 1]; + let mut dp = vec![0; cap as usize + 1]; // 状态转移 for i in 1..=n { for c in 1..=cap { - if wgt[i - 1] > c as i32 { + if wgt[i - 1] > c { // 若超过背包容量,则不选物品 i - } else { - // 不选和选物品 i 这两种方案的较大值 - dp[c] = std::cmp::max(dp[c], dp[c - wgt[i - 1] as usize] + val[i - 1]); + continue; } + // 不选和选物品 i 这两种方案的较大值 + let no = dp[c as usize]; + let yes = dp[(c - wgt[i - 1]) as usize] + val[i - 1]; + dp[c as usize] = cmp::max(no, yes); } } - dp[cap] + dp[cap as usize] } /* Driver Code */ fn main() { let wgt = [1, 2, 3]; let val = [5, 11, 15]; - let cap: usize = 4; + let cap = 4; // 动态规划 let res = unbounded_knapsack_dp(&wgt, &val, cap); From e9244fc17ff491f0ec115adcecfe9b3b6e96e610 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:00:34 +0800 Subject: [PATCH 099/109] perf: replace strings with char arrays for O(1) access --- .../edit_distance.rs | 211 +++++++++++------- 1 file changed, 134 insertions(+), 77 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/edit_distance.rs b/codes/rust/chapter_dynamic_programming/edit_distance.rs index 0c77b5f365..3e6898f360 100644 --- a/codes/rust/chapter_dynamic_programming/edit_distance.rs +++ b/codes/rust/chapter_dynamic_programming/edit_distance.rs @@ -4,116 +4,178 @@ * Author: codingonion (coderonion@gmail.com) */ +use std::cmp; + /* 编辑距离:暴力搜索 */ -pub fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 { - // 若 s 和 t 都为空,则返回 0 - if i == 0 && j == 0 { - return 0; - } - // 若 s 为空,则返回 t 长度 - if i == 0 { - return j as i32; - } - // 若 t 为空,则返回 s 长度 - if j == 0 { - return i as i32; - } - // 若两字符相等,则直接跳过此两字符 - if s.chars().nth(i - 1) == t.chars().nth(j - 1) { - return edit_distance_dfs(s, t, i - 1, j - 1); +pub fn edit_distance_dfs(s: &str, t: &str) -> usize { + fn dfs(s: &[char], t: &[char], i: usize, j: usize) -> usize { + // 若 s 和 t 都为空,则返回 0 + if i == 0 && j == 0 { + return 0; + } + // 若 s 为空,则返回 t 长度 + if i == 0 { + return j; + } + // 若 t 为空,则返回 s 长度 + if j == 0 { + return i; + } + // 若两字符相等,则直接跳过此两字符 + if s[i - 1] == t[j - 1] { + return dfs(s, t, i - 1, j - 1); + } + // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 + let insert = dfs(s, t, i, j - 1); + let delete = dfs(s, t, i - 1, j); + let replace = dfs(s, t, i - 1, j - 1); + // 返回最少编辑步数 + // 可用 insert.min(delete).min(replace) + 1,但中缀运算符求最小值似乎不够直观。 + cmp::min(cmp::min(insert, delete), replace) + 1 } - // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 - let insert = edit_distance_dfs(s, t, i, j - 1); - let delete = edit_distance_dfs(s, t, i - 1, j); - let replace = edit_distance_dfs(s, t, i - 1, j - 1); - // 返回最少编辑步数 - std::cmp::min(std::cmp::min(insert, delete), replace) + 1 + + // 注意:Rust 字符串是不定长的 UTF-8 序列,无法实现 O(1) 时间内的随机访问; + // 可先将字符串转换为字符数组来优化访问。由于没有扩容需求,这里可以进一步改为 + // 堆数组切片 Box<[char]> 来分别节省一个字宽的空间。 + let s: Vec = s.chars().collect(); + let t: Vec = t.chars().collect(); + + // 注意:不可使用 str::len 获取字符串长度,因为其返回的是字节数而非字符数。 + let n = s.len(); + let m = t.len(); + + dfs(&s, &t, n, m) } /* 编辑距离:记忆化搜索 */ -pub fn edit_distance_dfs_mem(s: &str, t: &str, mem: &mut Vec>, i: usize, j: usize) -> i32 { - // 若 s 和 t 都为空,则返回 0 - if i == 0 && j == 0 { - return 0; - } - // 若 s 为空,则返回 t 长度 - if i == 0 { - return j as i32; - } - // 若 t 为空,则返回 s 长度 - if j == 0 { - return i as i32; - } - // 若已有记录,则直接返回之 - if mem[i][j] != -1 { - return mem[i][j]; - } - // 若两字符相等,则直接跳过此两字符 - if s.chars().nth(i - 1) == t.chars().nth(j - 1) { - return edit_distance_dfs_mem(s, t, mem, i - 1, j - 1); +pub fn edit_distance_dfs_mem(s: &str, t: &str) -> usize { + fn dfs(s: &[char], t: &[char], mem: &mut [Vec>], i: usize, j: usize) -> usize { + // 若 s 和 t 都为空,则返回 0 + if i == 0 && j == 0 { + return 0; + } + // 若 s 为空,则返回 t 长度 + if i == 0 { + return j; + } + // 若 t 为空,则返回 s 长度 + if j == 0 { + return i; + } + // 若已有记录,则直接返回之 + if let Some(distance) = mem[i][j] { + return distance; + } + // 若两字符相等,则直接跳过此两字符 + if s[i - 1] == t[j - 1] { + return dfs(s, t, mem, i - 1, j - 1); + } + // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 + let insert = dfs(s, t, mem, i, j - 1); + let delete = dfs(s, t, mem, i - 1, j); + let replace = dfs(s, t, mem, i - 1, j - 1); + // 记录并返回最少编辑步数 + let distance = cmp::min(cmp::min(insert, delete), replace) + 1; + mem[i][j] = Some(distance); + distance } - // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 - let insert = edit_distance_dfs_mem(s, t, mem, i, j - 1); - let delete = edit_distance_dfs_mem(s, t, mem, i - 1, j); - let replace = edit_distance_dfs_mem(s, t, mem, i - 1, j - 1); - // 记录并返回最少编辑步数 - mem[i][j] = std::cmp::min(std::cmp::min(insert, delete), replace) + 1; - mem[i][j] + + // 注意:Rust 字符串是不定长的 UTF-8 序列,无法实现 O(1) 时间内的随机访问; + // 可先将字符串转换为字符数组来优化访问。由于没有扩容需求,这里可以进一步改为 + // 堆数组切片 Box<[char]> 来分别节省一个字宽的空间。 + let s: Vec = s.chars().collect(); + let t: Vec = t.chars().collect(); + + // 注意:不可使用 str::len 获取字符串长度,因为其返回的是字节数而非字符数。 + let n = s.len(); + let m = t.len(); + + let mut mem = vec![vec![None; m + 1]; n + 1]; + + dfs(&s, &t, &mut mem, n, m) } /* 编辑距离:动态规划 */ -pub fn edit_distance_dp(s: &str, t: &str) -> i32 { - let (n, m) = (s.len(), t.len()); +#[allow(clippy::needless_range_loop)] +pub fn edit_distance_dp(s: &str, t: &str) -> usize { + // 注意:Rust 字符串是不定长的 UTF-8 序列,无法实现 O(1) 时间内的随机访问; + // 可先将字符串转换为字符数组来优化访问。由于没有扩容需求,这里可以进一步改为 + // 堆数组切片 Box<[char]> 来分别节省一个字宽的空间。 + let s: Vec = s.chars().collect(); + let t: Vec = t.chars().collect(); + + // 注意:不可使用 str::len 获取字符串长度,因为其返回的是字节数而非字符数。 + let n = s.len(); + let m = t.len(); + let mut dp = vec![vec![0; m + 1]; n + 1]; + // 状态转移:首行首列 for i in 1..=n { - dp[i][0] = i as i32; + dp[i][0] = i; } - for j in 1..m { - dp[0][j] = j as i32; + for j in 1..=m { + dp[0][j] = j; } + // 状态转移:其余行和列 for i in 1..=n { for j in 1..=m { - if s.chars().nth(i - 1) == t.chars().nth(j - 1) { + if s[i - 1] == t[j - 1] { // 若两字符相等,则直接跳过此两字符 dp[i][j] = dp[i - 1][j - 1]; - } else { - // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 - dp[i][j] = - std::cmp::min(std::cmp::min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + continue; } + // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 + let insert = dp[i][j - 1]; + let delete = dp[i - 1][j]; + let replace = dp[i - 1][j - 1]; + dp[i][j] = cmp::min(cmp::min(insert, delete), replace) + 1; } } + dp[n][m] } /* 编辑距离:空间优化后的动态规划 */ -pub fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { - let (n, m) = (s.len(), t.len()); - let mut dp = vec![0; m + 1]; +pub fn edit_distance_dp_comp(s: &str, t: &str) -> usize { + // 注意:Rust 字符串是不定长的 UTF-8 序列,无法实现 O(1) 时间内的随机访问; + // 可先将字符串转换为字符数组来优化访问。由于没有扩容需求,这里可以进一步改为 + // 堆数组切片 Box<[char]> 来分别节省一个字宽的空间。 + let s: Vec = s.chars().collect(); + let t: Vec = t.chars().collect(); + + // 注意:不可使用 str::len 获取字符串长度,因为其返回的是字节数而非字符数。 + let n = s.len(); + let m = t.len(); + // 状态转移:首行 - for j in 1..m { - dp[j] = j as i32; - } + let mut dp: Vec = (0..=m).collect(); + // 状态转移:其余行 for i in 1..=n { // 状态转移:首列 - let mut leftup = dp[0]; // 暂存 dp[i-1, j-1] - dp[0] = i as i32; + // 暂存 dp[i - 1, j - 1] + let mut leftup = dp[0]; + dp[0] = i; // 状态转移:其余列 for j in 1..=m { let temp = dp[j]; - if s.chars().nth(i - 1) == t.chars().nth(j - 1) { + if s[i - 1] == t[j - 1] { // 若两字符相等,则直接跳过此两字符 dp[j] = leftup; } else { // 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1 - dp[j] = std::cmp::min(std::cmp::min(dp[j - 1], dp[j]), leftup) + 1; + let insert = dp[j - 1]; + let delete = dp[j]; + let replace = leftup; + dp[j] = cmp::min(cmp::min(insert, delete), replace) + 1; } - leftup = temp; // 更新为下一轮的 dp[i-1, j-1] + // 更新为下一轮的 dp[i - 1, j - 1] + leftup = temp; } } + dp[m] } @@ -121,18 +183,13 @@ pub fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { fn main() { let s = "bag"; let t = "pack"; - let (n, m) = (s.len(), t.len()); // 暴力搜索 - let res = edit_distance_dfs(s, t, n, m); + let res = edit_distance_dfs(s, t); println!("将 {s} 更改为 {t} 最少需要编辑 {res} 步"); // 记忆搜索 - let mut mem = vec![vec![0; m + 1]; n + 1]; - for row in mem.iter_mut() { - row.fill(-1); - } - let res = edit_distance_dfs_mem(s, t, &mut mem, n, m); + let res = edit_distance_dfs_mem(s, t); println!("将 {s} 更改为 {t} 最少需要编辑 {res} 步"); // 动态规划 From f820a04147c46f90a81941d2048c0081b9463be7 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:05:08 +0800 Subject: [PATCH 100/109] fix: resolve warning Removed: - `clippy::needless_return` - `clippy::self_assignment` --- codes/rust/chapter_dynamic_programming/coin_change.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/coin_change.rs b/codes/rust/chapter_dynamic_programming/coin_change.rs index 8e3d5922aa..97bffe5853 100644 --- a/codes/rust/chapter_dynamic_programming/coin_change.rs +++ b/codes/rust/chapter_dynamic_programming/coin_change.rs @@ -27,7 +27,7 @@ pub fn coin_change_dp(coins: &[i32], amt: usize) -> i32 { } } if dp[n][amt] != max { - return dp[n][amt] as i32; + dp[n][amt] as i32 } else { -1 } @@ -46,18 +46,13 @@ pub fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { for a in 1..=amt { if coins[i - 1] > a as i32 { // 若超过目标金额,则不选硬币 i - dp[a] = dp[a]; } else { // 不选和选硬币 i 这两种方案的较小值 dp[a] = std::cmp::min(dp[a], dp[a - coins[i - 1] as usize] + 1); } } } - if dp[amt] != max { - return dp[amt] as i32; - } else { - -1 - } + if dp[amt] != max { dp[amt] as i32 } else { -1 } } /* Driver Code */ From de91999f3f0fdb57e5be86160346e7320c182270 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:06:34 +0800 Subject: [PATCH 101/109] refactor: replace all input integer types with `u32` and all return types with `Option` --- .../coin_change.rs | 65 +++++++++++-------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/coin_change.rs b/codes/rust/chapter_dynamic_programming/coin_change.rs index 97bffe5853..65191c1033 100644 --- a/codes/rust/chapter_dynamic_programming/coin_change.rs +++ b/codes/rust/chapter_dynamic_programming/coin_change.rs @@ -4,67 +4,76 @@ * Author: codingonion (coderonion@gmail.com) */ +use std::cmp; + /* 零钱兑换:动态规划 */ -pub fn coin_change_dp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_dp(coins: &[u32], amt: u32) -> Option { let n = coins.len(); - let max = amt + 1; // 初始化 dp 表 - let mut dp = vec![vec![0; amt + 1]; n + 1]; - // 状态转移:首行首列 + let mut dp = vec![vec![Some(0); amt as usize + 1]; n + 1]; + // 状态转移:首行 for a in 1..=amt { - dp[0][a] = max; + dp[0][a as usize] = None; } - // 状态转移:其余行和列 + // 状态转移:其余行 for i in 1..=n { for a in 1..=amt { - if coins[i - 1] > a as i32 { + if coins[i - 1] > a { // 若超过目标金额,则不选硬币 i - dp[i][a] = dp[i - 1][a]; + dp[i][a as usize] = dp[i - 1][a as usize]; + continue; + } + // 不选和选硬币 i 这两种方案的较小值 + let no = dp[i - 1][a as usize]; + let yes = dp[i][(a - coins[i - 1]) as usize].map(|x| x + 1); + if let (Some(no), Some(yes)) = (no, yes) { + dp[i][a as usize] = Some(cmp::min(no, yes)); } else { - // 不选和选硬币 i 这两种方案的较小值 - dp[i][a] = std::cmp::min(dp[i - 1][a], dp[i][a - coins[i - 1] as usize] + 1); + dp[i][a as usize] = no.or(yes); } } } - if dp[n][amt] != max { - dp[n][amt] as i32 - } else { - -1 - } + // 返回 None 表示无法凑出目标金额 + dp[n][amt as usize] } /* 零钱兑换:空间优化后的动态规划 */ -pub fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_dp_comp(coins: &[u32], amt: u32) -> Option { let n = coins.len(); - let max = amt + 1; // 初始化 dp 表 - let mut dp = vec![0; amt + 1]; - dp.fill(max); - dp[0] = 0; + let mut dp = vec![None; amt as usize + 1]; + dp[0] = Some(0); // 状态转移 for i in 1..=n { for a in 1..=amt { - if coins[i - 1] > a as i32 { + if coins[i - 1] > a { // 若超过目标金额,则不选硬币 i + continue; + } + // 不选和选硬币 i 这两种方案的较小值 + let no = dp[a as usize]; + let yes = dp[(a - coins[i - 1]) as usize].map(|x| x + 1); + if let (Some(no), Some(yes)) = (no, yes) { + dp[a as usize] = Some(cmp::min(no, yes)); } else { - // 不选和选硬币 i 这两种方案的较小值 - dp[a] = std::cmp::min(dp[a], dp[a - coins[i - 1] as usize] + 1); + dp[a as usize] = no.or(yes); } } } - if dp[amt] != max { dp[amt] as i32 } else { -1 } + // 返回 None 表示无法凑出目标金额 + dp[amt as usize] } /* Driver Code */ fn main() { let coins = [1, 2, 5]; - let amt: usize = 4; + let amt = 4; // 动态规划 let res = coin_change_dp(&coins, amt); - println!("凑到目标金额所需的最少硬币数量为 {res}"); + println!("凑到目标金额所需的最少硬币数量为 {res:?}"); - // 空间优化后的动态规划 + // // 空间优化后的动态规划 let res = coin_change_dp_comp(&coins, amt); - println!("凑到目标金额所需的最少硬币数量为 {res}"); + println!("凑到目标金额所需的最少硬币数量为 {res:?}"); } From 7a58853f8bf0602ac7f7e9d3d1e663d3ddbe821b Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:07:50 +0800 Subject: [PATCH 102/109] fix: resolve warning Removed: - `clippy::self_assignment` - `clippy::assign_op_pattern` --- codes/rust/chapter_dynamic_programming/coin_change_ii.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/coin_change_ii.rs b/codes/rust/chapter_dynamic_programming/coin_change_ii.rs index cf0990e9dc..e876cb0cca 100644 --- a/codes/rust/chapter_dynamic_programming/coin_change_ii.rs +++ b/codes/rust/chapter_dynamic_programming/coin_change_ii.rs @@ -39,10 +39,9 @@ pub fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 { for a in 1..=amt { if coins[i - 1] > a as i32 { // 若超过目标金额,则不选硬币 i - dp[a] = dp[a]; } else { // 不选和选硬币 i 这两种方案之和 - dp[a] = dp[a] + dp[a - coins[i - 1] as usize]; + dp[a] += dp[a - coins[i - 1] as usize]; } } } From 21b3334b0a80839d966e56cca99c424ee334f9cc Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:08:22 +0800 Subject: [PATCH 103/109] refactor: replace all integer types with `u32` --- .../coin_change_ii.rs | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/codes/rust/chapter_dynamic_programming/coin_change_ii.rs b/codes/rust/chapter_dynamic_programming/coin_change_ii.rs index e876cb0cca..7d119cd411 100644 --- a/codes/rust/chapter_dynamic_programming/coin_change_ii.rs +++ b/codes/rust/chapter_dynamic_programming/coin_change_ii.rs @@ -5,53 +5,57 @@ */ /* 零钱兑换 II:动态规划 */ -pub fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_ii_dp(coins: &[u32], amt: u32) -> u32 { let n = coins.len(); // 初始化 dp 表 - let mut dp = vec![vec![0; amt + 1]; n + 1]; + let mut dp = vec![vec![0; amt as usize + 1]; n + 1]; // 初始化首列 - for i in 0..=n { - dp[i][0] = 1; + for row in &mut dp { + row[0] = 1; } // 状态转移 for i in 1..=n { for a in 1..=amt { - if coins[i - 1] > a as i32 { + if coins[i - 1] > a { // 若超过目标金额,则不选硬币 i - dp[i][a] = dp[i - 1][a]; - } else { - // 不选和选硬币 i 这两种方案之和 - dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1] as usize]; + dp[i][a as usize] = dp[i - 1][a as usize]; + continue; } + // 不选和选硬币 i 这两种方案之和 + let no = dp[i - 1][a as usize]; + let yes = dp[i][(a - coins[i - 1]) as usize]; + dp[i][a as usize] = no + yes; } } - dp[n][amt] + dp[n][amt as usize] } /* 零钱兑换 II:空间优化后的动态规划 */ -pub fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 { +pub fn coin_change_ii_dp_comp(coins: &[u32], amt: u32) -> u32 { let n = coins.len(); // 初始化 dp 表 - let mut dp = vec![0; amt + 1]; + let mut dp = vec![0; amt as usize + 1]; dp[0] = 1; // 状态转移 for i in 1..=n { for a in 1..=amt { - if coins[i - 1] > a as i32 { + if coins[i - 1] > a { // 若超过目标金额,则不选硬币 i - } else { - // 不选和选硬币 i 这两种方案之和 - dp[a] += dp[a - coins[i - 1] as usize]; + continue; } + // 不选和选硬币 i 这两种方案之和 + let no = dp[a as usize]; + let yes = dp[(a - coins[i - 1]) as usize]; + dp[a as usize] = no + yes; } } - dp[amt] + dp[amt as usize] } /* Driver Code */ fn main() { let coins = [1, 2, 5]; - let amt: usize = 5; + let amt = 5; // 动态规划 let res = coin_change_ii_dp(&coins, amt); From bf33f65fb9043052a109038e6512130efe8f28ce Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:10:00 +0800 Subject: [PATCH 104/109] refactor: replace all input integer types with `u32` and return type with `Option` --- .../rust/chapter_greedy/coin_change_greedy.rs | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/codes/rust/chapter_greedy/coin_change_greedy.rs b/codes/rust/chapter_greedy/coin_change_greedy.rs index 8637b994ad..78bb395748 100644 --- a/codes/rust/chapter_greedy/coin_change_greedy.rs +++ b/codes/rust/chapter_greedy/coin_change_greedy.rs @@ -5,26 +5,32 @@ */ /* 零钱兑换:贪心 */ -pub fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 { - // 假设 coins 列表有序 +pub fn coin_change_greedy(coins: &[u32], mut amt: u32) -> Option { + // coins 列表必须有序 + assert!(coins.is_sorted()); + + // 若硬币列表为空,无法凑出目标金额,直接返回 None + if coins.is_empty() { + return None; + } + + // coins 非空,此处不会发生减法溢出 let mut i = coins.len() - 1; let mut count = 0; + // 循环进行贪心选择,直到无剩余金额 while amt > 0 { // 找到小于且最接近剩余金额的硬币 - while i > 0 && coins[i] > amt { - i -= 1; + while coins[i] > amt { + // 若最小面值的硬币仍然大于剩余金额,则无法凑出目标金额,直接返回 None + i = i.checked_sub(1)?; } // 选择 coins[i] amt -= coins[i]; count += 1; } - // 若未找到可行方案,则返回 -1 - if amt == 0 { - count - } else { - -1 - } + + Some(count) } /* Driver Code */ @@ -33,22 +39,26 @@ fn main() { let coins = [1, 5, 10, 20, 50, 100]; let amt = 186; let res = coin_change_greedy(&coins, amt); - println!("\ncoins = {:?}, amt = {}", coins, amt); - println!("凑到 {} 所需的最少硬币数量为 {}", amt, res); + println!("coins = {coins:?}, amt = {amt}"); + println!("凑到 {amt} 所需的最少硬币数量为 {res:?}"); + + println!(); // 贪心:无法保证找到全局最优解 let coins = [1, 20, 50]; let amt = 60; let res = coin_change_greedy(&coins, amt); - println!("\ncoins = {:?}, amt = {}", coins, amt); - println!("凑到 {} 所需的最少硬币数量为 {}", amt, res); + println!("coins = {coins:?}, amt = {amt}"); + println!("凑到 {amt} 所需的最少硬币数量为 {res:?}"); println!("实际上需要的最少数量为 3 ,即 20 + 20 + 20"); + println!(); + // 贪心:无法保证找到全局最优解 let coins = [1, 49, 50]; let amt = 98; let res = coin_change_greedy(&coins, amt); - println!("\ncoins = {:?}, amt = {}", coins, amt); - println!("凑到 {} 所需的最少硬币数量为 {}", amt, res); + println!("coins = {coins:?}, amt = {amt}"); + println!("凑到 {amt} 所需的最少硬币数量为 {res:?}"); println!("实际上需要的最少数量为 2 ,即 49 + 49"); } From 2ae41a7fb873337720006a4d206db1c59bd5157d Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:13:25 +0800 Subject: [PATCH 105/109] refactor: replace all integer types with `u32` --- .../chapter_greedy/fractional_knapsack.rs | 24 ++++++++++------- codes/rust/chapter_greedy/max_capacity.rs | 20 +++++++++++--- .../chapter_greedy/max_product_cutting.rs | 27 +++++++++++-------- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/codes/rust/chapter_greedy/fractional_knapsack.rs b/codes/rust/chapter_greedy/fractional_knapsack.rs index e18f81b8de..8b40aa972c 100644 --- a/codes/rust/chapter_greedy/fractional_knapsack.rs +++ b/codes/rust/chapter_greedy/fractional_knapsack.rs @@ -6,33 +6,36 @@ /* 物品 */ struct Item { - w: i32, // 物品重量 - v: i32, // 物品价值 + w: u32, // 物品重量 + v: u32, // 物品价值 } impl Item { - fn new(w: i32, v: i32) -> Self { + fn new(w: u32, v: u32) -> Self { Self { w, v } } } /* 分数背包:贪心 */ -pub fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 { +pub fn fractional_knapsack(wgt: &[u32], val: &[u32], mut cap: u32) -> f64 { // 创建物品列表,包含两个属性:重量、价值 let mut items = wgt .iter() - .zip(val.iter()) + .zip(val) .map(|(&w, &v)| Item::new(w, v)) .collect::>(); + // 按照单位价值 item.v / item.w 从高到低进行排序 items.sort_by(|a, b| { - (b.v as f64 / b.w as f64) - .partial_cmp(&(a.v as f64 / a.w as f64)) - .unwrap() + let a_vpw = a.v as f64 / a.w as f64; + let b_vpw = b.v as f64 / b.w as f64; + // 调换顺序以实现降序排序 + f64::total_cmp(&b_vpw, &a_vpw) }); + // 循环贪心选择 let mut res = 0.0; - for item in &items { + for item in items { if item.w <= cap { // 若剩余容量充足,则将当前物品整个装进背包 res += item.v as f64; @@ -44,6 +47,7 @@ pub fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 { break; } } + res } @@ -55,5 +59,5 @@ fn main() { // 贪心算法 let res = fractional_knapsack(&wgt, &val, cap); - println!("不超过背包容量的最大物品价值为 {}", res); + println!("不超过背包容量的最大物品价值为 {res}"); } diff --git a/codes/rust/chapter_greedy/max_capacity.rs b/codes/rust/chapter_greedy/max_capacity.rs index d169111b47..556d69ad9c 100644 --- a/codes/rust/chapter_greedy/max_capacity.rs +++ b/codes/rust/chapter_greedy/max_capacity.rs @@ -4,8 +4,14 @@ * Author: night-cruise (2586447362@qq.com) */ +use std::cmp; + /* 最大容量:贪心 */ -pub fn max_capacity(ht: &[i32]) -> i32 { +pub fn max_capacity(ht: &[u32]) -> u32 { + // 若数组为空,直接返回 0 + if ht.is_empty() { + return 0; + } // 初始化 i, j,使其分列数组两端 let mut i = 0; let mut j = ht.len() - 1; @@ -14,8 +20,14 @@ pub fn max_capacity(ht: &[i32]) -> i32 { // 循环贪心选择,直至两板相遇 while i < j { // 更新最大容量 - let cap = std::cmp::min(ht[i], ht[j]) * (j - i) as i32; - res = std::cmp::max(res, cap); + // 选用 u32 而非 usize 是出于语义考虑:usize 用于索引偏移、容器长度、迭代计数等场景; + // 原则上,涉及一般数学计算时,应该选用通用整数类型。因为宽度和高度均不小于零,此处选用 + // 无符号整数 u32。注意到 64 位平台上 u32 无法覆盖所有 usize 值,此处直接对过大值做 + // 退出处理。 + let width: u32 = (j - i).try_into().expect("宽度过大"); + // 乘法溢出时终止程序 + let cap = cmp::min(ht[i], ht[j]) * width; + res = cmp::max(res, cap); // 向内移动短板 if ht[i] < ht[j] { i += 1; @@ -32,5 +44,5 @@ fn main() { // 贪心算法 let res = max_capacity(&ht); - println!("最大容量为 {}", res); + println!("最大容量为 {res}"); } diff --git a/codes/rust/chapter_greedy/max_product_cutting.rs b/codes/rust/chapter_greedy/max_product_cutting.rs index 2a952e82e0..8c796ae973 100644 --- a/codes/rust/chapter_greedy/max_product_cutting.rs +++ b/codes/rust/chapter_greedy/max_product_cutting.rs @@ -1,27 +1,32 @@ /* - * File: coin_change_greedy.rs + * File: max_product_cutting.rs * Created Time: 2023-07-22 * Author: night-cruise (2586447362@qq.com) */ /* 最大切分乘积:贪心 */ -pub fn max_product_cutting(n: i32) -> i32 { +pub fn max_product_cutting(n: u32) -> u32 { + assert!(n > 0, "n 必须为正整数"); + // 当 n <= 3 时,必须切分出一个 1 if n <= 3 { - return 1 * (n - 1); + // n > 0, 不会发生减法溢出 + return n - 1; } // 贪心地切分出 3 ,a 为 3 的个数,b 为余数 let a = n / 3; let b = n % 3; - if b == 1 { + match b { + // 当余数为 0 时,不做处理 + 0 => 3_u32.pow(a), + // 当余数为 1 时,将一对 1 * 3 转化为 2 * 2 - 3_i32.pow(a as u32 - 1) * 2 * 2 - } else if b == 2 { + 1 => 3_u32.pow(a - 1) * 2 * 2, + // 当余数为 2 时,不做处理 - 3_i32.pow(a as u32) * 2 - } else { - // 当余数为 0 时,不做处理 - 3_i32.pow(a as u32) + 2 => 3_u32.pow(a) * 2, + + _ => unreachable!(), } } @@ -31,5 +36,5 @@ fn main() { // 贪心算法 let res = max_product_cutting(n); - println!("最大切分乘积为 {}", res); + println!("最大切分乘积为 {res}"); } From 663e7d1346add010c36df9c5459941004c0c0042 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:17:36 +0800 Subject: [PATCH 106/109] refactor!: remove mod `include` --- codes/rust/src/include/list_node.rs | 57 --------------- codes/rust/src/include/mod.rs | 16 ----- codes/rust/src/include/print_util.rs | 103 --------------------------- codes/rust/src/include/tree_node.rs | 92 ------------------------ codes/rust/src/include/vertex.rs | 27 ------- codes/rust/src/lib.rs | 1 - 6 files changed, 296 deletions(-) delete mode 100644 codes/rust/src/include/list_node.rs delete mode 100644 codes/rust/src/include/mod.rs delete mode 100644 codes/rust/src/include/print_util.rs delete mode 100644 codes/rust/src/include/tree_node.rs delete mode 100644 codes/rust/src/include/vertex.rs diff --git a/codes/rust/src/include/list_node.rs b/codes/rust/src/include/list_node.rs deleted file mode 100644 index 003ab29893..0000000000 --- a/codes/rust/src/include/list_node.rs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * File: list_node.rs - * Created Time: 2023-03-05 - * Author: codingonion (coderonion@gmail.com), rongyi (hiarongyi@gmail.com) - */ - -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; - -#[derive(Debug)] -pub struct ListNode { - pub val: T, - pub next: Option>>>, -} - -impl ListNode { - pub fn new(val: T) -> Rc>> { - Rc::new(RefCell::new(ListNode { val, next: None })) - } - - /* 将数组反序列化为链表 */ - pub fn arr_to_linked_list(array: &[T]) -> Option>>> - where - T: Copy + Clone, - { - let mut head = None; - // insert in reverse order - for item in array.iter().rev() { - let node = Rc::new(RefCell::new(ListNode { - val: *item, - next: head.take(), - })); - head = Some(node); - } - head - } - - /* 将链表转化为哈希表 */ - pub fn linked_list_to_hashmap( - linked_list: Option>>>, - ) -> HashMap>>> - where - T: std::hash::Hash + Eq + Copy + Clone, - { - let mut hashmap = HashMap::new(); - let mut node = linked_list; - - while let Some(cur) = node { - let borrow = cur.borrow(); - hashmap.insert(borrow.val.clone(), cur.clone()); - node = borrow.next.clone(); - } - - hashmap - } -} diff --git a/codes/rust/src/include/mod.rs b/codes/rust/src/include/mod.rs deleted file mode 100644 index 6cba6f9a52..0000000000 --- a/codes/rust/src/include/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -/* - * File: include.rs - * Created Time: 2023-02-05 - * Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICE@outlook.com) - */ - -pub mod list_node; -pub mod print_util; -pub mod tree_node; -pub mod vertex; - -// rexport to include -pub use list_node::*; -pub use print_util::*; -pub use tree_node::*; -pub use vertex::*; diff --git a/codes/rust/src/include/print_util.rs b/codes/rust/src/include/print_util.rs deleted file mode 100644 index eccc659dd8..0000000000 --- a/codes/rust/src/include/print_util.rs +++ /dev/null @@ -1,103 +0,0 @@ -/* - * File: print_util.rs - * Created Time: 2023-02-05 - * Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICEx@outlook.com) - */ - -use std::cell::{Cell, RefCell}; -use std::fmt::Display; -use std::collections::{HashMap, VecDeque}; -use std::rc::Rc; - -use super::list_node::ListNode; -use super::tree_node::{TreeNode, vec_to_tree}; - -struct Trunk<'a, 'b> { - prev: Option<&'a Trunk<'a, 'b>>, - str: Cell<&'b str>, -} - -/* 打印数组 */ -pub fn print_array(nums: &[T]) { - print!("["); - if nums.len() > 0 { - for (i, num) in nums.iter().enumerate() { - print!("{}{}", num, if i == nums.len() - 1 {"]"} else {", "} ); - } - } else { - print!("]"); - } -} - -/* 打印哈希表 */ -pub fn print_hash_map(map: &HashMap) { - for (key, value) in map { - println!("{key} -> {value}"); - } -} - -/* 打印队列(双向队列) */ -pub fn print_queue(queue: &VecDeque) { - print!("["); - let iter = queue.iter(); - for (i, data) in iter.enumerate() { - print!("{}{}", data, if i == queue.len() - 1 {"]"} else {", "} ); - } -} - -/* 打印链表 */ -pub fn print_linked_list(head: &Rc>>) { - print!("{}{}", head.borrow().val, if head.borrow().next.is_none() {"\n"} else {" -> "}); - if let Some(node) = &head.borrow().next { - return print_linked_list(node); - } -} - -/* 打印二叉树 */ -pub fn print_tree(root: &Rc>) { - _print_tree(Some(root), None, false); -} - -/* 打印二叉树 */ -fn _print_tree(root: Option<&Rc>>, prev: Option<&Trunk>, is_right: bool) { - if let Some(node) = root { - let mut prev_str = " "; - let trunk = Trunk { prev, str: Cell::new(prev_str) }; - _print_tree(node.borrow().right.as_ref(), Some(&trunk), true); - - if prev.is_none() { - trunk.str.set("———"); - } else if is_right { - trunk.str.set("/———"); - prev_str = " |"; - } else { - trunk.str.set("\\———"); - prev.as_ref().unwrap().str.set(prev_str); - } - - show_trunks(Some(&trunk)); - println!(" {}", node.borrow().val); - if let Some(prev) = prev { - prev.str.set(prev_str); - } - trunk.str.set(" |"); - - _print_tree(node.borrow().left.as_ref(), Some(&trunk), false); - } -} - -fn show_trunks(trunk: Option<&Trunk>) { - if let Some(trunk) = trunk { - show_trunks(trunk.prev); - print!("{}", trunk.str.get()); - } -} - -/* 打印堆 */ -pub fn print_heap(heap: Vec) { - println!("堆的数组表示:{:?}", heap); - println!("堆的树状表示:"); - if let Some(root) = vec_to_tree(heap.into_iter().map(|val| Some(val)).collect()) { - print_tree(&root); - } -} diff --git a/codes/rust/src/include/tree_node.rs b/codes/rust/src/include/tree_node.rs deleted file mode 100644 index 8ff3549981..0000000000 --- a/codes/rust/src/include/tree_node.rs +++ /dev/null @@ -1,92 +0,0 @@ -/* - * File: tree_node.rs - * Created Time: 2023-02-27 - * Author: xBLACKICEx (xBLACKICE@outlook.com), night-cruise (2586447362@qq.com) - */ - -use std::cell::RefCell; -use std::rc::Rc; - -/* 二叉树节点类型 */ -#[derive(Debug)] -pub struct TreeNode { - pub val: i32, - pub height: i32, - pub parent: Option>>, - pub left: Option>>, - pub right: Option>>, -} - -impl TreeNode { - /* 构造方法 */ - pub fn new(val: i32) -> Rc> { - Rc::new(RefCell::new(Self { - val, - height: 0, - parent: None, - left: None, - right: None, - })) - } -} - -#[macro_export] -macro_rules! op_vec { - ( $( $x:expr ),* ) => { - vec![ - $(Option::from($x)),* - ] - }; -} - -// 序列化编码规则请参考: -// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ -// 二叉树的数组表示: -// [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] -// 二叉树的链表表示: -// /——— 15 -// /——— 7 -// /——— 3 -// | \——— 6 -// | \——— 12 -// ——— 1 -// \——— 2 -// | /——— 9 -// \——— 4 -// \——— 8 - -/* 将列表反序列化为二叉树:递归 */ -fn vec_to_tree_dfs(arr: &[Option], i: usize) -> Option>> { - if i >= arr.len() || arr[i].is_none() { - return None; - } - let root = TreeNode::new(arr[i].unwrap()); - root.borrow_mut().left = vec_to_tree_dfs(arr, 2 * i + 1); - root.borrow_mut().right = vec_to_tree_dfs(arr, 2 * i + 2); - Some(root) -} - -/* 将列表反序列化为二叉树 */ -pub fn vec_to_tree(arr: Vec>) -> Option>> { - vec_to_tree_dfs(&arr, 0) -} - -/* 将二叉树序列化为列表:递归 */ -fn tree_to_vec_dfs(root: Option<&Rc>>, i: usize, res: &mut Vec>) { - if let Some(root) = root { - // i + 1 is the minimum valid size to access index i - while res.len() < i + 1 { - res.push(None); - } - res[i] = Some(root.borrow().val); - tree_to_vec_dfs(root.borrow().left.as_ref(), 2 * i + 1, res); - tree_to_vec_dfs(root.borrow().right.as_ref(), 2 * i + 2, res); - } -} - -/* 将二叉树序列化为列表 */ -pub fn tree_to_vec(root: Option>>) -> Vec> { - let mut res = vec![]; - tree_to_vec_dfs(root.as_ref(), 0, &mut res); - res -} diff --git a/codes/rust/src/include/vertex.rs b/codes/rust/src/include/vertex.rs deleted file mode 100644 index ca1a5a8214..0000000000 --- a/codes/rust/src/include/vertex.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * File: vertex.rs - * Created Time: 2023-07-13 - * Author: night-cruise (2586447362@qq.com) - */ - -/* 顶点类型 */ -#[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub struct Vertex { - pub val: i32, -} - -impl From for Vertex { - fn from(value: i32) -> Self { - Self { val: value } - } -} - -/* 输入值列表 vals ,返回顶点列表 vets */ -pub fn vals_to_vets(vals: Vec) -> Vec { - vals.into_iter().map(|val| val.into()).collect() -} - -/* 输入顶点列表 vets ,返回值列表 vals */ -pub fn vets_to_vals(vets: Vec) -> Vec { - vets.into_iter().map(|vet| vet.val).collect() -} diff --git a/codes/rust/src/lib.rs b/codes/rust/src/lib.rs index 342e855e21..3aacd62819 100644 --- a/codes/rust/src/lib.rs +++ b/codes/rust/src/lib.rs @@ -2,5 +2,4 @@ pub mod binary_tree; pub mod fmt; pub mod graph_adjacency_list; pub mod heap; -pub mod include; pub mod linked_list; From b2b4b18ffad57cbb8da2556db5480d798028528c Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:22:53 +0800 Subject: [PATCH 107/109] docs: remove leading underscores --- docs/chapter_array_and_linkedlist/list.md | 8 ++++---- docs/chapter_hashing/hash_map.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index ded6505eb0..1a49eb7810 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -684,15 +684,15 @@ ```rust title="list.rs" // 通过索引遍历列表 - let mut _count = 0; + let mut count = 0; for i in 0..nums.len() { - _count += nums[i]; + count += nums[i]; } // 直接遍历列表元素 - _count = 0; + count = 0; for num in &nums { - _count += num; + count += num; } ``` diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index b4c0e9664a..3091af4eef 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -254,11 +254,11 @@ /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value - let _name: Option<&String> = map.get(&15937); + let name: Option<&String> = map.get(&15937); /* 删除操作 */ // 在哈希表中删除键值对 (key, value) - let _removed_value: Option = map.remove(&10583); + let removed_value: Option = map.remove(&10583); ``` === "C" From 66592389a30841e14e5e0c1e501a402eff00e6f3 Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Fri, 6 Feb 2026 03:26:33 +0800 Subject: [PATCH 108/109] docs: remove redundant code --- .../space_complexity.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 156f146ffa..22fc39e0a6 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -80,13 +80,13 @@ Node next; Node(int x) { val = x; } } - + /* 函数 */ int function() { // 执行某些操作... return 0; } - + int algorithm(int n) { // 输入数据 final int a = 0; // 暂存数据(常量) int b = 0; // 暂存数据(变量) @@ -133,7 +133,7 @@ func newNode(val int) *node { return &node{val: val} } - + /* 函数 */ func function() int { // 执行某些操作... @@ -263,7 +263,7 @@ ```rust title="" use std::rc::Rc; use std::cell::RefCell; - + /* 结构体 */ struct Node { val: i32, @@ -273,14 +273,14 @@ /* 创建 Node 结构体 */ impl Node { fn new(val: i32) -> Self { - Self { val: val, next: None } + Self { val, next: None } } } /* 函数 */ - fn function() -> i32 { + fn function() -> i32 { // 执行某些操作... - return 0; + 0 } fn algorithm(n: i32) -> i32 { // 输入数据 @@ -288,7 +288,7 @@ let mut b = 0; // 暂存数据(变量) let node = Node::new(0); // 暂存数据(对象) let c = function(); // 栈帧空间(调用函数) - return a + b + c; // 输出数据 + a + b + c // 输出数据 } ``` @@ -611,14 +611,14 @@ // 执行某些操作 return 0 } - + /* 循环的空间复杂度为 O(1) */ func loop(n int) { for i := 0; i < n; i++ { function() } } - + /* 递归的空间复杂度为 O(n) */ func recur(n int) { if n == 1 { From ec033294e58683d7650dc49a46ebf3d0e4e48bab Mon Sep 17 00:00:00 2001 From: Lingxuan Ye Date: Sat, 7 Feb 2026 06:07:16 +0800 Subject: [PATCH 109/109] docs: reword --- codes/rust/GUIDELINES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codes/rust/GUIDELINES.md b/codes/rust/GUIDELINES.md index 3960c392b4..1133fcc91a 100644 --- a/codes/rust/GUIDELINES.md +++ b/codes/rust/GUIDELINES.md @@ -36,9 +36,9 @@ cargo clippy ## 常见情况的处理建议 -- **公共项**:应作为本项目的同名库 crate `hello_algo_rust` 的公共接口,放在 `src` 目录下。项目内的其他所有代码均为二进制 crate,它们作为依赖链的最下游,不应作为依赖项被其他 crate「挂载」为模块。目前 Cargo 并没有阻止这种做法,甚至允许一个文件被多次「挂载」,但这是一种典型的反模式,应当避免。 +- **公共项**:应作为 lib crate `hello_algo_rust` 的公共接口,放在 `src` 目录下。项目内的其他所有代码均为 bin crates,它们作为依赖链的最下游,不应作为依赖项被其他 crate「挂载」为模块。目前 Cargo 并没有阻止这种做法,甚至允许一个文件被多次「挂载」,但这是一种典型的反模式,应当避免。 -- **可见性**:**示例代码**全部位于 bin crate,原则上不会被其他地方使用,最大可见性本应为 `pub(crate)`,在 crate 顶层无需被可见性修饰符修饰;然而,「实现某种数据结构或算法」暗示着代码将作为某种公开接口供下游使用,为了表达这种意图,以及区分公开接口和内部实现细节,**示例代码**中原则上是公开接口的部分应使用 `pub` 修饰符,是内部实现细节的部分不使用可见性修饰符。可见性修饰符中不得出现范围参数,例如 `pub(super)`、`pub(in some::path)` 等。 +- **可见性**:**示例代码**全部位于 bin crates,原则上不会被其他地方使用,最大可见性本应为 `pub(crate)`,在 crate 顶层无需被可见性修饰符修饰;然而,「实现某种数据结构或算法」暗示着代码将作为某种公开接口供下游使用,为了表达这种意图,以及区分公开接口和内部实现细节,**示例代码**中原则上是公开接口的部分应使用 `pub` 修饰符,是内部实现细节的部分不使用可见性修饰符。可见性修饰符中不得出现范围参数,例如 `pub(super)`、`pub(in some::path)` 等。 - **导入**:常量、静态量、类型别名、结构体、枚举、trait 等可直接导入,函数应导入上级模块并以其为前缀使用。