diff --git a/docs-en/chapter_array_and_linkedlist/linked_list.md b/docs-en/chapter_array_and_linkedlist/linked_list.md index f80060f04..bfd32b4dd 100755 --- a/docs-en/chapter_array_and_linkedlist/linked_list.md +++ b/docs-en/chapter_array_and_linkedlist/linked_list.md @@ -512,7 +512,7 @@ By comparison, inserting an element into an array has a time complexity of $O(n) /* 在链表的节点 n0 之后插入节点 P */ #[allow(non_snake_case)] pub fn insert(n0: &Rc>>, P: Rc>>) { - let n1 = n0.borrow_mut().next.take(); + let n1 = n0.borrow_mut().next.take(); P.borrow_mut().next = n1; n0.borrow_mut().next = Some(P); } @@ -690,7 +690,9 @@ It's important to note that even though node `P` continues to point to `n1` afte /* 删除链表的节点 n0 之后的首个节点 */ #[allow(non_snake_case)] pub fn remove(n0: &Rc>>) { - if n0.borrow().next.is_none() {return}; + if n0.borrow().next.is_none() { + return; + }; // n0 -> P -> n1 let P = n0.borrow_mut().next.take(); if let Some(node) = P { @@ -872,10 +874,13 @@ It's important to note that even though node `P` continues to point to `n1` afte ```rust title="linked_list.rs" /* 访问链表中索引为 index 的节点 */ pub fn access(head: Rc>>, index: i32) -> Rc>> { - if index <= 0 {return head}; - if let Some(node) = &head.borrow_mut().next { + if index <= 0 { + return head; + }; + if let Some(node) = &head.borrow().next { return access(node.clone(), index - 1); } + return head; } ``` @@ -1071,7 +1076,9 @@ Traverse the linked list to locate a node whose value matches `target`, and then ```rust title="linked_list.rs" /* 在链表中查找值为 target 的首个节点 */ pub fn find(head: Rc>>, target: T, index: i32) -> i32 { - if head.borrow().val == target {return index}; + if head.borrow().val == target { + return index; + }; if let Some(node) = &head.borrow_mut().next { return find(node.clone(), target, index + 1); } diff --git a/docs-en/chapter_array_and_linkedlist/list.md b/docs-en/chapter_array_and_linkedlist/list.md index 789d90086..f2daca28b 100755 --- a/docs-en/chapter_array_and_linkedlist/list.md +++ b/docs-en/chapter_array_and_linkedlist/list.md @@ -1785,16 +1785,16 @@ To enhance our understanding of how lists work, we will attempt to implement a s #[allow(dead_code)] struct MyList { arr: Vec, // 数组(存储列表元素) - capacity: usize, // 列表容量 - size: usize, // 列表长度(当前元素数量) - extend_ratio: usize, // 每次列表扩容的倍数 + capacity: usize, // 列表容量 + size: usize, // 列表长度(当前元素数量) + extend_ratio: usize, // 每次列表扩容的倍数 } - #[allow(unused,unused_comparisons)] + #[allow(unused, unused_comparisons)] impl MyList { /* 构造方法 */ pub fn new(capacity: usize) -> Self { - let mut vec = Vec::new(); + let mut vec = Vec::new(); vec.resize(capacity, 0); Self { arr: vec, @@ -1817,13 +1817,17 @@ To enhance our understanding of how lists work, we will attempt to implement a s /* 访问元素 */ pub fn get(&self, index: usize) -> i32 { // 索引如果越界,则抛出异常,下同 - if index >= self.size {panic!("索引越界")}; + if index >= self.size { + panic!("索引越界") + }; return self.arr[index]; } /* 更新元素 */ pub fn set(&mut self, index: usize, num: i32) { - if index >= self.size {panic!("索引越界")}; + if index >= self.size { + panic!("索引越界") + }; self.arr[index] = num; } @@ -1840,7 +1844,9 @@ To enhance our understanding of how lists work, we will attempt to implement a s /* 在中间插入元素 */ pub fn insert(&mut self, index: usize, num: i32) { - if index >= self.size() {panic!("索引越界")}; + if index >= self.size() { + panic!("索引越界") + }; // 元素数量超出容量时,触发扩容机制 if self.size == self.capacity() { self.extend_capacity(); @@ -1856,7 +1862,9 @@ To enhance our understanding of how lists work, we will attempt to implement a s /* 删除元素 */ pub fn remove(&mut self, index: usize) -> i32 { - if index >= self.size() {panic!("索引越界")}; + if index >= self.size() { + panic!("索引越界") + }; let num = self.arr[index]; // 将将索引 index 之后的元素都向前移动一位 for j in (index..self.size - 1) { diff --git a/docs-en/chapter_computational_complexity/iteration_and_recursion.md b/docs-en/chapter_computational_complexity/iteration_and_recursion.md index ee661b9ef..88da24a19 100644 --- a/docs-en/chapter_computational_complexity/iteration_and_recursion.md +++ b/docs-en/chapter_computational_complexity/iteration_and_recursion.md @@ -151,7 +151,7 @@ The following function implements the sum $1 + 2 + \dots + n$ using a `for` loop res += i; } res - } + } ``` === "C" @@ -352,6 +352,7 @@ Below we use a `while` loop to implement the sum $1 + 2 + \dots + n$: fn while_loop(n: i32) -> i32 { let mut res = 0; let mut i = 1; // 初始化条件变量 + // 循环求和 1, 2, ..., n-1, n while i <= n { res += i; @@ -570,6 +571,7 @@ For example, in the following code, the condition variable $i$ is updated twice fn while_loop_ii(n: i32) -> i32 { let mut res = 0; let mut i = 1; // 初始化条件变量 + // 循环求和 1, 4, 10, ... while i <= n { res += i; diff --git a/docs-en/chapter_computational_complexity/space_complexity.md b/docs-en/chapter_computational_complexity/space_complexity.md index 97c92e202..baeb34b63 100644 --- a/docs-en/chapter_computational_complexity/space_complexity.md +++ b/docs-en/chapter_computational_complexity/space_complexity.md @@ -979,7 +979,7 @@ Note that memory occupied by initializing variables or calling functions in a lo ```rust title="space_complexity.rs" /* 函数 */ - fn function() ->i32 { + fn function() -> i32 { // 执行某些操作 return 0; } @@ -1452,7 +1452,9 @@ As shown below, this function's recursive depth is $n$, meaning there are $n$ in /* 线性阶(递归实现) */ fn linear_recur(n: i32) { println!("递归 n = {}", n); - if n == 1 {return}; + if n == 1 { + return; + }; linear_recur(n - 1); } ``` @@ -1834,7 +1836,9 @@ As shown below, the recursive depth of this function is $n$, and in each recursi ```rust title="space_complexity.rs" /* 平方阶(递归实现) */ fn quadratic_recur(n: i32) -> i32 { - if n <= 0 {return 0}; + if n <= 0 { + return 0; + }; // 数组 nums 长度为 n, n-1, ..., 2, 1 let nums = vec![0; n as usize]; println!("递归 n = {} 中的 nums 长度 = {}", n, nums.len()); @@ -2011,7 +2015,9 @@ Exponential order is common in binary trees. Observe the below image, a "full bi ```rust title="space_complexity.rs" /* 指数阶(建立满二叉树) */ fn build_tree(n: i32) -> Option>> { - if n == 0 {return None}; + 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); diff --git a/docs-en/chapter_computational_complexity/time_complexity.md b/docs-en/chapter_computational_complexity/time_complexity.md index 8ca18e698..f1716a9fb 100644 --- a/docs-en/chapter_computational_complexity/time_complexity.md +++ b/docs-en/chapter_computational_complexity/time_complexity.md @@ -1737,7 +1737,7 @@ For instance, in bubble sort, the outer loop runs $n - 1$ times, and the inner l int count = 0; // 计数器 // 外循环:未排序区间为 [0, i] for (int i = nums.Length - 1; i > 0; i--) { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -1781,7 +1781,7 @@ For instance, in bubble sort, the outer loop runs $n - 1$ times, and the inner l var count = 0 // 计数器 // 外循环:未排序区间为 [0, i] for i in stride(from: nums.count - 1, to: 0, by: -1) { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in 0 ..< i { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] @@ -1871,9 +1871,10 @@ For instance, in bubble sort, the outer loop runs $n - 1$ times, and the inner l /* 平方阶(冒泡排序) */ fn bubble_sort(nums: &mut [i32]) -> i32 { let mut count = 0; // 计数器 + // 外循环:未排序区间为 [0, i] for i in (1..nums.len()).rev() { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in 0..i { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] @@ -1921,7 +1922,7 @@ For instance, in bubble sort, the outer loop runs $n - 1$ times, and the inner l var i: i32 = @as(i32, @intCast(nums.len)) - 1; while (i > 0) : (i -= 1) { var j: usize = 0; - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 while (j < i) : (j += 1) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -2792,10 +2793,10 @@ Linear-logarithmic order often appears in nested loops, with the complexities of return 1; } let mut count = linear_log_recur(n / 2.0) + linear_log_recur(n / 2.0); - for _ in 0 ..n as i32 { + for _ in 0..n as i32 { count += 1; } - return count + return count; } ``` diff --git a/docs-en/chapter_hashing/hash_algorithm.md b/docs-en/chapter_hashing/hash_algorithm.md index 773a52994..9cb093294 100644 --- a/docs-en/chapter_hashing/hash_algorithm.md +++ b/docs-en/chapter_hashing/hash_algorithm.md @@ -469,7 +469,7 @@ The design of hash algorithms is a complex issue that requires consideration of } hash as i32 - } + } /* 乘法哈希 */ fn mul_hash(key: &str) -> i32 { diff --git a/docs-en/chapter_hashing/hash_collision.md b/docs-en/chapter_hashing/hash_collision.md index 37c42a3c5..755d4a80e 100644 --- a/docs-en/chapter_hashing/hash_collision.md +++ b/docs-en/chapter_hashing/hash_collision.md @@ -1863,129 +1863,113 @@ The code below implements an open addressing (linear probing) hash table with la capacity int // 哈希表容量 loadThres float64 // 触发扩容的负载因子阈值 extendRatio int // 扩容倍数 - buckets []pair // 桶数组 - removed pair // 删除标记 + buckets []*pair // 桶数组 + TOMBSTONE *pair // 删除标记 } /* 构造方法 */ func newHashMapOpenAddressing() *hashMapOpenAddressing { - buckets := make([]pair, 4) return &hashMapOpenAddressing{ size: 0, capacity: 4, loadThres: 2.0 / 3.0, extendRatio: 2, - buckets: buckets, - removed: pair{ - key: -1, - val: "-1", - }, + buckets: make([]*pair, 4), + TOMBSTONE: &pair{-1, "-1"}, } } /* 哈希函数 */ - func (m *hashMapOpenAddressing) hashFunc(key int) int { - return key % m.capacity + func (h *hashMapOpenAddressing) hashFunc(key int) int { + return key % h.capacity // 根据键计算哈希值 } /* 负载因子 */ - func (m *hashMapOpenAddressing) loadFactor() float64 { - return float64(m.size) / float64(m.capacity) + func (h *hashMapOpenAddressing) loadFactor() float64 { + return float64(h.size) / float64(h.capacity) // 计算当前负载因子 + } + + /* 搜索 key 对应的桶索引 */ + func (h *hashMapOpenAddressing) findBucket(key int) int { + index := h.hashFunc(key) // 获取初始索引 + firstTombstone := -1 // 记录遇到的第一个TOMBSTONE的位置 + for h.buckets[index] != nil { + if h.buckets[index].key == key { + if firstTombstone != -1 { + // 若之前遇到了删除标记,则将键值对移动至该索引处 + h.buckets[firstTombstone] = h.buckets[index] + h.buckets[index] = h.TOMBSTONE + return firstTombstone // 返回移动后的桶索引 + } + return index // 返回找到的索引 + } + if firstTombstone == -1 && h.buckets[index] == h.TOMBSTONE { + firstTombstone = index // 记录遇到的首个删除标记的位置 + } + index = (index + 1) % h.capacity // 线性探测,越过尾部则返回头部 + } + // 若 key 不存在,则返回添加点的索引 + if firstTombstone != -1 { + return firstTombstone + } + return index } /* 查询操作 */ - func (m *hashMapOpenAddressing) get(key int) string { - idx := m.hashFunc(key) - // 线性探测,从 index 开始向后遍历 - for i := 0; i < m.capacity; i++ { - // 计算桶索引,越过尾部则返回头部 - j := (idx + i) % m.capacity - // 若遇到空桶,说明无此 key ,则返回 null - if m.buckets[j] == (pair{}) { - return "" - } - // 若遇到指定 key ,则返回对应 val - if m.buckets[j].key == key && m.buckets[j] != m.removed { - return m.buckets[j].val - } + func (h *hashMapOpenAddressing) get(key int) string { + index := h.findBucket(key) // 搜索 key 对应的桶索引 + if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE { + return h.buckets[index].val // 若找到键值对,则返回对应 val } - // 若未找到 key ,则返回空字符串 - return "" + return "" // 若键值对不存在,则返回 "" } /* 添加操作 */ - func (m *hashMapOpenAddressing) put(key int, val string) { - // 当负载因子超过阈值时,执行扩容 - if m.loadFactor() > m.loadThres { - m.extend() + func (h *hashMapOpenAddressing) put(key int, val string) { + if h.loadFactor() > h.loadThres { + h.extend() // 当负载因子超过阈值时,执行扩容 } - idx := m.hashFunc(key) - // 线性探测,从 index 开始向后遍历 - for i := 0; i < m.capacity; i++ { - // 计算桶索引,越过尾部则返回头部 - j := (idx + i) % m.capacity - // 若遇到空桶、或带有删除标记的桶,则将键值对放入该桶 - if m.buckets[j] == (pair{}) || m.buckets[j] == m.removed { - m.buckets[j] = pair{ - key: key, - val: val, - } - m.size += 1 - return - } - // 若遇到指定 key ,则更新对应 val - if m.buckets[j].key == key { - m.buckets[j].val = val - return - } + index := h.findBucket(key) // 搜索 key 对应的桶索引 + if h.buckets[index] == nil || h.buckets[index] == h.TOMBSTONE { + h.buckets[index] = &pair{key, val} // 若键值对不存在,则添加该键值对 + h.size++ + } else { + h.buckets[index].val = val // 若找到键值对,则覆盖 val } } /* 删除操作 */ - func (m *hashMapOpenAddressing) remove(key int) { - idx := m.hashFunc(key) - // 遍历桶,从中删除键值对 - // 线性探测,从 index 开始向后遍历 - for i := 0; i < m.capacity; i++ { - // 计算桶索引,越过尾部则返回头部 - j := (idx + i) % m.capacity - // 若遇到空桶,说明无此 key ,则直接返回 - if m.buckets[j] == (pair{}) { - return - } - // 若遇到指定 key ,则标记删除并返回 - if m.buckets[j].key == key { - m.buckets[j] = m.removed - m.size -= 1 - } + func (h *hashMapOpenAddressing) remove(key int) { + index := h.findBucket(key) // 搜索 key 对应的桶索引 + if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE { + h.buckets[index] = h.TOMBSTONE // 若找到键值对,则用删除标记覆盖它 + h.size-- } } /* 扩容哈希表 */ - func (m *hashMapOpenAddressing) extend() { - // 暂存原哈希表 - tmpBuckets := make([]pair, len(m.buckets)) - copy(tmpBuckets, m.buckets) - - // 初始化扩容后的新哈希表 - m.capacity *= m.extendRatio - m.buckets = make([]pair, m.capacity) - m.size = 0 + func (h *hashMapOpenAddressing) extend() { + oldBuckets := h.buckets // 暂存原哈希表 + h.capacity *= h.extendRatio // 更新容量 + h.buckets = make([]*pair, h.capacity) // 初始化扩容后的新哈希表 + h.size = 0 // 重置大小 // 将键值对从原哈希表搬运至新哈希表 - for _, p := range tmpBuckets { - if p != (pair{}) && p != m.removed { - m.put(p.key, p.val) + for _, pair := range oldBuckets { + if pair != nil && pair != h.TOMBSTONE { + h.put(pair.key, pair.val) } } } /* 打印哈希表 */ - func (m *hashMapOpenAddressing) print() { - for _, p := range m.buckets { - if p != (pair{}) { - fmt.Println(strconv.Itoa(p.key) + " -> " + p.val) - } else { + func (h *hashMapOpenAddressing) print() { + for _, pair := range h.buckets { + if pair == nil { fmt.Println("nil") + } else if pair == h.TOMBSTONE { + fmt.Println("TOMBSTONE") + } else { + fmt.Printf("%d -> %s\n", pair.key, pair.val) } } } @@ -2540,15 +2524,14 @@ The code below implements an open addressing (linear probing) hash table with la ```rust title="hash_map_open_addressing.rs" /* 开放寻址哈希表 */ struct HashMapOpenAddressing { - size: usize, // 键值对数量 - capacity: usize, // 哈希表容量 - load_thres: f64, // 触发扩容的负载因子阈值 - extend_ratio: usize, // 扩容倍数 - buckets: Vec>, // 桶数组 - TOMBSTONE: Option, // 删除标记 + size: usize, // 键值对数量 + capacity: usize, // 哈希表容量 + load_thres: f64, // 触发扩容的负载因子阈值 + extend_ratio: usize, // 扩容倍数 + buckets: Vec>, // 桶数组 + TOMBSTONE: Option, // 删除标记 } - impl HashMapOpenAddressing { /* 构造方法 */ fn new() -> Self { @@ -2558,7 +2541,10 @@ The code below implements an open addressing (linear probing) hash table with la load_thres: 2.0 / 3.0, extend_ratio: 2, buckets: vec![None; 4], - TOMBSTONE: Some(Pair {key: -1, val: "-1".to_string()}), + TOMBSTONE: Some(Pair { + key: -1, + val: "-1".to_string(), + }), } } @@ -2584,9 +2570,9 @@ The code below implements an open addressing (linear probing) hash table with la 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; // 返回移动后的桶索引 + return first_tombstone as usize; // 返回移动后的桶索引 } - return index; // 返回桶索引 + return index; // 返回桶索引 } // 记录遇到的首个删除标记 if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE { @@ -2596,7 +2582,11 @@ The code below implements an open addressing (linear probing) hash table with la index = (index + 1) % self.capacity; } // 若 key 不存在,则返回添加点的索引 - if first_tombstone == -1 { index } else { first_tombstone as usize } + if first_tombstone == -1 { + index + } else { + first_tombstone as usize + } } /* 查询操作 */ diff --git a/docs-en/chapter_hashing/hash_map.md b/docs-en/chapter_hashing/hash_map.md index 3abf28611..6236774fc 100755 --- a/docs-en/chapter_hashing/hash_map.md +++ b/docs-en/chapter_hashing/hash_map.md @@ -1343,13 +1343,15 @@ The following code implements a simple hash table. Here, we encapsulate `key` an /* 基于数组实现的哈希表 */ pub struct ArrayHashMap { - buckets: Vec> + buckets: Vec>, } impl ArrayHashMap { pub fn new() -> ArrayHashMap { // 初始化数组,包含 100 个桶 - Self { buckets: vec![None; 100] } + Self { + buckets: vec![None; 100], + } } /* 哈希函数 */ @@ -1381,17 +1383,26 @@ The following code implements a simple hash table. Here, we encapsulate `key` an /* 获取所有键值对 */ pub fn entry_set(&self) -> Vec<&Pair> { - self.buckets.iter().filter_map(|pair| pair.as_ref()).collect() + self.buckets + .iter() + .filter_map(|pair| pair.as_ref()) + .collect() } /* 获取所有键 */ pub fn key_set(&self) -> Vec<&i32> { - self.buckets.iter().filter_map(|pair| pair.as_ref().map(|pair| &pair.key)).collect() + self.buckets + .iter() + .filter_map(|pair| pair.as_ref().map(|pair| &pair.key)) + .collect() } /* 获取所有值 */ pub fn value_set(&self) -> Vec<&String> { - self.buckets.iter().filter_map(|pair| pair.as_ref().map(|pair| &pair.val)).collect() + self.buckets + .iter() + .filter_map(|pair| pair.as_ref().map(|pair| &pair.val)) + .collect() } /* 打印哈希表 */ diff --git a/docs-en/chapter_stack_and_queue/deque.md b/docs-en/chapter_stack_and_queue/deque.md index 3aac39caa..7a32f5d79 100644 --- a/docs-en/chapter_stack_and_queue/deque.md +++ b/docs-en/chapter_stack_and_queue/deque.md @@ -1522,9 +1522,9 @@ The implementation code is as follows: /* 基于双向链表实现的双向队列 */ #[allow(dead_code)] pub struct LinkedListDeque { - front: Option>>>, // 头节点 front - rear: Option>>>, // 尾节点 rear - que_size: usize, // 双向队列的长度 + front: Option>>>, // 头节点 front + rear: Option>>>, // 尾节点 rear + que_size: usize, // 双向队列的长度 } impl LinkedListDeque { @@ -1532,7 +1532,7 @@ The implementation code is as follows: Self { front: None, rear: None, - que_size: 0, + que_size: 0, } } @@ -1564,7 +1564,7 @@ The implementation code is as follows: self.front = Some(node); // 更新头节点 } } - } + } // 队尾入队操作 else { match self.rear.take() { @@ -1597,8 +1597,8 @@ The implementation code is as follows: /* 出队操作 */ pub fn pop(&mut self, is_front: bool) -> Option { // 若队列为空,直接返回 None - if self.is_empty() { - return None + if self.is_empty() { + return None; }; // 队首出队操作 if is_front { @@ -1606,7 +1606,7 @@ The implementation code is as follows: match old_front.borrow_mut().next.take() { Some(new_front) => { new_front.borrow_mut().prev.take(); - self.front = Some(new_front); // 更新头节点 + self.front = Some(new_front); // 更新头节点 } None => { self.rear.take(); @@ -1615,15 +1615,14 @@ The implementation code is as follows: self.que_size -= 1; // 更新队列长度 Rc::try_unwrap(old_front).ok().unwrap().into_inner().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); // 更新尾节点 + self.rear = Some(new_rear); // 更新尾节点 } None => { self.front.take(); diff --git a/docs-en/chapter_stack_and_queue/queue.md b/docs-en/chapter_stack_and_queue/queue.md index c306a7f88..8850efb4c 100755 --- a/docs-en/chapter_stack_and_queue/queue.md +++ b/docs-en/chapter_stack_and_queue/queue.md @@ -959,9 +959,9 @@ Below is the code for implementing a queue using a linked list: /* 基于链表实现的队列 */ #[allow(dead_code)] pub struct LinkedListQueue { - front: Option>>>, // 头节点 front - rear: Option>>>, // 尾节点 rear - que_size: usize, // 队列的长度 + front: Option>>>, // 头节点 front + rear: Option>>>, // 尾节点 rear + que_size: usize, // 队列的长度 } impl LinkedListQueue { @@ -969,7 +969,7 @@ Below is the code for implementing a queue using a linked list: Self { front: None, rear: None, - que_size: 0, + que_size: 0, } } @@ -1887,10 +1887,10 @@ For a circular array, `front` or `rear` needs to loop back to the start of the a ```rust title="array_queue.rs" /* 基于环形数组实现的队列 */ struct ArrayQueue { - nums: Vec, // 用于存储队列元素的数组 - front: i32, // 队首指针,指向队首元素 - que_size: i32, // 队列长度 - que_capacity: i32, // 队列容量 + nums: Vec, // 用于存储队列元素的数组 + front: i32, // 队首指针,指向队首元素 + que_size: i32, // 队列长度 + que_capacity: i32, // 队列容量 } impl ArrayQueue { diff --git a/docs-en/chapter_stack_and_queue/stack.md b/docs-en/chapter_stack_and_queue/stack.md index db5fa9079..6b79c2601 100755 --- a/docs-en/chapter_stack_and_queue/stack.md +++ b/docs-en/chapter_stack_and_queue/stack.md @@ -876,8 +876,8 @@ Below is an example code for implementing a stack based on a linked list: /* 基于链表实现的栈 */ #[allow(dead_code)] pub struct LinkedListStack { - stack_peek: Option>>>, // 将头节点作为栈顶 - stk_size: usize, // 栈的长度 + stack_peek: Option>>>, // 将头节点作为栈顶 + stk_size: usize, // 栈的长度 } impl LinkedListStack { @@ -1537,7 +1537,9 @@ Since the elements to be pushed onto the stack may continuously increase, we can impl ArrayStack { /* 初始化栈 */ fn new() -> ArrayStack { - ArrayStack:: { stack: Vec::::new() } + ArrayStack:: { + stack: Vec::::new(), + } } /* 获取栈的长度 */ @@ -1565,7 +1567,9 @@ Since the elements to be pushed onto the stack may continuously increase, we can /* 访问栈顶元素 */ fn peek(&self) -> Option<&T> { - if self.is_empty() { panic!("栈为空") }; + if self.is_empty() { + panic!("栈为空") + }; self.stack.last() } diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md index 72016b527..16964d6b5 100755 --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -517,7 +517,7 @@ comments: true /* 在链表的节点 n0 之后插入节点 P */ #[allow(non_snake_case)] pub fn insert(n0: &Rc>>, P: Rc>>) { - let n1 = n0.borrow_mut().next.take(); + let n1 = n0.borrow_mut().next.take(); P.borrow_mut().next = n1; n0.borrow_mut().next = Some(P); } @@ -695,7 +695,9 @@ comments: true /* 删除链表的节点 n0 之后的首个节点 */ #[allow(non_snake_case)] pub fn remove(n0: &Rc>>) { - if n0.borrow().next.is_none() {return}; + if n0.borrow().next.is_none() { + return; + }; // n0 -> P -> n1 let P = n0.borrow_mut().next.take(); if let Some(node) = P { @@ -877,10 +879,13 @@ comments: true ```rust title="linked_list.rs" /* 访问链表中索引为 index 的节点 */ pub fn access(head: Rc>>, index: i32) -> Rc>> { - if index <= 0 {return head}; - if let Some(node) = &head.borrow_mut().next { + if index <= 0 { + return head; + }; + if let Some(node) = &head.borrow().next { return access(node.clone(), index - 1); } + return head; } ``` @@ -1076,7 +1081,9 @@ comments: true ```rust title="linked_list.rs" /* 在链表中查找值为 target 的首个节点 */ pub fn find(head: Rc>>, target: T, index: i32) -> i32 { - if head.borrow().val == target {return index}; + if head.borrow().val == target { + return index; + }; if let Some(node) = &head.borrow_mut().next { return find(node.clone(), target, index + 1); } diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index c3c87e3d9..62e41e569 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -1815,16 +1815,16 @@ comments: true #[allow(dead_code)] struct MyList { arr: Vec, // 数组(存储列表元素) - capacity: usize, // 列表容量 - size: usize, // 列表长度(当前元素数量) - extend_ratio: usize, // 每次列表扩容的倍数 + capacity: usize, // 列表容量 + size: usize, // 列表长度(当前元素数量) + extend_ratio: usize, // 每次列表扩容的倍数 } - #[allow(unused,unused_comparisons)] + #[allow(unused, unused_comparisons)] impl MyList { /* 构造方法 */ pub fn new(capacity: usize) -> Self { - let mut vec = Vec::new(); + let mut vec = Vec::new(); vec.resize(capacity, 0); Self { arr: vec, @@ -1847,13 +1847,17 @@ comments: true /* 访问元素 */ pub fn get(&self, index: usize) -> i32 { // 索引如果越界,则抛出异常,下同 - if index >= self.size {panic!("索引越界")}; + if index >= self.size { + panic!("索引越界") + }; return self.arr[index]; } /* 更新元素 */ pub fn set(&mut self, index: usize, num: i32) { - if index >= self.size {panic!("索引越界")}; + if index >= self.size { + panic!("索引越界") + }; self.arr[index] = num; } @@ -1870,7 +1874,9 @@ comments: true /* 在中间插入元素 */ pub fn insert(&mut self, index: usize, num: i32) { - if index >= self.size() {panic!("索引越界")}; + if index >= self.size() { + panic!("索引越界") + }; // 元素数量超出容量时,触发扩容机制 if self.size == self.capacity() { self.extend_capacity(); @@ -1886,7 +1892,9 @@ comments: true /* 删除元素 */ pub fn remove(&mut self, index: usize) -> i32 { - if index >= self.size() {panic!("索引越界")}; + if index >= self.size() { + panic!("索引越界") + }; let num = self.arr[index]; // 将将索引 index 之后的元素都向前移动一位 for j in (index..self.size - 1) { diff --git a/docs/chapter_array_and_linkedlist/summary.md b/docs/chapter_array_and_linkedlist/summary.md index c14b12653..07955e5cb 100644 --- a/docs/chapter_array_and_linkedlist/summary.md +++ b/docs/chapter_array_and_linkedlist/summary.md @@ -35,11 +35,11 @@ comments: true # 元素内存地址 = 数组内存地址(首元素内存地址) + 元素长度 * 元素索引 ``` -**Q**:删除节点后,是否需要把 `P.next` 设为 `None` 呢? +**Q**:删除节点 `P` 后,是否需要把 `P.next` 设为 `None` 呢? 不修改 `P.next` 也可以。从该链表的角度看,从头节点遍历到尾节点已经不会遇到 `P` 了。这意味着节点 `P` 已经从链表中删除了,此时节点 `P` 指向哪里都不会对该链表产生影响。 -从垃圾回收的角度看,对于 Java、Python、Go 等拥有自动垃圾回收机制的语言来说,节点 `P` 是否被回收取决于是否仍存在指向它的引用,而不是 `P.next` 的值。在 C 和 C++ 等语言中,我们需要手动释放节点内存。 +从数据结构与算法(做题)的角度看,不断开没有关系,只要保证程序的逻辑是正确的就行。从标准库的角度看,断开更加安全、逻辑更加清晰。如果不断开,假设被删除节点未被正常回收,那么它会影响后继节点的内存回收。 **Q**:在链表中插入和删除操作的时间复杂度是 $O(1)$ 。但是增删之前都需要 $O(n)$ 的时间查找元素,那为什么时间复杂度不是 $O(n)$ 呢? @@ -78,7 +78,3 @@ comments: true **Q**:初始化列表 `res = [0] * self.size()` 操作,会导致 `res` 的每个元素引用相同的地址吗? 不会。但二维数组会有这个问题,例如初始化二维列表 `res = [[0] * self.size()]` ,则多次引用了同一个列表 `[0]` 。 - -**Q**:在删除节点中,需要断开该节点与其后继节点之间的引用指向吗? - -从数据结构与算法(做题)的角度看,不断开没有关系,只要保证程序的逻辑是正确的就行。从标准库的角度看,断开更加安全、逻辑更加清晰。如果不断开,假设被删除节点未被正常回收,那么它会影响后继节点的内存回收。 diff --git a/docs/chapter_backtracking/backtracking_algorithm.md b/docs/chapter_backtracking/backtracking_algorithm.md index 9416d0704..01941dedf 100644 --- a/docs/chapter_backtracking/backtracking_algorithm.md +++ b/docs/chapter_backtracking/backtracking_algorithm.md @@ -428,7 +428,11 @@ comments: true ```rust title="preorder_traversal_ii_compact.rs" /* 前序遍历:例题二 */ - fn pre_order(res: &mut Vec>>>, path: &mut Vec>>, root: Option>>) { + fn pre_order( + res: &mut Vec>>>, + path: &mut Vec>>, + root: Option>>, + ) { if root.is_none() { return; } @@ -442,7 +446,7 @@ comments: true pre_order(res, path, node.borrow().left.clone()); pre_order(res, path, node.borrow().right.clone()); // 回退 - path.remove(path.len() - 1); + path.remove(path.len() - 1); } } ``` @@ -738,7 +742,11 @@ comments: true ```rust title="preorder_traversal_iii_compact.rs" /* 前序遍历:例题三 */ - fn pre_order(res: &mut Vec>>>, path: &mut Vec>>, root: Option>>) { + fn pre_order( + res: &mut Vec>>>, + path: &mut Vec>>, + root: Option>>, + ) { // 剪枝 if root.is_none() || root.as_ref().unwrap().borrow().val == 3 { return; @@ -753,7 +761,7 @@ comments: true pre_order(res, path, node.borrow().left.clone()); pre_order(res, path, node.borrow().right.clone()); // 回退 - path.remove(path.len() - 1); + path.remove(path.len() - 1); } } ``` @@ -1558,7 +1566,10 @@ comments: true } /* 记录解 */ - fn record_solution(state: &mut Vec>>, res: &mut Vec>>>) { + fn record_solution( + state: &mut Vec>>, + res: &mut Vec>>>, + ) { res.push(state.clone()); } @@ -1578,7 +1589,11 @@ comments: true } /* 回溯算法:例题三 */ - fn backtrack(state: &mut Vec>>, choices: &mut Vec>>, res: &mut Vec>>>) { + fn backtrack( + state: &mut Vec>>, + choices: &mut Vec>>, + res: &mut Vec>>>, + ) { // 检查是否为解 if is_solution(state) { // 记录解 @@ -1591,7 +1606,14 @@ comments: true // 尝试:做出选择,更新状态 make_choice(state, choice.clone()); // 进行下一轮选择 - backtrack(state, &mut vec![choice.borrow().left.clone().unwrap(), choice.borrow().right.clone().unwrap()], res); + backtrack( + state, + &mut vec![ + choice.borrow().left.clone().unwrap(), + choice.borrow().right.clone().unwrap(), + ], + res, + ); // 回退:撤销选择,恢复到之前的状态 undo_choice(state, choice.clone()); } diff --git a/docs/chapter_backtracking/n_queens_problem.md b/docs/chapter_backtracking/n_queens_problem.md index c58f3057c..c2efa6cbf 100644 --- a/docs/chapter_backtracking/n_queens_problem.md +++ b/docs/chapter_backtracking/n_queens_problem.md @@ -516,8 +516,15 @@ comments: true ```rust title="n_queens.rs" /* 回溯算法:n 皇后 */ - fn backtrack(row: usize, n: usize, state: &mut Vec>, res: &mut Vec>>, - cols: &mut [bool], diags1: &mut [bool], diags2: &mut [bool]) { + fn backtrack( + row: usize, + n: usize, + state: &mut Vec>, + res: &mut Vec>>, + cols: &mut [bool], + diags1: &mut [bool], + diags2: &mut [bool], + ) { // 当放置完所有行时,记录解 if row == n { let mut copy_state: Vec> = Vec::new(); @@ -562,7 +569,15 @@ comments: true let mut diags2 = vec![false; 2 * n - 1]; // 记录次对角线上是否有皇后 let mut res: Vec>> = Vec::new(); - backtrack(0, n, &mut state, &mut res, &mut cols, &mut diags1, &mut diags2); + backtrack( + 0, + n, + &mut state, + &mut res, + &mut cols, + &mut diags1, + &mut diags2, + ); res } diff --git a/docs/chapter_backtracking/subset_sum_problem.md b/docs/chapter_backtracking/subset_sum_problem.md index bc3923be5..d41a5792f 100644 --- a/docs/chapter_backtracking/subset_sum_problem.md +++ b/docs/chapter_backtracking/subset_sum_problem.md @@ -354,7 +354,13 @@ comments: true ```rust title="subset_sum_i_naive.rs" /* 回溯算法:子集和 I */ - fn backtrack(mut state: Vec, target: i32, total: i32, choices: &[i32], res: &mut Vec>) { + fn backtrack( + mut state: Vec, + target: i32, + total: i32, + choices: &[i32], + res: &mut Vec>, + ) { // 子集和等于 target 时,记录解 if total == target { res.push(state); @@ -830,7 +836,13 @@ comments: true ```rust title="subset_sum_i.rs" /* 回溯算法:子集和 I */ - fn backtrack(mut state: Vec, target: i32, choices: &[i32], start: usize, res: &mut Vec>) { + fn backtrack( + mut state: Vec, + target: i32, + choices: &[i32], + start: usize, + res: &mut Vec>, + ) { // 子集和等于 target 时,记录解 if target == 0 { res.push(state); @@ -1344,7 +1356,13 @@ comments: true ```rust title="subset_sum_ii.rs" /* 回溯算法:子集和 II */ - fn backtrack(mut state: Vec, target: i32, choices: &[i32], start: usize, res: &mut Vec>) { + fn backtrack( + mut state: Vec, + target: i32, + choices: &[i32], + start: usize, + res: &mut Vec>, + ) { // 子集和等于 target 时,记录解 if target == 0 { res.push(state); diff --git a/docs/chapter_computational_complexity/iteration_and_recursion.md b/docs/chapter_computational_complexity/iteration_and_recursion.md index dd7dea4c3..6947dcbc7 100644 --- a/docs/chapter_computational_complexity/iteration_and_recursion.md +++ b/docs/chapter_computational_complexity/iteration_and_recursion.md @@ -151,7 +151,7 @@ comments: true res += i; } res - } + } ``` === "C" @@ -352,6 +352,7 @@ comments: true fn while_loop(n: i32) -> i32 { let mut res = 0; let mut i = 1; // 初始化条件变量 + // 循环求和 1, 2, ..., n-1, n while i <= n { res += i; @@ -570,6 +571,7 @@ comments: true fn while_loop_ii(n: i32) -> i32 { let mut res = 0; let mut i = 1; // 初始化条件变量 + // 循环求和 1, 4, 10, ... while i <= n { res += i; diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 02e684816..c2c47eac6 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -978,7 +978,7 @@ $$ ```rust title="space_complexity.rs" /* 函数 */ - fn function() ->i32 { + fn function() -> i32 { // 执行某些操作 return 0; } @@ -1451,7 +1451,9 @@ $$ /* 线性阶(递归实现) */ fn linear_recur(n: i32) { println!("递归 n = {}", n); - if n == 1 {return}; + if n == 1 { + return; + }; linear_recur(n - 1); } ``` @@ -1833,7 +1835,9 @@ $$ ```rust title="space_complexity.rs" /* 平方阶(递归实现) */ fn quadratic_recur(n: i32) -> i32 { - if n <= 0 {return 0}; + if n <= 0 { + return 0; + }; // 数组 nums 长度为 n, n-1, ..., 2, 1 let nums = vec![0; n as usize]; println!("递归 n = {} 中的 nums 长度 = {}", n, nums.len()); @@ -2010,7 +2014,9 @@ $$ ```rust title="space_complexity.rs" /* 指数阶(建立满二叉树) */ fn build_tree(n: i32) -> Option>> { - if n == 0 {return None}; + 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); diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index 8d2782cb4..4f3f7dcc2 100755 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -1741,7 +1741,7 @@ $$ int count = 0; // 计数器 // 外循环:未排序区间为 [0, i] for (int i = nums.Length - 1; i > 0; i--) { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -1785,7 +1785,7 @@ $$ var count = 0 // 计数器 // 外循环:未排序区间为 [0, i] for i in stride(from: nums.count - 1, to: 0, by: -1) { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in 0 ..< i { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] @@ -1875,9 +1875,10 @@ $$ /* 平方阶(冒泡排序) */ fn bubble_sort(nums: &mut [i32]) -> i32 { let mut count = 0; // 计数器 + // 外循环:未排序区间为 [0, i] for i in (1..nums.len()).rev() { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in 0..i { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] @@ -1925,7 +1926,7 @@ $$ var i: i32 = @as(i32, @intCast(nums.len)) - 1; while (i > 0) : (i -= 1) { var j: usize = 0; - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 while (j < i) : (j += 1) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -2796,10 +2797,10 @@ $$ return 1; } let mut count = linear_log_recur(n / 2.0) + linear_log_recur(n / 2.0); - for _ in 0 ..n as i32 { + for _ in 0..n as i32 { count += 1; } - return count + return count; } ``` diff --git a/docs/chapter_divide_and_conquer/binary_search_recur.md b/docs/chapter_divide_and_conquer/binary_search_recur.md index 938787cdf..bb0545acd 100644 --- a/docs/chapter_divide_and_conquer/binary_search_recur.md +++ b/docs/chapter_divide_and_conquer/binary_search_recur.md @@ -329,7 +329,9 @@ comments: true /* 二分查找:问题 f(i, j) */ fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 { // 若区间为空,代表无目标元素,则返回 -1 - if i > j { return -1; } + if i > j { + return -1; + } let m: i32 = (i + j) / 2; if nums[m as usize] < target { // 递归子问题 f(m+1, j) diff --git a/docs/chapter_divide_and_conquer/build_binary_tree_problem.md b/docs/chapter_divide_and_conquer/build_binary_tree_problem.md index 9550a8ad4..b6bb81582 100644 --- a/docs/chapter_divide_and_conquer/build_binary_tree_problem.md +++ b/docs/chapter_divide_and_conquer/build_binary_tree_problem.md @@ -374,9 +374,17 @@ comments: true ```rust title="build_tree.rs" /* 构建二叉树:分治 */ - fn dfs(preorder: &[i32], inorder_map: &HashMap, i: i32, l: i32, r: i32) -> Option>> { + fn dfs( + preorder: &[i32], + inorder_map: &HashMap, + i: i32, + l: i32, + r: i32, + ) -> Option>> { // 子树区间为空时终止 - if r - l < 0 { return None; } + if r - l < 0 { + return None; + } // 初始化根节点 let root = TreeNode::new(preorder[i as usize]); // 查询 m ,从而划分左右子树 diff --git a/docs/chapter_dynamic_programming/dp_problem_features.md b/docs/chapter_dynamic_programming/dp_problem_features.md index a4cc48cdf..264231946 100644 --- a/docs/chapter_dynamic_programming/dp_problem_features.md +++ b/docs/chapter_dynamic_programming/dp_problem_features.md @@ -241,7 +241,9 @@ $$ /* 爬楼梯最小代价:动态规划 */ fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 { let n = cost.len() - 1; - if n == 1 || n == 2 { return cost[n]; } + if n == 1 || n == 2 { + return cost[n]; + } // 初始化 dp 表,用于存储子问题的解 let mut dp = vec![-1; n + 1]; // 初始状态:预设最小子问题的解 @@ -489,7 +491,9 @@ $$ /* 爬楼梯最小代价:空间优化后的动态规划 */ fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { let n = cost.len() - 1; - if n == 1 || n == 2 { return cost[n] }; + if n == 1 || n == 2 { + return cost[n]; + }; let (mut a, mut b) = (cost[1], cost[2]); for i in 3..=n { let tmp = b; @@ -802,7 +806,9 @@ $$ ```rust title="climbing_stairs_constraint_dp.rs" /* 带约束爬楼梯:动态规划 */ fn climbing_stairs_constraint_dp(n: usize) -> i32 { - if n == 1 || n == 2 { return 1 }; + if n == 1 || n == 2 { + return 1; + }; // 初始化 dp 表,用于存储子问题的解 let mut dp = vec![vec![-1; 3]; n + 1]; // 初始状态:预设最小子问题的解 diff --git a/docs/chapter_dynamic_programming/edit_distance_problem.md b/docs/chapter_dynamic_programming/edit_distance_problem.md index 201ca05bb..a760d2d67 100644 --- a/docs/chapter_dynamic_programming/edit_distance_problem.md +++ b/docs/chapter_dynamic_programming/edit_distance_problem.md @@ -360,7 +360,7 @@ $$ let (n, m) = (s.len(), t.len()); let mut dp = vec![vec![0; m + 1]; n + 1]; // 状态转移:首行首列 - for i in 1..= n { + for i in 1..=n { dp[i][0] = i as i32; } for j in 1..m { @@ -374,7 +374,8 @@ $$ 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; + dp[i][j] = + std::cmp::min(std::cmp::min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } } } diff --git a/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md b/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md index d1f1e1384..74f6ac2f3 100644 --- a/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md +++ b/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md @@ -296,11 +296,15 @@ comments: true /* 回溯 */ fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) { // 当爬到第 n 阶时,方案数量加 1 - if state == n { res[0] = res[0] + 1; } + if state == n { + res[0] = res[0] + 1; + } // 遍历所有选择 for &choice in choices { // 剪枝:不允许越过第 n 阶 - if state + choice > n { continue; } + if state + choice > n { + continue; + } // 尝试:做出选择,更新状态 backtrack(choices, state + choice, n, res); // 回退 @@ -309,7 +313,7 @@ comments: true /* 爬楼梯:回溯 */ fn climbing_stairs_backtrack(n: usize) -> i32 { - let choices = vec![ 1, 2 ]; // 可选择向上爬 1 阶或 2 阶 + let choices = vec![1, 2]; // 可选择向上爬 1 阶或 2 阶 let state = 0; // 从第 0 阶开始爬 let mut res = Vec::new(); res.push(0); // 使用 res[0] 记录方案数量 @@ -592,7 +596,9 @@ $$ /* 搜索 */ fn dfs(i: usize) -> i32 { // 已知 dp[1] 和 dp[2] ,返回之 - if i == 1 || i == 2 { return i as i32; } + if i == 1 || i == 2 { + return i as i32; + } // dp[i] = dp[i-1] + dp[i-2] let count = dfs(i - 1) + dfs(i - 2); count @@ -600,7 +606,7 @@ $$ /* 爬楼梯:搜索 */ fn climbing_stairs_dfs(n: usize) -> i32 { - dfs(n) + dfs(n) } ``` @@ -908,9 +914,13 @@ $$ /* 记忆化搜索 */ fn dfs(i: usize, mem: &mut [i32]) -> i32 { // 已知 dp[1] 和 dp[2] ,返回之 - if i == 1 || i == 2 { return i as i32; } + if i == 1 || i == 2 { + return i as i32; + } // 若存在记录 dp[i] ,则直接返回之 - if mem[i] != -1 { return mem[i]; } + if mem[i] != -1 { + return mem[i]; + } // dp[i] = dp[i-1] + dp[i-2] let count = dfs(i - 1, mem) + dfs(i - 2, mem); // 记录 dp[i] @@ -1186,7 +1196,9 @@ $$ /* 爬楼梯:动态规划 */ fn climbing_stairs_dp(n: usize) -> i32 { // 已知 dp[1] 和 dp[2] ,返回之 - if n == 1 || n == 2 { return n as i32; } + if n == 1 || n == 2 { + return n as i32; + } // 初始化 dp 表,用于存储子问题的解 let mut dp = vec![-1; n + 1]; // 初始状态:预设最小子问题的解 @@ -1420,7 +1432,9 @@ $$ ```rust title="climbing_stairs_dp.rs" /* 爬楼梯:空间优化后的动态规划 */ fn climbing_stairs_dp_comp(n: usize) -> i32 { - if n == 1 || n == 2 { return n as i32; } + if n == 1 || n == 2 { + return n as i32; + } let (mut a, mut b) = (1, 2); for _ in 3..=n { let tmp = b; diff --git a/docs/chapter_dynamic_programming/knapsack_problem.md b/docs/chapter_dynamic_programming/knapsack_problem.md index b48b9887e..830dcdcdc 100644 --- a/docs/chapter_dynamic_programming/knapsack_problem.md +++ b/docs/chapter_dynamic_programming/knapsack_problem.md @@ -919,7 +919,10 @@ $$ 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]); + dp[i][c] = std::cmp::max( + dp[i - 1][c], + dp[i - 1][c - wgt[i - 1] as usize] + val[i - 1], + ); } } } diff --git a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md index 4bc231111..7e8d6c017 100644 --- a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md +++ b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md @@ -1002,7 +1002,7 @@ $$ // 初始化 dp 表 let mut dp = vec![vec![0; amt + 1]; n + 1]; // 状态转移:首行首列 - for a in 1..= amt { + for a in 1..=amt { dp[0][a] = max; } // 状态转移:其余行和列 @@ -1017,7 +1017,11 @@ $$ } } } - if dp[n][amt] != max { return dp[n][amt] as i32; } else { -1 } + if dp[n][amt] != max { + return dp[n][amt] as i32; + } else { + -1 + } } ``` @@ -1412,7 +1416,11 @@ $$ } } } - if dp[amt] != max { return dp[amt] as i32; } else { -1 } + if dp[amt] != max { + return dp[amt] as i32; + } else { + -1 + } } ``` @@ -1768,7 +1776,7 @@ $$ // 初始化 dp 表 let mut dp = vec![vec![0; amt + 1]; n + 1]; // 初始化首列 - for i in 0..= n { + for i in 0..=n { dp[i][0] = 1; } // 状态转移 diff --git a/docs/chapter_graph/graph_traversal.md b/docs/chapter_graph/graph_traversal.md index 438079dda..49337afcb 100644 --- a/docs/chapter_graph/graph_traversal.md +++ b/docs/chapter_graph/graph_traversal.md @@ -323,7 +323,8 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先 while !que.is_empty() { let vet = que.pop_front().unwrap(); // 队首顶点出队 res.push(vet); // 记录访问顶点 - // 遍历该顶点的所有邻接顶点 + + // 遍历该顶点的所有邻接顶点 if let Some(adj_vets) = graph.adj_list.get(&vet) { for &adj_vet in adj_vets { if visited.contains(&adj_vet) { diff --git a/docs/chapter_hashing/hash_algorithm.md b/docs/chapter_hashing/hash_algorithm.md index a7b901cb2..8346c461d 100644 --- a/docs/chapter_hashing/hash_algorithm.md +++ b/docs/chapter_hashing/hash_algorithm.md @@ -469,7 +469,7 @@ index = hash(key) % capacity } hash as i32 - } + } /* 乘法哈希 */ fn mul_hash(key: &str) -> i32 { diff --git a/docs/chapter_hashing/hash_collision.md b/docs/chapter_hashing/hash_collision.md index 929d614d4..bd7d37ed5 100644 --- a/docs/chapter_hashing/hash_collision.md +++ b/docs/chapter_hashing/hash_collision.md @@ -1863,129 +1863,113 @@ comments: true capacity int // 哈希表容量 loadThres float64 // 触发扩容的负载因子阈值 extendRatio int // 扩容倍数 - buckets []pair // 桶数组 - removed pair // 删除标记 + buckets []*pair // 桶数组 + TOMBSTONE *pair // 删除标记 } /* 构造方法 */ func newHashMapOpenAddressing() *hashMapOpenAddressing { - buckets := make([]pair, 4) return &hashMapOpenAddressing{ size: 0, capacity: 4, loadThres: 2.0 / 3.0, extendRatio: 2, - buckets: buckets, - removed: pair{ - key: -1, - val: "-1", - }, + buckets: make([]*pair, 4), + TOMBSTONE: &pair{-1, "-1"}, } } /* 哈希函数 */ - func (m *hashMapOpenAddressing) hashFunc(key int) int { - return key % m.capacity + func (h *hashMapOpenAddressing) hashFunc(key int) int { + return key % h.capacity // 根据键计算哈希值 } /* 负载因子 */ - func (m *hashMapOpenAddressing) loadFactor() float64 { - return float64(m.size) / float64(m.capacity) + func (h *hashMapOpenAddressing) loadFactor() float64 { + return float64(h.size) / float64(h.capacity) // 计算当前负载因子 + } + + /* 搜索 key 对应的桶索引 */ + func (h *hashMapOpenAddressing) findBucket(key int) int { + index := h.hashFunc(key) // 获取初始索引 + firstTombstone := -1 // 记录遇到的第一个TOMBSTONE的位置 + for h.buckets[index] != nil { + if h.buckets[index].key == key { + if firstTombstone != -1 { + // 若之前遇到了删除标记,则将键值对移动至该索引处 + h.buckets[firstTombstone] = h.buckets[index] + h.buckets[index] = h.TOMBSTONE + return firstTombstone // 返回移动后的桶索引 + } + return index // 返回找到的索引 + } + if firstTombstone == -1 && h.buckets[index] == h.TOMBSTONE { + firstTombstone = index // 记录遇到的首个删除标记的位置 + } + index = (index + 1) % h.capacity // 线性探测,越过尾部则返回头部 + } + // 若 key 不存在,则返回添加点的索引 + if firstTombstone != -1 { + return firstTombstone + } + return index } /* 查询操作 */ - func (m *hashMapOpenAddressing) get(key int) string { - idx := m.hashFunc(key) - // 线性探测,从 index 开始向后遍历 - for i := 0; i < m.capacity; i++ { - // 计算桶索引,越过尾部则返回头部 - j := (idx + i) % m.capacity - // 若遇到空桶,说明无此 key ,则返回 null - if m.buckets[j] == (pair{}) { - return "" - } - // 若遇到指定 key ,则返回对应 val - if m.buckets[j].key == key && m.buckets[j] != m.removed { - return m.buckets[j].val - } + func (h *hashMapOpenAddressing) get(key int) string { + index := h.findBucket(key) // 搜索 key 对应的桶索引 + if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE { + return h.buckets[index].val // 若找到键值对,则返回对应 val } - // 若未找到 key ,则返回空字符串 - return "" + return "" // 若键值对不存在,则返回 "" } /* 添加操作 */ - func (m *hashMapOpenAddressing) put(key int, val string) { - // 当负载因子超过阈值时,执行扩容 - if m.loadFactor() > m.loadThres { - m.extend() + func (h *hashMapOpenAddressing) put(key int, val string) { + if h.loadFactor() > h.loadThres { + h.extend() // 当负载因子超过阈值时,执行扩容 } - idx := m.hashFunc(key) - // 线性探测,从 index 开始向后遍历 - for i := 0; i < m.capacity; i++ { - // 计算桶索引,越过尾部则返回头部 - j := (idx + i) % m.capacity - // 若遇到空桶、或带有删除标记的桶,则将键值对放入该桶 - if m.buckets[j] == (pair{}) || m.buckets[j] == m.removed { - m.buckets[j] = pair{ - key: key, - val: val, - } - m.size += 1 - return - } - // 若遇到指定 key ,则更新对应 val - if m.buckets[j].key == key { - m.buckets[j].val = val - return - } + index := h.findBucket(key) // 搜索 key 对应的桶索引 + if h.buckets[index] == nil || h.buckets[index] == h.TOMBSTONE { + h.buckets[index] = &pair{key, val} // 若键值对不存在,则添加该键值对 + h.size++ + } else { + h.buckets[index].val = val // 若找到键值对,则覆盖 val } } /* 删除操作 */ - func (m *hashMapOpenAddressing) remove(key int) { - idx := m.hashFunc(key) - // 遍历桶,从中删除键值对 - // 线性探测,从 index 开始向后遍历 - for i := 0; i < m.capacity; i++ { - // 计算桶索引,越过尾部则返回头部 - j := (idx + i) % m.capacity - // 若遇到空桶,说明无此 key ,则直接返回 - if m.buckets[j] == (pair{}) { - return - } - // 若遇到指定 key ,则标记删除并返回 - if m.buckets[j].key == key { - m.buckets[j] = m.removed - m.size -= 1 - } + func (h *hashMapOpenAddressing) remove(key int) { + index := h.findBucket(key) // 搜索 key 对应的桶索引 + if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE { + h.buckets[index] = h.TOMBSTONE // 若找到键值对,则用删除标记覆盖它 + h.size-- } } /* 扩容哈希表 */ - func (m *hashMapOpenAddressing) extend() { - // 暂存原哈希表 - tmpBuckets := make([]pair, len(m.buckets)) - copy(tmpBuckets, m.buckets) - - // 初始化扩容后的新哈希表 - m.capacity *= m.extendRatio - m.buckets = make([]pair, m.capacity) - m.size = 0 + func (h *hashMapOpenAddressing) extend() { + oldBuckets := h.buckets // 暂存原哈希表 + h.capacity *= h.extendRatio // 更新容量 + h.buckets = make([]*pair, h.capacity) // 初始化扩容后的新哈希表 + h.size = 0 // 重置大小 // 将键值对从原哈希表搬运至新哈希表 - for _, p := range tmpBuckets { - if p != (pair{}) && p != m.removed { - m.put(p.key, p.val) + for _, pair := range oldBuckets { + if pair != nil && pair != h.TOMBSTONE { + h.put(pair.key, pair.val) } } } /* 打印哈希表 */ - func (m *hashMapOpenAddressing) print() { - for _, p := range m.buckets { - if p != (pair{}) { - fmt.Println(strconv.Itoa(p.key) + " -> " + p.val) - } else { + func (h *hashMapOpenAddressing) print() { + for _, pair := range h.buckets { + if pair == nil { fmt.Println("nil") + } else if pair == h.TOMBSTONE { + fmt.Println("TOMBSTONE") + } else { + fmt.Printf("%d -> %s\n", pair.key, pair.val) } } } @@ -2540,15 +2524,14 @@ comments: true ```rust title="hash_map_open_addressing.rs" /* 开放寻址哈希表 */ struct HashMapOpenAddressing { - size: usize, // 键值对数量 - capacity: usize, // 哈希表容量 - load_thres: f64, // 触发扩容的负载因子阈值 - extend_ratio: usize, // 扩容倍数 - buckets: Vec>, // 桶数组 - TOMBSTONE: Option, // 删除标记 + size: usize, // 键值对数量 + capacity: usize, // 哈希表容量 + load_thres: f64, // 触发扩容的负载因子阈值 + extend_ratio: usize, // 扩容倍数 + buckets: Vec>, // 桶数组 + TOMBSTONE: Option, // 删除标记 } - impl HashMapOpenAddressing { /* 构造方法 */ fn new() -> Self { @@ -2558,7 +2541,10 @@ comments: true load_thres: 2.0 / 3.0, extend_ratio: 2, buckets: vec![None; 4], - TOMBSTONE: Some(Pair {key: -1, val: "-1".to_string()}), + TOMBSTONE: Some(Pair { + key: -1, + val: "-1".to_string(), + }), } } @@ -2584,9 +2570,9 @@ comments: true 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; // 返回移动后的桶索引 + return first_tombstone as usize; // 返回移动后的桶索引 } - return index; // 返回桶索引 + return index; // 返回桶索引 } // 记录遇到的首个删除标记 if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE { @@ -2596,7 +2582,11 @@ comments: true index = (index + 1) % self.capacity; } // 若 key 不存在,则返回添加点的索引 - if first_tombstone == -1 { index } else { first_tombstone as usize } + if first_tombstone == -1 { + index + } else { + first_tombstone as usize + } } /* 查询操作 */ diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 680d031bc..1b2648bee 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -1343,13 +1343,15 @@ index = hash(key) % capacity /* 基于数组实现的哈希表 */ pub struct ArrayHashMap { - buckets: Vec> + buckets: Vec>, } impl ArrayHashMap { pub fn new() -> ArrayHashMap { // 初始化数组,包含 100 个桶 - Self { buckets: vec![None; 100] } + Self { + buckets: vec![None; 100], + } } /* 哈希函数 */ @@ -1381,17 +1383,26 @@ index = hash(key) % capacity /* 获取所有键值对 */ pub fn entry_set(&self) -> Vec<&Pair> { - self.buckets.iter().filter_map(|pair| pair.as_ref()).collect() + self.buckets + .iter() + .filter_map(|pair| pair.as_ref()) + .collect() } /* 获取所有键 */ pub fn key_set(&self) -> Vec<&i32> { - self.buckets.iter().filter_map(|pair| pair.as_ref().map(|pair| &pair.key)).collect() + self.buckets + .iter() + .filter_map(|pair| pair.as_ref().map(|pair| &pair.key)) + .collect() } /* 获取所有值 */ pub fn value_set(&self) -> Vec<&String> { - self.buckets.iter().filter_map(|pair| pair.as_ref().map(|pair| &pair.val)).collect() + self.buckets + .iter() + .filter_map(|pair| pair.as_ref().map(|pair| &pair.val)) + .collect() } /* 打印哈希表 */ diff --git a/docs/chapter_paperbook/index.md b/docs/chapter_paperbook/index.md index 5066e1fb6..3f1c5514d 100644 --- a/docs/chapter_paperbook/index.md +++ b/docs/chapter_paperbook/index.md @@ -4,7 +4,7 @@ icon: fontawesome/solid/book status: new --- -# 纸质书介绍 +# 纸质书 经过长时间的打磨,《Hello 算法》纸质书终于发布了!此时的心情可以用一句诗来形容: diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index a8d52d98f..91588c76f 100755 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -274,14 +274,17 @@ comments: true let mut j = nums.len() as i32 - 1; // 循环,当搜索区间为空时跳出(当 i > j 时为空) while i <= j { - let m = i + (j - i) / 2; // 计算中点索引 m - if nums[m as usize] < target { // 此情况说明 target 在区间 [m+1, 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] 中 + } else if nums[m as usize] > target { + // 此情况说明 target 在区间 [i, m-1] 中 j = m - 1; - } else { // 找到目标元素,返回其索引 + } else { + // 找到目标元素,返回其索引 return m; - } + } } // 未找到目标元素,返回 -1 return -1; @@ -570,14 +573,17 @@ comments: true let mut j = nums.len() as i32; // 循环,当搜索区间为空时跳出(当 i = j 时为空) while i < j { - let m = i + (j - i) / 2; // 计算中点索引 m - if nums[m as usize] < target { // 此情况说明 target 在区间 [m+1, 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) 中 + } else if nums[m as usize] > target { + // 此情况说明 target 在区间 [i, m) 中 j = m; - } else { // 找到目标元素,返回其索引 + } else { + // 找到目标元素,返回其索引 return m; - } + } } // 未找到目标元素,返回 -1 return -1; diff --git a/docs/chapter_searching/binary_search_insertion.md b/docs/chapter_searching/binary_search_insertion.md index a6cb22fbf..6bffb0a0d 100644 --- a/docs/chapter_searching/binary_search_insertion.md +++ b/docs/chapter_searching/binary_search_insertion.md @@ -229,13 +229,13 @@ comments: true ```rust title="binary_search_insertion.rs" /* 二分查找插入点(无重复元素) */ fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 { - let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] + let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] while i <= j { - let m = i + (j - i) / 2; // 计算中点索引 m + let m = i + (j - i) / 2; // 计算中点索引 m if nums[m as usize] < target { - i = m + 1; // target 在区间 [m+1, j] 中 + i = m + 1; // target 在区间 [m+1, j] 中 } else if nums[m as usize] > target { - j = m - 1; // target 在区间 [i, m-1] 中 + j = m - 1; // target 在区间 [i, m-1] 中 } else { return m; } @@ -531,15 +531,15 @@ comments: true ```rust title="binary_search_insertion.rs" /* 二分查找插入点(存在重复元素) */ pub fn binary_search_insertion(nums: &[i32], target: i32) -> i32 { - let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] + let (mut i, mut j) = (0, nums.len() as i32 - 1); // 初始化双闭区间 [0, n-1] while i <= j { - let m = i + (j - i) / 2; // 计算中点索引 m + let m = i + (j - i) / 2; // 计算中点索引 m if nums[m as usize] < target { - i = m + 1; // target 在区间 [m+1, j] 中 + i = m + 1; // target 在区间 [m+1, j] 中 } else if nums[m as usize] > target { - j = m - 1; // target 在区间 [i, m-1] 中 + j = m - 1; // target 在区间 [i, m-1] 中 } else { - j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 + j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 } } // 返回插入点 i diff --git a/docs/chapter_searching/replace_linear_by_hashing.md b/docs/chapter_searching/replace_linear_by_hashing.md index 33b7a8306..190f79322 100755 --- a/docs/chapter_searching/replace_linear_by_hashing.md +++ b/docs/chapter_searching/replace_linear_by_hashing.md @@ -433,7 +433,7 @@ comments: true 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) + None => dic.insert(num, i as i32), }; } None diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index e8c461a9a..604b897a5 100755 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -107,7 +107,7 @@ comments: true void BubbleSort(int[] nums) { // 外循环:未排序区间为 [0, i] for (int i = nums.Length - 1; i > 0; i--) { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -143,7 +143,7 @@ comments: true func bubbleSort(nums: inout [Int]) { // 外循环:未排序区间为 [0, i] for i in stride(from: nums.count - 1, to: 0, by: -1) { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in stride(from: 0, to: i, by: 1) { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] @@ -223,7 +223,7 @@ comments: true fn bubble_sort(nums: &mut [i32]) { // 外循环:未排序区间为 [0, i] for i in (1..nums.len()).rev() { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in 0..i { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] @@ -264,7 +264,7 @@ comments: true var i: usize = nums.len - 1; while (i > 0) : (i -= 1) { var j: usize = 0; - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 while (j < i) : (j += 1) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -362,7 +362,7 @@ comments: true // 外循环:未排序区间为 [0, i] for (int i = nums.Length - 1; i > 0; i--) { bool flag = false; // 初始化标志位 - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -499,17 +499,19 @@ comments: true // 外循环:未排序区间为 [0, i] for i in (1..nums.len()).rev() { let mut flag = false; // 初始化标志位 - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for j in 0..i { if nums[j] > nums[j + 1] { // 交换 nums[j] 与 nums[j + 1] let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - flag = true; // 记录交换元素 + flag = true; // 记录交换元素 } } - if !flag {break}; // 此轮“冒泡”未交换任何元素,直接跳出 + if !flag { + break; // 此轮“冒泡”未交换任何元素,直接跳出 + }; } } ``` @@ -547,7 +549,7 @@ comments: true while (i > 0) : (i -= 1) { var flag = false; // 初始化标志位 var j: usize = 0; - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 while (j < i) : (j += 1) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] diff --git a/docs/chapter_sorting/insertion_sort.md b/docs/chapter_sorting/insertion_sort.md index 9f1033e56..a2669d6d8 100755 --- a/docs/chapter_sorting/insertion_sort.md +++ b/docs/chapter_sorting/insertion_sort.md @@ -200,13 +200,13 @@ comments: true 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); + 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; } - nums[(j + 1) as usize] = base; // 将 base 赋值到正确位置 + nums[(j + 1) as usize] = base; // 将 base 赋值到正确位置 } } ``` diff --git a/docs/chapter_sorting/merge_sort.md b/docs/chapter_sorting/merge_sort.md index 68b6aea38..9aaaea74b 100755 --- a/docs/chapter_sorting/merge_sort.md +++ b/docs/chapter_sorting/merge_sort.md @@ -521,11 +521,15 @@ comments: true /* 归并排序 */ fn merge_sort(nums: &mut [i32], left: usize, right: usize) { // 终止条件 - if left >= right { return; } // 当子数组长度为 1 时终止递归 + if left >= right { + return; // 当子数组长度为 1 时终止递归 + } + // 划分阶段 - let mid = (left + right) / 2; // 计算中点 - merge_sort(nums, left, mid); // 递归左子数组 - merge_sort(nums, mid + 1, right); // 递归右子数组 + let mid = (left + right) / 2; // 计算中点 + merge_sort(nums, left, mid); // 递归左子数组 + merge_sort(nums, mid + 1, right); // 递归右子数组 + // 合并阶段 merge(nums, left, mid, right); } diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md index a43c9bbe8..3b29f1c90 100755 --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -287,15 +287,15 @@ comments: true let (mut i, mut j) = (left, right); while i < j { while i < j && nums[j] >= nums[left] { - j -= 1; // 从右向左找首个小于基准数的元素 + j -= 1; // 从右向左找首个小于基准数的元素 } while i < j && nums[i] <= nums[left] { - i += 1; // 从左向右找首个大于基准数的元素 + i += 1; // 从左向右找首个大于基准数的元素 } nums.swap(i, j); // 交换这两个元素 } - nums.swap(i, left); // 将基准数交换至两子数组的分界线 - i // 返回基准数的索引 + nums.swap(i, left); // 将基准数交换至两子数组的分界线 + i // 返回基准数的索引 } ``` @@ -942,11 +942,11 @@ comments: true ```rust title="quick_sort.rs" /* 选取三个候选元素的中位数 */ fn median_three(nums: &mut [i32], left: usize, mid: usize, right: usize) -> usize { - let (mut l, mut m, mut r) = (nums[left], nums[mid], nums[right]); - if ((l <= m && m <= r) || (r <= m && m <= l)) { + let (l, m, r) = (nums[left], nums[mid], nums[right]); + if (l <= m && m <= r) || (r <= m && m <= l) { return mid; // m 在 l 和 r 之间 } - if ((m <= l && l <= r) || (r <= l && l <= m)) { + if (m <= l && l <= r) || (r <= l && l <= m) { return left; // l 在 m 和 r 之间 } right @@ -962,15 +962,15 @@ comments: true let (mut i, mut j) = (left, right); while i < j { while i < j && nums[j] >= nums[left] { - j -= 1; // 从右向左找首个小于基准数的元素 + j -= 1; // 从右向左找首个小于基准数的元素 } while i < j && nums[i] <= nums[left] { - i += 1; // 从左向右找首个大于基准数的元素 + i += 1; // 从左向右找首个大于基准数的元素 } nums.swap(i, j); // 交换这两个元素 } - nums.swap(i, left); // 将基准数交换至两子数组的分界线 - i // 返回基准数的索引 + nums.swap(i, left); // 将基准数交换至两子数组的分界线 + i // 返回基准数的索引 } ``` @@ -1251,9 +1251,9 @@ comments: true // 哨兵划分操作 let pivot = Self::partition(nums, left as usize, right as usize) as i32; // 对两个子数组中较短的那个执行快速排序 - if pivot - left < right - pivot { - Self::quick_sort(left, pivot - 1, nums); // 递归排序左子数组 - left = pivot + 1; // 剩余未排序区间为 [pivot + 1, right] + if pivot - left < right - pivot { + Self::quick_sort(left, pivot - 1, nums); // 递归排序左子数组 + left = pivot + 1; // 剩余未排序区间为 [pivot + 1, right] } else { Self::quick_sort(pivot + 1, right, nums); // 递归排序右子数组 right = pivot - 1; // 剩余未排序区间为 [left, pivot - 1] diff --git a/docs/chapter_sorting/selection_sort.md b/docs/chapter_sorting/selection_sort.md index 343f0fc54..3e3702fb4 100644 --- a/docs/chapter_sorting/selection_sort.md +++ b/docs/chapter_sorting/selection_sort.md @@ -246,10 +246,10 @@ comments: true } 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; // 记录最小元素的索引 } diff --git a/docs/chapter_stack_and_queue/deque.md b/docs/chapter_stack_and_queue/deque.md index d146a7eb9..e6a586f85 100644 --- a/docs/chapter_stack_and_queue/deque.md +++ b/docs/chapter_stack_and_queue/deque.md @@ -1523,9 +1523,9 @@ comments: true /* 基于双向链表实现的双向队列 */ #[allow(dead_code)] pub struct LinkedListDeque { - front: Option>>>, // 头节点 front - rear: Option>>>, // 尾节点 rear - que_size: usize, // 双向队列的长度 + front: Option>>>, // 头节点 front + rear: Option>>>, // 尾节点 rear + que_size: usize, // 双向队列的长度 } impl LinkedListDeque { @@ -1533,7 +1533,7 @@ comments: true Self { front: None, rear: None, - que_size: 0, + que_size: 0, } } @@ -1565,7 +1565,7 @@ comments: true self.front = Some(node); // 更新头节点 } } - } + } // 队尾入队操作 else { match self.rear.take() { @@ -1598,8 +1598,8 @@ comments: true /* 出队操作 */ pub fn pop(&mut self, is_front: bool) -> Option { // 若队列为空,直接返回 None - if self.is_empty() { - return None + if self.is_empty() { + return None; }; // 队首出队操作 if is_front { @@ -1607,7 +1607,7 @@ comments: true match old_front.borrow_mut().next.take() { Some(new_front) => { new_front.borrow_mut().prev.take(); - self.front = Some(new_front); // 更新头节点 + self.front = Some(new_front); // 更新头节点 } None => { self.rear.take(); @@ -1616,15 +1616,14 @@ comments: true self.que_size -= 1; // 更新队列长度 Rc::try_unwrap(old_front).ok().unwrap().into_inner().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); // 更新尾节点 + self.rear = Some(new_rear); // 更新尾节点 } None => { self.front.take(); @@ -2990,9 +2989,9 @@ comments: true ```rust title="array_deque.rs" /* 基于环形数组实现的双向队列 */ struct ArrayDeque { - nums: Vec, // 用于存储双向队列元素的数组 - front: usize, // 队首指针,指向队首元素 - que_size: usize, // 双向队列长度 + nums: Vec, // 用于存储双向队列元素的数组 + front: usize, // 队首指针,指向队首元素 + que_size: usize, // 双向队列长度 } impl ArrayDeque { @@ -3032,7 +3031,7 @@ comments: true pub fn push_first(&mut self, num: i32) { if self.que_size == self.capacity() { println!("双向队列已满"); - return + return; } // 队首指针向左移动一位 // 通过取余操作实现 front 越过数组头部后回到尾部 @@ -3046,7 +3045,7 @@ comments: true pub fn push_last(&mut self, num: i32) { if self.que_size == self.capacity() { println!("双向队列已满"); - return + return; } // 计算队尾指针,指向队尾索引 + 1 let rear = self.index(self.front as i32 + self.que_size as i32); @@ -3073,18 +3072,22 @@ comments: true /* 访问队首元素 */ fn peek_first(&self) -> i32 { - if self.is_empty() { panic!("双向队列为空") }; + if self.is_empty() { + panic!("双向队列为空") + }; self.nums[self.front] } /* 访问队尾元素 */ fn peek_last(&self) -> i32 { - if self.is_empty() { panic!("双向队列为空") }; + if self.is_empty() { + panic!("双向队列为空") + }; // 计算尾元素索引 let last = self.index(self.front as i32 + self.que_size as i32 - 1); self.nums[last] } - + /* 返回数组用于打印 */ fn to_array(&self) -> Vec { // 仅转换有效长度范围内的列表元素 diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index cc89465f5..5dc437791 100755 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -959,9 +959,9 @@ comments: true /* 基于链表实现的队列 */ #[allow(dead_code)] pub struct LinkedListQueue { - front: Option>>>, // 头节点 front - rear: Option>>>, // 尾节点 rear - que_size: usize, // 队列的长度 + front: Option>>>, // 头节点 front + rear: Option>>>, // 尾节点 rear + que_size: usize, // 队列的长度 } impl LinkedListQueue { @@ -969,7 +969,7 @@ comments: true Self { front: None, rear: None, - que_size: 0, + que_size: 0, } } @@ -1887,10 +1887,10 @@ comments: true ```rust title="array_queue.rs" /* 基于环形数组实现的队列 */ struct ArrayQueue { - nums: Vec, // 用于存储队列元素的数组 - front: i32, // 队首指针,指向队首元素 - que_size: i32, // 队列长度 - que_capacity: i32, // 队列容量 + nums: Vec, // 用于存储队列元素的数组 + front: i32, // 队首指针,指向队首元素 + que_size: i32, // 队列长度 + que_capacity: i32, // 队列容量 } impl ArrayQueue { diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index 0fead0b22..fe10f9864 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -876,8 +876,8 @@ comments: true /* 基于链表实现的栈 */ #[allow(dead_code)] pub struct LinkedListStack { - stack_peek: Option>>>, // 将头节点作为栈顶 - stk_size: usize, // 栈的长度 + stack_peek: Option>>>, // 将头节点作为栈顶 + stk_size: usize, // 栈的长度 } impl LinkedListStack { @@ -1537,7 +1537,9 @@ comments: true impl ArrayStack { /* 初始化栈 */ fn new() -> ArrayStack { - ArrayStack:: { stack: Vec::::new() } + ArrayStack:: { + stack: Vec::::new(), + } } /* 获取栈的长度 */ @@ -1565,7 +1567,9 @@ comments: true /* 访问栈顶元素 */ fn peek(&self) -> Option<&T> { - if self.is_empty() { panic!("栈为空") }; + if self.is_empty() { + panic!("栈为空") + }; self.stack.last() } diff --git a/docs/chapter_tree/array_representation_of_tree.md b/docs/chapter_tree/array_representation_of_tree.md index 9e2fb4576..fb38f4cf9 100644 --- a/docs/chapter_tree/array_representation_of_tree.md +++ b/docs/chapter_tree/array_representation_of_tree.md @@ -18,7 +18,7 @@ comments: true

图 7-12   完美二叉树的数组表示

-**映射公式的角色相当于链表中的指针**。给定数组中的任意一个节点,我们都可以通过映射公式来访问它的左(右)子节点。 +**映射公式的角色相当于链表中的引用**。给定数组中的任意一个节点,我们都可以通过映射公式来访问它的左(右)子节点。 ## 7.3.2   表示任意二叉树 diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index 4b1e99d08..8bdbf0640 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -1819,6 +1819,7 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区 } } Self::update_height(Some(node.clone())); // 更新节点高度 + /* 2. 执行旋转操作,使该子树重新恢复平衡 */ node = Self::rotate(Some(node)).unwrap(); // 返回子树的根节点 @@ -2343,6 +2344,7 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区 node.borrow_mut().val = temp.borrow().val; } Self::update_height(Some(node.clone())); // 更新节点高度 + /* 2. 执行旋转操作,使该子树重新恢复平衡 */ node = Self::rotate(Some(node)).unwrap(); // 返回子树的根节点 diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index db5fa10c9..fa8aef29f 100755 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -1291,8 +1291,8 @@ comments: true /* 删除节点 */ pub fn remove(&mut self, num: i32) { // 若树为空,直接提前返回 - if self.root.is_none() { - return; + if self.root.is_none() { + return; } let mut cur = self.root.clone(); let mut pre = None; diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index 7d81bbdd1..0e924aa22 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -233,13 +233,14 @@ comments: true // 初始化一个列表,用于保存遍历序列 let mut vec = Vec::new(); - while let Some(node) = que.pop_front() { // 队列出队 - vec.push(node.borrow().val); // 保存节点值 + while let Some(node) = que.pop_front() { + // 队列出队 + vec.push(node.borrow().val); // 保存节点值 if let Some(left) = node.borrow().left.as_ref() { - que.push_back(Rc::clone(left)); // 左子节点入队 + que.push_back(Rc::clone(left)); // 左子节点入队 } if let Some(right) = node.borrow().right.as_ref() { - que.push_back(Rc::clone(right)); // 右子节点入队 + que.push_back(Rc::clone(right)); // 右子节点入队 }; } vec diff --git a/overrides/main.html b/overrides/main.html index 3a70e0096..1ea83977a 100644 --- a/overrides/main.html +++ b/overrides/main.html @@ -2,7 +2,7 @@ {% block announce %} {% if config.theme.language == 'zh' %} - {% set announcements = '纸质书已发布,详情请见纸质书介绍' %} + {% set announcements = '纸质书已发布,详情请见这里' %} {% elif config.theme.language == 'en' %} {% set announcements = 'The paper book (Chinese edition) published. Please visit this link for more details.' %} {% endif %}