From cdd8923e98691aacbbe9a04baacabd757f383bdf Mon Sep 17 00:00:00 2001 From: krahets Date: Tue, 16 Apr 2024 04:01:59 +0800 Subject: [PATCH] build --- .../knapsack_problem.md | 8 +- docs/chapter_dynamic_programming/summary.md | 2 +- docs/chapter_hashing/hash_algorithm.md | 64 +++++- docs/chapter_hashing/hash_collision.md | 207 +++++++++++++++++- docs/chapter_hashing/hash_map.md | 158 ++++++++++--- docs/chapter_stack_and_queue/deque.md | 2 +- docs/chapter_stack_and_queue/queue.md | 2 +- docs/chapter_stack_and_queue/stack.md | 4 +- en/docs/chapter_graph/index.md | 2 +- en/docs/chapter_hashing/hash_algorithm.md | 40 +++- en/docs/chapter_hashing/hash_collision.md | 207 +++++++++++++++++- en/docs/chapter_hashing/hash_map.md | 75 ++++++- en/docs/chapter_stack_and_queue/deque.md | 2 +- en/docs/chapter_stack_and_queue/queue.md | 2 +- en/docs/chapter_stack_and_queue/stack.md | 4 +- .../knapsack_problem.md | 8 +- .../chapter_dynamic_programming/summary.md | 2 +- .../docs/chapter_hashing/hash_algorithm.md | 64 +++++- .../docs/chapter_hashing/hash_collision.md | 207 +++++++++++++++++- zh-Hant/docs/chapter_hashing/hash_map.md | 158 ++++++++++--- zh-Hant/docs/chapter_stack_and_queue/deque.md | 2 +- zh-Hant/docs/chapter_stack_and_queue/queue.md | 2 +- zh-Hant/docs/chapter_stack_and_queue/stack.md | 4 +- 23 files changed, 1116 insertions(+), 110 deletions(-) diff --git a/docs/chapter_dynamic_programming/knapsack_problem.md b/docs/chapter_dynamic_programming/knapsack_problem.md index 98375ccee..1565cc706 100644 --- a/docs/chapter_dynamic_programming/knapsack_problem.md +++ b/docs/chapter_dynamic_programming/knapsack_problem.md @@ -24,15 +24,15 @@ comments: true **第一步:思考每轮的决策,定义状态,从而得到 $dp$ 表** -对于每个物品来说,不放入背包,背包容量不变;放入背包,背包容量减小。由此可得状态定义:当前物品编号 $i$ 和剩余背包容量 $c$ ,记为 $[i, c]$ 。 +对于每个物品来说,不放入背包,背包容量不变;放入背包,背包容量减小。由此可得状态定义:当前物品编号 $i$ 和背包容量 $c$ ,记为 $[i, c]$ 。 -状态 $[i, c]$ 对应的子问题为:**前 $i$ 个物品在剩余容量为 $c$ 的背包中的最大价值**,记为 $dp[i, c]$ 。 +状态 $[i, c]$ 对应的子问题为:**前 $i$ 个物品在容量为 $c$ 的背包中的最大价值**,记为 $dp[i, c]$ 。 待求解的是 $dp[n, cap]$ ,因此需要一个尺寸为 $(n+1) \times (cap+1)$ 的二维 $dp$ 表。 **第二步:找出最优子结构,进而推导出状态转移方程** -当我们做出物品 $i$ 的决策后,剩余的是前 $i-1$ 个物品的决策,可分为以下两种情况。 +当我们做出物品 $i$ 的决策后,剩余的是前 $i-1$ 个物品决策的子问题,可分为以下两种情况。 - **不放入物品 $i$** :背包容量不变,状态变化为 $[i-1, c]$ 。 - **放入物品 $i$** :背包容量减少 $wgt[i-1]$ ,价值增加 $val[i-1]$ ,状态变化为 $[i-1, c-wgt[i-1]]$ 。 @@ -47,7 +47,7 @@ $$ **第三步:确定边界条件和状态转移顺序** -当无物品或无剩余背包容量时最大价值为 $0$ ,即首列 $dp[i, 0]$ 和首行 $dp[0, c]$ 都等于 $0$ 。 +当无物品或背包容量为 $0$ 时最大价值为 $0$ ,即首列 $dp[i, 0]$ 和首行 $dp[0, c]$ 都等于 $0$ 。 当前状态 $[i, c]$ 从上方的状态 $[i-1, c]$ 和左上方的状态 $[i-1, c-wgt[i-1]]$ 转移而来,因此通过两层循环正序遍历整个 $dp$ 表即可。 diff --git a/docs/chapter_dynamic_programming/summary.md b/docs/chapter_dynamic_programming/summary.md index a2b7b434b..6c0453646 100644 --- a/docs/chapter_dynamic_programming/summary.md +++ b/docs/chapter_dynamic_programming/summary.md @@ -15,7 +15,7 @@ comments: true **背包问题** - 背包问题是最典型的动态规划问题之一,具有 0-1 背包、完全背包、多重背包等变种。 -- 0-1 背包的状态定义为前 $i$ 个物品在剩余容量为 $c$ 的背包中的最大价值。根据不放入背包和放入背包两种决策,可得到最优子结构,并构建出状态转移方程。在空间优化中,由于每个状态依赖正上方和左上方的状态,因此需要倒序遍历列表,避免左上方状态被覆盖。 +- 0-1 背包的状态定义为前 $i$ 个物品在容量为 $c$ 的背包中的最大价值。根据不放入背包和放入背包两种决策,可得到最优子结构,并构建出状态转移方程。在空间优化中,由于每个状态依赖正上方和左上方的状态,因此需要倒序遍历列表,避免左上方状态被覆盖。 - 完全背包问题的每种物品的选取数量无限制,因此选择放入物品的状态转移与 0-1 背包问题不同。由于状态依赖正上方和正左方的状态,因此在空间优化中应当正序遍历。 - 零钱兑换问题是完全背包问题的一个变种。它从求“最大”价值变为求“最小”硬币数量,因此状态转移方程中的 $\max()$ 应改为 $\min()$ 。从追求“不超过”背包容量到追求“恰好”凑出目标金额,因此使用 $amt + 1$ 来表示“无法凑出目标金额”的无效解。 - 零钱兑换问题 II 从求“最少硬币数量”改为求“硬币组合数量”,状态转移方程相应地从 $\min()$ 改为求和运算符。 diff --git a/docs/chapter_hashing/hash_algorithm.md b/docs/chapter_hashing/hash_algorithm.md index 5ef5103c0..5fd0da406 100644 --- a/docs/chapter_hashing/hash_algorithm.md +++ b/docs/chapter_hashing/hash_algorithm.md @@ -601,13 +601,45 @@ index = hash(key) % capacity === "Ruby" ```ruby title="simple_hash.rb" - [class]{}-[func]{add_hash} + ### 加法哈希 ### + def add_hash(key) + hash = 0 + modulus = 1_000_000_007 - [class]{}-[func]{mul_hash} + key.each_char { |c| hash += c.ord } - [class]{}-[func]{xor_hash} + hash % modulus + end - [class]{}-[func]{rot_hash} + ### 乘法哈希 ### + def mul_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash = 31 * hash + c.ord } + + hash % modulus + end + + ### 异或哈希 ### + def xor_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash ^= c.ord } + + hash % modulus + end + + ### 旋转哈希 ### + def rot_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash = (hash << 4) ^ (hash >> 28) ^ c.ord } + + hash % modulus + end ``` === "Zig" @@ -880,7 +912,7 @@ $$ ```rust title="built_in_hash.rs" use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; - + let num = 3; let mut num_hasher = DefaultHasher::new(); num.hash(&mut num_hasher); @@ -955,7 +987,29 @@ $$ === "Ruby" ```ruby title="built_in_hash.rb" + num = 3 + hash_num = num.hash + # 整数 3 的哈希值为 -4385856518450339636 + + bol = true + hash_bol = bol.hash + # 布尔量 true 的哈希值为 -1617938112149317027 + + dec = 3.14159 + hash_dec = dec.hash + # 小数 3.14159 的哈希值为 -1479186995943067893 + + str = "Hello 算法" + hash_str = str.hash + # 字符串“Hello 算法”的哈希值为 -4075943250025831763 + + tup = [12836, '小哈'] + hash_tup = tup.hash + # 元组 (12836, '小哈') 的哈希值为 1999544809202288822 + obj = ListNode.new(0) + hash_obj = obj.hash + # 节点对象 # 的哈希值为 4302940560806366381 ``` === "Zig" diff --git a/docs/chapter_hashing/hash_collision.md b/docs/chapter_hashing/hash_collision.md index a87f7d414..0ce44df38 100644 --- a/docs/chapter_hashing/hash_collision.md +++ b/docs/chapter_hashing/hash_collision.md @@ -1426,7 +1426,99 @@ comments: true === "Ruby" ```ruby title="hash_map_chaining.rb" - [class]{HashMapChaining}-[func]{} + ### 键式地址哈希表 ### + class HashMapChaining + ### 构造方法 ### + def initialize + @size = 0 # 键值对数量 + @capacity = 4 # 哈希表容量 + @load_thres = 2.0 / 3.0 # 触发扩容的负载因子阈值 + @extend_ratio = 2 # 扩容倍数 + @buckets = Array.new(@capacity) { [] } # 桶数组 + end + + ### 哈希函数 ### + def hash_func(key) + key % @capacity + end + + ### 负载因子 ### + def load_factor + @size / @capacity + end + + ### 查询操作 ### + def get(key) + index = hash_func(key) + bucket = @buckets[index] + # 遍历桶,若找到 key ,则返回对应 val + for pair in bucket + return pair.val if pair.key == key + end + # 若未找到 key , 则返回 nil + nil + end + + ### 添加操作 ### + def put(key, val) + # 当负载因子超过阈值时,执行扩容 + extend if load_factor > @load_thres + index = hash_func(key) + bucket = @buckets[index] + # 遍历桶,若遇到指定 key ,则更新对应 val 并返回 + for pair in bucket + if pair.key == key + pair.val = val + return + end + end + # 若无该 key ,则将键值对添加至尾部 + pair = Pair.new(key, val) + bucket << pair + @size += 1 + end + + ### 删除操作 ### + def remove(key) + index = hash_func(key) + bucket = @buckets[index] + # 遍历桶,从中删除键值对 + for pair in bucket + if pair.key == key + bucket.delete(pair) + @size -= 1 + break + end + end + end + + ### 扩容哈希表 ### + def extend + # 暫存原哈希表 + buckets = @buckets + # 初始化扩容后的新哈希表 + @capacity *= @extend_ratio + @buckets = Array.new(@capacity) { [] } + @size = 0 + # 将键值对从原哈希表搬运至新哈希表 + for bucket in buckets + for pair in bucket + put(pair.key, pair.val) + end + end + end + + ### 打印哈希表 ### + def print + for bucket in @buckets + res = [] + for pair in bucket + res << "#{pair.key} -> #{pair.val}" + end + pp res + end + end + end ``` === "Zig" @@ -3086,7 +3178,118 @@ comments: true === "Ruby" ```ruby title="hash_map_open_addressing.rb" - [class]{HashMapOpenAddressing}-[func]{} + ### 开放寻址哈希表 ### + class HashMapOpenAddressing + TOMBSTONE = Pair.new(-1, '-1') # 删除标记 + + ### 构造方法 ### + def initialize + @size = 0 # 键值对数量 + @capacity = 4 # 哈希表容量 + @load_thres = 2.0 / 3.0 # 触发扩容的负载因子阈值 + @extend_ratio = 2 # 扩容倍数 + @buckets = Array.new(@capacity) # 桶数组 + end + + ### 哈希函数 ### + def hash_func(key) + key % @capacity + end + + ### 负载因子 ### + def load_factor + @size / @capacity + end + + ### 搜索 key 对应的桶索引 ### + def find_bucket(key) + index = hash_func(key) + first_tombstone = -1 + # 线性探测,当遇到空桶时跳出 + while !@buckets[index].nil? + # 若遇到 key ,返回对应的桶索引 + if @buckets[index].key == key + # 若之前遇到了删除标记,则将键值对移动至该索引处 + if first_tombstone != -1 + @buckets[first_tombstone] = @buckets[index] + @buckets[index] = TOMBSTONE + return first_tombstone # 返回移动后的桶索引 + end + return index # 返回桶索引 + end + # 记录遇到的首个删除标记 + first_tombstone = index if first_tombstone == -1 && @buckets[index] == TOMBSTONE + # 计算桶索引,越过尾部则返回头部 + index = (index + 1) % @capacity + end + # 若 key 不存在,则返回添加点的索引 + first_tombstone == -1 ? index : first_tombstone + end + + ### 查询操作 ### + def get(key) + # 搜索 key 对应的桶索引 + index = find_bucket(key) + # 若找到键值对,则返回对应 val + return @buckets[index].val unless [nil, TOMBSTONE].include?(@buckets[index]) + # 若键值对不存在,则返回 nil + nil + end + + ### 添加操作 ### + def put(key, val) + # 当负载因子超过阈值时,执行扩容 + extend if load_factor > @load_thres + # 搜索 key 对应的桶索引 + index = find_bucket(key) + # 若找到键值对,则覆盖 val 开返回 + unless [nil, TOMBSTONE].include?(@buckets[index]) + @buckets[index].val = val + return + end + # 若键值对不存在,则添加该键值对 + @buckets[index] = Pair.new(key, val) + @size += 1 + end + + ### 删除操作 ### + def remove(key) + # 搜索 key 对应的桶索引 + index = find_bucket(key) + # 若找到键值对,则用删除标记覆盖它 + unless [nil, TOMBSTONE].include?(@buckets[index]) + @buckets[index] = TOMBSTONE + @size -= 1 + end + end + + ### 扩容哈希表 ### + def extend + # 暂存原哈希表 + buckets_tmp = @buckets + # 初始化扩容后的新哈希表 + @capacity *= @extend_ratio + @buckets = Array.new(@capacity) + @size = 0 + # 将键值对从原哈希表搬运至新哈希表 + for pair in buckets_tmp + put(pair.key, pair.val) unless [nil, TOMBSTONE].include?(pair) + end + end + + ### 打印哈希表 ### + def print + for pair in @buckets + if pair.nil? + puts "Nil" + elsif pair == TOMBSTONE + puts "TOMBSTONE" + else + puts "#{pair.key} -> #{pair.val}" + end + end + end + end ``` === "Zig" diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index ceec027da..345ef2fcf 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -41,7 +41,7 @@ comments: true ```python title="hash_map.py" # 初始化哈希表 hmap: dict = {} - + # 添加操作 # 在哈希表中添加键值对 (key, value) hmap[12836] = "小哈" @@ -49,11 +49,11 @@ comments: true hmap[16750] = "小算" hmap[13276] = "小法" hmap[10583] = "小鸭" - + # 查询操作 # 向哈希表中输入键 key ,得到值 value name: str = hmap[15937] - + # 删除操作 # 在哈希表中删除键值对 (key, value) hmap.pop(10583) @@ -64,7 +64,7 @@ comments: true ```cpp title="hash_map.cpp" /* 初始化哈希表 */ unordered_map map; - + /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map[12836] = "小哈"; @@ -72,11 +72,11 @@ comments: true map[16750] = "小算"; map[13276] = "小法"; map[10583] = "小鸭"; - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value string name = map[15937]; - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.erase(10583); @@ -87,19 +87,19 @@ comments: true ```java title="hash_map.java" /* 初始化哈希表 */ Map map = new HashMap<>(); - + /* 添加操作 */ // 在哈希表中添加键值对 (key, value) - map.put(12836, "小哈"); - map.put(15937, "小啰"); - map.put(16750, "小算"); + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); map.put(13276, "小法"); map.put(10583, "小鸭"); - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value String name = map.get(15937); - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.remove(10583); @@ -118,11 +118,11 @@ comments: true { 13276, "小法" }, { 10583, "小鸭" } }; - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value string name = map[15937]; - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.Remove(10583); @@ -133,7 +133,7 @@ comments: true ```go title="hash_map_test.go" /* 初始化哈希表 */ hmap := make(map[int]string) - + /* 添加操作 */ // 在哈希表中添加键值对 (key, value) hmap[12836] = "小哈" @@ -141,11 +141,11 @@ comments: true hmap[16750] = "小算" hmap[13276] = "小法" hmap[10583] = "小鸭" - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value name := hmap[15937] - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) delete(hmap, 10583) @@ -156,7 +156,7 @@ comments: true ```swift title="hash_map.swift" /* 初始化哈希表 */ var map: [Int: String] = [:] - + /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map[12836] = "小哈" @@ -164,11 +164,11 @@ comments: true map[16750] = "小算" map[13276] = "小法" map[10583] = "小鸭" - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value let name = map[15937]! - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.removeValue(forKey: 10583) @@ -186,11 +186,11 @@ comments: true map.set(16750, '小算'); map.set(13276, '小法'); map.set(10583, '小鸭'); - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value let name = map.get(15937); - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.delete(10583); @@ -210,12 +210,12 @@ comments: true map.set(10583, '小鸭'); console.info('\n添加完成后,哈希表为\nKey -> Value'); console.info(map); - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value let name = map.get(15937); console.info('\n输入学号 15937 ,查询到姓名 ' + name); - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.delete(10583); @@ -250,7 +250,7 @@ comments: true ```rust title="hash_map.rs" use std::collections::HashMap; - + /* 初始化哈希表 */ let mut map: HashMap = HashMap::new(); @@ -282,7 +282,7 @@ comments: true ```kotlin title="hash_map.kt" /* 初始化哈希表 */ val map = HashMap() - + /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map[12836] = "小哈" @@ -290,11 +290,11 @@ comments: true map[16750] = "小算" map[13276] = "小法" map[10583] = "小鸭" - + /* 查询操作 */ // 向哈希表中输入键 key ,得到值 value val name = map[15937] - + /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.remove(10583) @@ -303,7 +303,24 @@ comments: true === "Ruby" ```ruby title="hash_map.rb" + # 初始化哈希表 + hmap = {} + + # 添加操作 + # 在哈希表中添加键值对 (key, value) + hmap[12836] = "小哈" + hmap[15937] = "小啰" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鸭" + # 查询操作 + # 向哈希表中输入键 key ,得到值 value + name = hmap[15937] + + # 删除操作 + # 在哈希表中删除键值对 (key, value) + hmap.delete(10583) ``` === "Zig" @@ -487,7 +504,7 @@ comments: true // 单独遍历键 Key for key in map.keys() { - println!("{key}"); + println!("{key}"); } // 单独遍历值 Value @@ -523,7 +540,15 @@ comments: true === "Ruby" ```ruby title="hash_map.rb" + # 遍历哈希表 + # 遍历键值对 key->value + hmap.entries.each { |key, value| puts "#{key} -> #{value}" } + + # 单独遍历键 key + hmap.keys.each { |key| puts key } + # 单独遍历值 value + hmap.values.each { |val| puts val } ``` === "Zig" @@ -1666,9 +1691,78 @@ index = hash(key) % capacity === "Ruby" ```ruby title="array_hash_map.rb" - [class]{Pair}-[func]{} - - [class]{ArrayHashMap}-[func]{} + ### 键值对 ### + class Pair + attr_accessor :key, :val + + def initialize(key, val) + @key = key + @val = val + end + end + + ### 基于数组实现的哈希表 ### + class ArrayHashMap + ### 构造方法 ### + def initialize + # 初始化数组,包含 100 个桶 + @buckets = Array.new(100) + end + + ### 哈希函数 ### + def hash_func(key) + index = key % 100 + end + + ### 查询操作 ### + def get(key) + index = hash_func(key) + pair = @buckets[index] + + return if pair.nil? + pair.val + end + + ### 添加操作 ### + def put(key, val) + pair = Pair.new(key, val) + index = hash_func(key) + @buckets[index] = pair + end + + ### 删除操作 ### + def remove(key) + index = hash_func(key) + # 置为 nil ,代表删除 + @buckets[index] = nil + end + + ### 获取所有键值对 ### + def entry_set + result = [] + @buckets.each { |pair| result << pair unless pair.nil? } + result + end + + ### 获取所有键 ### + def key_set + result = [] + @buckets.each { |pair| result << pair.key unless pair.nil? } + result + end + + ### 获取所有值 ### + def value_set + result = [] + @buckets.each { |pair| result << pair.val unless pair.nil? } + result + end + + ### 打印哈希表 ### + def print + @buckets.each { |pair| puts "#{pair.key} -> #{pair.val}" unless pair.nil? } + end + end ``` === "Zig" diff --git a/docs/chapter_stack_and_queue/deque.md b/docs/chapter_stack_and_queue/deque.md index eba2a04e1..0f801075d 100644 --- a/docs/chapter_stack_and_queue/deque.md +++ b/docs/chapter_stack_and_queue/deque.md @@ -462,7 +462,7 @@ comments: true def is_empty(self) -> bool: """判断双向队列是否为空""" - return self.size() == 0 + return self._size == 0 def push(self, num: int, is_front: bool): """入队操作""" diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index b862b1f2f..f606c322d 100755 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -416,7 +416,7 @@ comments: true def is_empty(self) -> bool: """判断队列是否为空""" - return not self._front + return self._size == 0 def push(self, num: int): """入队""" diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index aa7c26a50..fe0d8e3af 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -412,7 +412,7 @@ comments: true def is_empty(self) -> bool: """判断栈是否为空""" - return not self._peek + return self._size == 0 def push(self, val: int): """入栈""" @@ -1284,7 +1284,7 @@ comments: true def is_empty(self) -> bool: """判断栈是否为空""" - return self._stack == [] + return self._size == 0 def push(self, item: int): """入栈""" diff --git a/en/docs/chapter_graph/index.md b/en/docs/chapter_graph/index.md index 09a098784..61571e906 100644 --- a/en/docs/chapter_graph/index.md +++ b/en/docs/chapter_graph/index.md @@ -11,7 +11,7 @@ icon: material/graphql In the journey of life, we are like individual nodes, connected by countless invisible edges. - Every encountering and parting leaves a unique mark on this vast network graph. + Each encounter and parting leaves a distinctive imprint on this vast network graph. ## Chapter contents diff --git a/en/docs/chapter_hashing/hash_algorithm.md b/en/docs/chapter_hashing/hash_algorithm.md index bb0f91df2..996fda00c 100644 --- a/en/docs/chapter_hashing/hash_algorithm.md +++ b/en/docs/chapter_hashing/hash_algorithm.md @@ -601,13 +601,45 @@ The design of hash algorithms is a complex issue that requires consideration of === "Ruby" ```ruby title="simple_hash.rb" - [class]{}-[func]{add_hash} + ### 加法哈希 ### + def add_hash(key) + hash = 0 + modulus = 1_000_000_007 - [class]{}-[func]{mul_hash} + key.each_char { |c| hash += c.ord } - [class]{}-[func]{xor_hash} + hash % modulus + end - [class]{}-[func]{rot_hash} + ### 乘法哈希 ### + def mul_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash = 31 * hash + c.ord } + + hash % modulus + end + + ### 异或哈希 ### + def xor_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash ^= c.ord } + + hash % modulus + end + + ### 旋转哈希 ### + def rot_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash = (hash << 4) ^ (hash >> 28) ^ c.ord } + + hash % modulus + end ``` === "Zig" diff --git a/en/docs/chapter_hashing/hash_collision.md b/en/docs/chapter_hashing/hash_collision.md index 49df160dc..f83e4a9f5 100644 --- a/en/docs/chapter_hashing/hash_collision.md +++ b/en/docs/chapter_hashing/hash_collision.md @@ -1426,7 +1426,99 @@ The code below provides a simple implementation of a separate chaining hash tabl === "Ruby" ```ruby title="hash_map_chaining.rb" - [class]{HashMapChaining}-[func]{} + ### 键式地址哈希表 ### + class HashMapChaining + ### 构造方法 ### + def initialize + @size = 0 # 键值对数量 + @capacity = 4 # 哈希表容量 + @load_thres = 2.0 / 3.0 # 触发扩容的负载因子阈值 + @extend_ratio = 2 # 扩容倍数 + @buckets = Array.new(@capacity) { [] } # 桶数组 + end + + ### 哈希函数 ### + def hash_func(key) + key % @capacity + end + + ### 负载因子 ### + def load_factor + @size / @capacity + end + + ### 查询操作 ### + def get(key) + index = hash_func(key) + bucket = @buckets[index] + # 遍历桶,若找到 key ,则返回对应 val + for pair in bucket + return pair.val if pair.key == key + end + # 若未找到 key , 则返回 nil + nil + end + + ### 添加操作 ### + def put(key, val) + # 当负载因子超过阈值时,执行扩容 + extend if load_factor > @load_thres + index = hash_func(key) + bucket = @buckets[index] + # 遍历桶,若遇到指定 key ,则更新对应 val 并返回 + for pair in bucket + if pair.key == key + pair.val = val + return + end + end + # 若无该 key ,则将键值对添加至尾部 + pair = Pair.new(key, val) + bucket << pair + @size += 1 + end + + ### 删除操作 ### + def remove(key) + index = hash_func(key) + bucket = @buckets[index] + # 遍历桶,从中删除键值对 + for pair in bucket + if pair.key == key + bucket.delete(pair) + @size -= 1 + break + end + end + end + + ### 扩容哈希表 ### + def extend + # 暫存原哈希表 + buckets = @buckets + # 初始化扩容后的新哈希表 + @capacity *= @extend_ratio + @buckets = Array.new(@capacity) { [] } + @size = 0 + # 将键值对从原哈希表搬运至新哈希表 + for bucket in buckets + for pair in bucket + put(pair.key, pair.val) + end + end + end + + ### 打印哈希表 ### + def print + for bucket in @buckets + res = [] + for pair in bucket + res << "#{pair.key} -> #{pair.val}" + end + pp res + end + end + end ``` === "Zig" @@ -3086,7 +3178,118 @@ The code below implements an open addressing (linear probing) hash table with la === "Ruby" ```ruby title="hash_map_open_addressing.rb" - [class]{HashMapOpenAddressing}-[func]{} + ### 开放寻址哈希表 ### + class HashMapOpenAddressing + TOMBSTONE = Pair.new(-1, '-1') # 删除标记 + + ### 构造方法 ### + def initialize + @size = 0 # 键值对数量 + @capacity = 4 # 哈希表容量 + @load_thres = 2.0 / 3.0 # 触发扩容的负载因子阈值 + @extend_ratio = 2 # 扩容倍数 + @buckets = Array.new(@capacity) # 桶数组 + end + + ### 哈希函数 ### + def hash_func(key) + key % @capacity + end + + ### 负载因子 ### + def load_factor + @size / @capacity + end + + ### 搜索 key 对应的桶索引 ### + def find_bucket(key) + index = hash_func(key) + first_tombstone = -1 + # 线性探测,当遇到空桶时跳出 + while !@buckets[index].nil? + # 若遇到 key ,返回对应的桶索引 + if @buckets[index].key == key + # 若之前遇到了删除标记,则将键值对移动至该索引处 + if first_tombstone != -1 + @buckets[first_tombstone] = @buckets[index] + @buckets[index] = TOMBSTONE + return first_tombstone # 返回移动后的桶索引 + end + return index # 返回桶索引 + end + # 记录遇到的首个删除标记 + first_tombstone = index if first_tombstone == -1 && @buckets[index] == TOMBSTONE + # 计算桶索引,越过尾部则返回头部 + index = (index + 1) % @capacity + end + # 若 key 不存在,则返回添加点的索引 + first_tombstone == -1 ? index : first_tombstone + end + + ### 查询操作 ### + def get(key) + # 搜索 key 对应的桶索引 + index = find_bucket(key) + # 若找到键值对,则返回对应 val + return @buckets[index].val unless [nil, TOMBSTONE].include?(@buckets[index]) + # 若键值对不存在,则返回 nil + nil + end + + ### 添加操作 ### + def put(key, val) + # 当负载因子超过阈值时,执行扩容 + extend if load_factor > @load_thres + # 搜索 key 对应的桶索引 + index = find_bucket(key) + # 若找到键值对,则覆盖 val 开返回 + unless [nil, TOMBSTONE].include?(@buckets[index]) + @buckets[index].val = val + return + end + # 若键值对不存在,则添加该键值对 + @buckets[index] = Pair.new(key, val) + @size += 1 + end + + ### 删除操作 ### + def remove(key) + # 搜索 key 对应的桶索引 + index = find_bucket(key) + # 若找到键值对,则用删除标记覆盖它 + unless [nil, TOMBSTONE].include?(@buckets[index]) + @buckets[index] = TOMBSTONE + @size -= 1 + end + end + + ### 扩容哈希表 ### + def extend + # 暂存原哈希表 + buckets_tmp = @buckets + # 初始化扩容后的新哈希表 + @capacity *= @extend_ratio + @buckets = Array.new(@capacity) + @size = 0 + # 将键值对从原哈希表搬运至新哈希表 + for pair in buckets_tmp + put(pair.key, pair.val) unless [nil, TOMBSTONE].include?(pair) + end + end + + ### 打印哈希表 ### + def print + for pair in @buckets + if pair.nil? + puts "Nil" + elsif pair == TOMBSTONE + puts "TOMBSTONE" + else + puts "#{pair.key} -> #{pair.val}" + end + end + end + end ``` === "Zig" diff --git a/en/docs/chapter_hashing/hash_map.md b/en/docs/chapter_hashing/hash_map.md index f48c50fc9..dec89ad99 100755 --- a/en/docs/chapter_hashing/hash_map.md +++ b/en/docs/chapter_hashing/hash_map.md @@ -1625,9 +1625,78 @@ The following code implements a simple hash table. Here, we encapsulate `key` an === "Ruby" ```ruby title="array_hash_map.rb" - [class]{Pair}-[func]{} - - [class]{ArrayHashMap}-[func]{} + ### 键值对 ### + class Pair + attr_accessor :key, :val + + def initialize(key, val) + @key = key + @val = val + end + end + + ### 基于数组实现的哈希表 ### + class ArrayHashMap + ### 构造方法 ### + def initialize + # 初始化数组,包含 100 个桶 + @buckets = Array.new(100) + end + + ### 哈希函数 ### + def hash_func(key) + index = key % 100 + end + + ### 查询操作 ### + def get(key) + index = hash_func(key) + pair = @buckets[index] + + return if pair.nil? + pair.val + end + + ### 添加操作 ### + def put(key, val) + pair = Pair.new(key, val) + index = hash_func(key) + @buckets[index] = pair + end + + ### 删除操作 ### + def remove(key) + index = hash_func(key) + # 置为 nil ,代表删除 + @buckets[index] = nil + end + + ### 获取所有键值对 ### + def entry_set + result = [] + @buckets.each { |pair| result << pair unless pair.nil? } + result + end + + ### 获取所有键 ### + def key_set + result = [] + @buckets.each { |pair| result << pair.key unless pair.nil? } + result + end + + ### 获取所有值 ### + def value_set + result = [] + @buckets.each { |pair| result << pair.val unless pair.nil? } + result + end + + ### 打印哈希表 ### + def print + @buckets.each { |pair| puts "#{pair.key} -> #{pair.val}" unless pair.nil? } + end + end ``` === "Zig" diff --git a/en/docs/chapter_stack_and_queue/deque.md b/en/docs/chapter_stack_and_queue/deque.md index 48621087e..2bd1813b7 100644 --- a/en/docs/chapter_stack_and_queue/deque.md +++ b/en/docs/chapter_stack_and_queue/deque.md @@ -408,7 +408,7 @@ The implementation code is as follows: def is_empty(self) -> bool: """判断双向队列是否为空""" - return self.size() == 0 + return self._size == 0 def push(self, num: int, is_front: bool): """入队操作""" diff --git a/en/docs/chapter_stack_and_queue/queue.md b/en/docs/chapter_stack_and_queue/queue.md index 719952379..635cbb3ee 100755 --- a/en/docs/chapter_stack_and_queue/queue.md +++ b/en/docs/chapter_stack_and_queue/queue.md @@ -368,7 +368,7 @@ Below is the code for implementing a queue using a linked list: def is_empty(self) -> bool: """判断队列是否为空""" - return not self._front + return self._size == 0 def push(self, num: int): """入队""" diff --git a/en/docs/chapter_stack_and_queue/stack.md b/en/docs/chapter_stack_and_queue/stack.md index 22ebe4a13..32165bf45 100755 --- a/en/docs/chapter_stack_and_queue/stack.md +++ b/en/docs/chapter_stack_and_queue/stack.md @@ -365,7 +365,7 @@ Below is an example code for implementing a stack based on a linked list: def is_empty(self) -> bool: """判断栈是否为空""" - return not self._peek + return self._size == 0 def push(self, val: int): """入栈""" @@ -1237,7 +1237,7 @@ Since the elements to be pushed onto the stack may continuously increase, we can def is_empty(self) -> bool: """判断栈是否为空""" - return self._stack == [] + return self._size == 0 def push(self, item: int): """入栈""" diff --git a/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md b/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md index f19287422..f753de146 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md +++ b/zh-Hant/docs/chapter_dynamic_programming/knapsack_problem.md @@ -24,15 +24,15 @@ comments: true **第一步:思考每輪的決策,定義狀態,從而得到 $dp$ 表** -對於每個物品來說,不放入背包,背包容量不變;放入背包,背包容量減小。由此可得狀態定義:當前物品編號 $i$ 和剩餘背包容量 $c$ ,記為 $[i, c]$ 。 +對於每個物品來說,不放入背包,背包容量不變;放入背包,背包容量減小。由此可得狀態定義:當前物品編號 $i$ 和背包容量 $c$ ,記為 $[i, c]$ 。 -狀態 $[i, c]$ 對應的子問題為:**前 $i$ 個物品在剩餘容量為 $c$ 的背包中的最大價值**,記為 $dp[i, c]$ 。 +狀態 $[i, c]$ 對應的子問題為:**前 $i$ 個物品在容量為 $c$ 的背包中的最大價值**,記為 $dp[i, c]$ 。 待求解的是 $dp[n, cap]$ ,因此需要一個尺寸為 $(n+1) \times (cap+1)$ 的二維 $dp$ 表。 **第二步:找出最優子結構,進而推導出狀態轉移方程** -當我們做出物品 $i$ 的決策後,剩餘的是前 $i-1$ 個物品的決策,可分為以下兩種情況。 +當我們做出物品 $i$ 的決策後,剩餘的是前 $i-1$ 個物品決策的子問題,可分為以下兩種情況。 - **不放入物品 $i$** :背包容量不變,狀態變化為 $[i-1, c]$ 。 - **放入物品 $i$** :背包容量減少 $wgt[i-1]$ ,價值增加 $val[i-1]$ ,狀態變化為 $[i-1, c-wgt[i-1]]$ 。 @@ -47,7 +47,7 @@ $$ **第三步:確定邊界條件和狀態轉移順序** -當無物品或無剩餘背包容量時最大價值為 $0$ ,即首列 $dp[i, 0]$ 和首行 $dp[0, c]$ 都等於 $0$ 。 +當無物品或背包容量為 $0$ 時最大價值為 $0$ ,即首列 $dp[i, 0]$ 和首行 $dp[0, c]$ 都等於 $0$ 。 當前狀態 $[i, c]$ 從上方的狀態 $[i-1, c]$ 和左上方的狀態 $[i-1, c-wgt[i-1]]$ 轉移而來,因此透過兩層迴圈正序走訪整個 $dp$ 表即可。 diff --git a/zh-Hant/docs/chapter_dynamic_programming/summary.md b/zh-Hant/docs/chapter_dynamic_programming/summary.md index 4c2e020c1..f158d187a 100644 --- a/zh-Hant/docs/chapter_dynamic_programming/summary.md +++ b/zh-Hant/docs/chapter_dynamic_programming/summary.md @@ -15,7 +15,7 @@ comments: true **背包問題** - 背包問題是最典型的動態規劃問題之一,具有 0-1 背包、完全背包、多重背包等變種。 -- 0-1 背包的狀態定義為前 $i$ 個物品在剩餘容量為 $c$ 的背包中的最大價值。根據不放入背包和放入背包兩種決策,可得到最優子結構,並構建出狀態轉移方程。在空間最佳化中,由於每個狀態依賴正上方和左上方的狀態,因此需要倒序走訪串列,避免左上方狀態被覆蓋。 +- 0-1 背包的狀態定義為前 $i$ 個物品在容量為 $c$ 的背包中的最大價值。根據不放入背包和放入背包兩種決策,可得到最優子結構,並構建出狀態轉移方程。在空間最佳化中,由於每個狀態依賴正上方和左上方的狀態,因此需要倒序走訪串列,避免左上方狀態被覆蓋。 - 完全背包問題的每種物品的選取數量無限制,因此選擇放入物品的狀態轉移與 0-1 背包問題不同。由於狀態依賴正上方和正左方的狀態,因此在空間最佳化中應當正序走訪。 - 零錢兌換問題是完全背包問題的一個變種。它從求“最大”價值變為求“最小”硬幣數量,因此狀態轉移方程中的 $\max()$ 應改為 $\min()$ 。從追求“不超過”背包容量到追求“恰好”湊出目標金額,因此使用 $amt + 1$ 來表示“無法湊出目標金額”的無效解。 - 零錢兌換問題 II 從求“最少硬幣數量”改為求“硬幣組合數量”,狀態轉移方程相應地從 $\min()$ 改為求和運算子。 diff --git a/zh-Hant/docs/chapter_hashing/hash_algorithm.md b/zh-Hant/docs/chapter_hashing/hash_algorithm.md index 5b24c8d9b..515e4862c 100644 --- a/zh-Hant/docs/chapter_hashing/hash_algorithm.md +++ b/zh-Hant/docs/chapter_hashing/hash_algorithm.md @@ -601,13 +601,45 @@ index = hash(key) % capacity === "Ruby" ```ruby title="simple_hash.rb" - [class]{}-[func]{add_hash} + ### 加法雜湊 ### + def add_hash(key) + hash = 0 + modulus = 1_000_000_007 - [class]{}-[func]{mul_hash} + key.each_char { |c| hash += c.ord } - [class]{}-[func]{xor_hash} + hash % modulus + end - [class]{}-[func]{rot_hash} + ### 乘法雜湊 ### + def mul_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash = 31 * hash + c.ord } + + hash % modulus + end + + ### 互斥或雜湊 ### + def xor_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash ^= c.ord } + + hash % modulus + end + + ### 旋轉雜湊 ### + def rot_hash(key) + hash = 0 + modulus = 1_000_000_007 + + key.each_char { |c| hash = (hash << 4) ^ (hash >> 28) ^ c.ord } + + hash % modulus + end ``` === "Zig" @@ -880,7 +912,7 @@ $$ ```rust title="built_in_hash.rs" use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; - + let num = 3; let mut num_hasher = DefaultHasher::new(); num.hash(&mut num_hasher); @@ -955,7 +987,29 @@ $$ === "Ruby" ```ruby title="built_in_hash.rb" + num = 3 + hash_num = num.hash + # 整數 3 的雜湊值為 -4385856518450339636 + + bol = true + hash_bol = bol.hash + # 布林量 true 的雜湊值為 -1617938112149317027 + + dec = 3.14159 + hash_dec = dec.hash + # 小數 3.14159 的雜湊值為 -1479186995943067893 + + str = "Hello 演算法" + hash_str = str.hash + # 字串“Hello 演算法”的雜湊值為 -4075943250025831763 + + tup = [12836, '小哈'] + hash_tup = tup.hash + # 元組 (12836, '小哈') 的雜湊值為 1999544809202288822 + obj = ListNode.new(0) + hash_obj = obj.hash + # 節點物件 # 的雜湊值為 4302940560806366381 ``` === "Zig" diff --git a/zh-Hant/docs/chapter_hashing/hash_collision.md b/zh-Hant/docs/chapter_hashing/hash_collision.md index 2d2caf172..4e37beeda 100644 --- a/zh-Hant/docs/chapter_hashing/hash_collision.md +++ b/zh-Hant/docs/chapter_hashing/hash_collision.md @@ -1426,7 +1426,99 @@ comments: true === "Ruby" ```ruby title="hash_map_chaining.rb" - [class]{HashMapChaining}-[func]{} + ### 鍵式位址雜湊表 ### + class HashMapChaining + ### 建構子 ### + def initialize + @size = 0 # 鍵值對數量 + @capacity = 4 # 雜湊表容量 + @load_thres = 2.0 / 3.0 # 觸發擴容的負載因子閾值 + @extend_ratio = 2 # 擴容倍數 + @buckets = Array.new(@capacity) { [] } # 桶陣列 + end + + ### 雜湊函式 ### + def hash_func(key) + key % @capacity + end + + ### 負載因子 ### + def load_factor + @size / @capacity + end + + ### 查詢操作 ### + def get(key) + index = hash_func(key) + bucket = @buckets[index] + # 走訪桶,若找到 key ,則返回對應 val + for pair in bucket + return pair.val if pair.key == key + end + # 若未找到 key , 則返回 nil + nil + end + + ### 新增操作 ### + def put(key, val) + # 當負載因子超過閾值時,執行擴容 + extend if load_factor > @load_thres + index = hash_func(key) + bucket = @buckets[index] + # 走訪桶,若遇到指定 key ,則更新對應 val 並返回 + for pair in bucket + if pair.key == key + pair.val = val + return + end + end + # 若無該 key ,則將鍵值對新增至尾部 + pair = Pair.new(key, val) + bucket << pair + @size += 1 + end + + ### 刪除操作 ### + def remove(key) + index = hash_func(key) + bucket = @buckets[index] + # 走訪桶,從中刪除鍵值對 + for pair in bucket + if pair.key == key + bucket.delete(pair) + @size -= 1 + break + end + end + end + + ### 擴容雜湊表 ### + def extend + # 暫存原雜湊表 + buckets = @buckets + # 初始化擴容後的新雜湊表 + @capacity *= @extend_ratio + @buckets = Array.new(@capacity) { [] } + @size = 0 + # 將鍵值對從原雜湊表搬運至新雜湊表 + for bucket in buckets + for pair in bucket + put(pair.key, pair.val) + end + end + end + + ### 列印雜湊表 ### + def print + for bucket in @buckets + res = [] + for pair in bucket + res << "#{pair.key} -> #{pair.val}" + end + pp res + end + end + end ``` === "Zig" @@ -3086,7 +3178,118 @@ comments: true === "Ruby" ```ruby title="hash_map_open_addressing.rb" - [class]{HashMapOpenAddressing}-[func]{} + ### 開放定址雜湊表 ### + class HashMapOpenAddressing + TOMBSTONE = Pair.new(-1, '-1') # 刪除標記 + + ### 建構子 ### + def initialize + @size = 0 # 鍵值對數量 + @capacity = 4 # 雜湊表容量 + @load_thres = 2.0 / 3.0 # 觸發擴容的負載因子閾值 + @extend_ratio = 2 # 擴容倍數 + @buckets = Array.new(@capacity) # 桶陣列 + end + + ### 雜湊函式 ### + def hash_func(key) + key % @capacity + end + + ### 負載因子 ### + def load_factor + @size / @capacity + end + + ### 搜尋 key 對應的桶索引 ### + def find_bucket(key) + index = hash_func(key) + first_tombstone = -1 + # 線性探查,當遇到空桶時跳出 + while !@buckets[index].nil? + # 若遇到 key ,返回對應的桶索引 + if @buckets[index].key == key + # 若之前遇到了刪除標記,則將鍵值對移動至該索引處 + if first_tombstone != -1 + @buckets[first_tombstone] = @buckets[index] + @buckets[index] = TOMBSTONE + return first_tombstone # 返回移動後的桶索引 + end + return index # 返回桶索引 + end + # 記錄遇到的首個刪除標記 + first_tombstone = index if first_tombstone == -1 && @buckets[index] == TOMBSTONE + # 計算桶索引,越過尾部則返回頭部 + index = (index + 1) % @capacity + end + # 若 key 不存在,則返回新增點的索引 + first_tombstone == -1 ? index : first_tombstone + end + + ### 查詢操作 ### + def get(key) + # 搜尋 key 對應的桶索引 + index = find_bucket(key) + # 若找到鍵值對,則返回對應 val + return @buckets[index].val unless [nil, TOMBSTONE].include?(@buckets[index]) + # 若鍵值對不存在,則返回 nil + nil + end + + ### 新增操作 ### + def put(key, val) + # 當負載因子超過閾值時,執行擴容 + extend if load_factor > @load_thres + # 搜尋 key 對應的桶索引 + index = find_bucket(key) + # 若找到鍵值對,則覆蓋 val 開返回 + unless [nil, TOMBSTONE].include?(@buckets[index]) + @buckets[index].val = val + return + end + # 若鍵值對不存在,則新增該鍵值對 + @buckets[index] = Pair.new(key, val) + @size += 1 + end + + ### 刪除操作 ### + def remove(key) + # 搜尋 key 對應的桶索引 + index = find_bucket(key) + # 若找到鍵值對,則用刪除標記覆蓋它 + unless [nil, TOMBSTONE].include?(@buckets[index]) + @buckets[index] = TOMBSTONE + @size -= 1 + end + end + + ### 擴容雜湊表 ### + def extend + # 暫存原雜湊表 + buckets_tmp = @buckets + # 初始化擴容後的新雜湊表 + @capacity *= @extend_ratio + @buckets = Array.new(@capacity) + @size = 0 + # 將鍵值對從原雜湊表搬運至新雜湊表 + for pair in buckets_tmp + put(pair.key, pair.val) unless [nil, TOMBSTONE].include?(pair) + end + end + + ### 列印雜湊表 ### + def print + for pair in @buckets + if pair.nil? + puts "Nil" + elsif pair == TOMBSTONE + puts "TOMBSTONE" + else + puts "#{pair.key} -> #{pair.val}" + end + end + end + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_hashing/hash_map.md b/zh-Hant/docs/chapter_hashing/hash_map.md index b1f4a1b18..6157c42a9 100755 --- a/zh-Hant/docs/chapter_hashing/hash_map.md +++ b/zh-Hant/docs/chapter_hashing/hash_map.md @@ -41,7 +41,7 @@ comments: true ```python title="hash_map.py" # 初始化雜湊表 hmap: dict = {} - + # 新增操作 # 在雜湊表中新增鍵值對 (key, value) hmap[12836] = "小哈" @@ -49,11 +49,11 @@ comments: true hmap[16750] = "小算" hmap[13276] = "小法" hmap[10583] = "小鴨" - + # 查詢操作 # 向雜湊表中輸入鍵 key ,得到值 value name: str = hmap[15937] - + # 刪除操作 # 在雜湊表中刪除鍵值對 (key, value) hmap.pop(10583) @@ -64,7 +64,7 @@ comments: true ```cpp title="hash_map.cpp" /* 初始化雜湊表 */ unordered_map map; - + /* 新增操作 */ // 在雜湊表中新增鍵值對 (key, value) map[12836] = "小哈"; @@ -72,11 +72,11 @@ comments: true map[16750] = "小算"; map[13276] = "小法"; map[10583] = "小鴨"; - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value string name = map[15937]; - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) map.erase(10583); @@ -87,19 +87,19 @@ comments: true ```java title="hash_map.java" /* 初始化雜湊表 */ Map map = new HashMap<>(); - + /* 新增操作 */ // 在雜湊表中新增鍵值對 (key, value) - map.put(12836, "小哈"); - map.put(15937, "小囉"); - map.put(16750, "小算"); + map.put(12836, "小哈"); + map.put(15937, "小囉"); + map.put(16750, "小算"); map.put(13276, "小法"); map.put(10583, "小鴨"); - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value String name = map.get(15937); - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) map.remove(10583); @@ -118,11 +118,11 @@ comments: true { 13276, "小法" }, { 10583, "小鴨" } }; - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value string name = map[15937]; - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) map.Remove(10583); @@ -133,7 +133,7 @@ comments: true ```go title="hash_map_test.go" /* 初始化雜湊表 */ hmap := make(map[int]string) - + /* 新增操作 */ // 在雜湊表中新增鍵值對 (key, value) hmap[12836] = "小哈" @@ -141,11 +141,11 @@ comments: true hmap[16750] = "小算" hmap[13276] = "小法" hmap[10583] = "小鴨" - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value name := hmap[15937] - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) delete(hmap, 10583) @@ -156,7 +156,7 @@ comments: true ```swift title="hash_map.swift" /* 初始化雜湊表 */ var map: [Int: String] = [:] - + /* 新增操作 */ // 在雜湊表中新增鍵值對 (key, value) map[12836] = "小哈" @@ -164,11 +164,11 @@ comments: true map[16750] = "小算" map[13276] = "小法" map[10583] = "小鴨" - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value let name = map[15937]! - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) map.removeValue(forKey: 10583) @@ -186,11 +186,11 @@ comments: true map.set(16750, '小算'); map.set(13276, '小法'); map.set(10583, '小鴨'); - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value let name = map.get(15937); - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) map.delete(10583); @@ -210,12 +210,12 @@ comments: true map.set(10583, '小鴨'); console.info('\n新增完成後,雜湊表為\nKey -> Value'); console.info(map); - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value let name = map.get(15937); console.info('\n輸入學號 15937 ,查詢到姓名 ' + name); - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) map.delete(10583); @@ -250,7 +250,7 @@ comments: true ```rust title="hash_map.rs" use std::collections::HashMap; - + /* 初始化雜湊表 */ let mut map: HashMap = HashMap::new(); @@ -282,7 +282,7 @@ comments: true ```kotlin title="hash_map.kt" /* 初始化雜湊表 */ val map = HashMap() - + /* 新增操作 */ // 在雜湊表中新增鍵值對 (key, value) map[12836] = "小哈" @@ -290,11 +290,11 @@ comments: true map[16750] = "小算" map[13276] = "小法" map[10583] = "小鴨" - + /* 查詢操作 */ // 向雜湊表中輸入鍵 key ,得到值 value val name = map[15937] - + /* 刪除操作 */ // 在雜湊表中刪除鍵值對 (key, value) map.remove(10583) @@ -303,7 +303,24 @@ comments: true === "Ruby" ```ruby title="hash_map.rb" + # 初始化雜湊表 + hmap = {} + + # 新增操作 + # 在雜湊表中新增鍵值對 (key, value) + hmap[12836] = "小哈" + hmap[15937] = "小囉" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鴨" + # 查詢操作 + # 向雜湊表中輸入鍵 key ,得到值 value + name = hmap[15937] + + # 刪除操作 + # 在雜湊表中刪除鍵值對 (key, value) + hmap.delete(10583) ``` === "Zig" @@ -487,7 +504,7 @@ comments: true // 單獨走訪鍵 Key for key in map.keys() { - println!("{key}"); + println!("{key}"); } // 單獨走訪值 Value @@ -523,7 +540,15 @@ comments: true === "Ruby" ```ruby title="hash_map.rb" + # 走訪雜湊表 + # 走訪鍵值對 key->value + hmap.entries.each { |key, value| puts "#{key} -> #{value}" } + + # 單獨走訪鍵 key + hmap.keys.each { |key| puts key } + # 單獨走訪值 value + hmap.values.each { |val| puts val } ``` === "Zig" @@ -1666,9 +1691,78 @@ index = hash(key) % capacity === "Ruby" ```ruby title="array_hash_map.rb" - [class]{Pair}-[func]{} - - [class]{ArrayHashMap}-[func]{} + ### 鍵值對 ### + class Pair + attr_accessor :key, :val + + def initialize(key, val) + @key = key + @val = val + end + end + + ### 基於陣列實現的雜湊表 ### + class ArrayHashMap + ### 建構子 ### + def initialize + # 初始化陣列,包含 100 個桶 + @buckets = Array.new(100) + end + + ### 雜湊函式 ### + def hash_func(key) + index = key % 100 + end + + ### 查詢操作 ### + def get(key) + index = hash_func(key) + pair = @buckets[index] + + return if pair.nil? + pair.val + end + + ### 新增操作 ### + def put(key, val) + pair = Pair.new(key, val) + index = hash_func(key) + @buckets[index] = pair + end + + ### 刪除操作 ### + def remove(key) + index = hash_func(key) + # 置為 nil ,代表刪除 + @buckets[index] = nil + end + + ### 獲取所有鍵值對 ### + def entry_set + result = [] + @buckets.each { |pair| result << pair unless pair.nil? } + result + end + + ### 獲取所有鍵 ### + def key_set + result = [] + @buckets.each { |pair| result << pair.key unless pair.nil? } + result + end + + ### 獲取所有值 ### + def value_set + result = [] + @buckets.each { |pair| result << pair.val unless pair.nil? } + result + end + + ### 列印雜湊表 ### + def print + @buckets.each { |pair| puts "#{pair.key} -> #{pair.val}" unless pair.nil? } + end + end ``` === "Zig" diff --git a/zh-Hant/docs/chapter_stack_and_queue/deque.md b/zh-Hant/docs/chapter_stack_and_queue/deque.md index f246ef132..828c120d0 100644 --- a/zh-Hant/docs/chapter_stack_and_queue/deque.md +++ b/zh-Hant/docs/chapter_stack_and_queue/deque.md @@ -462,7 +462,7 @@ comments: true def is_empty(self) -> bool: """判斷雙向佇列是否為空""" - return self.size() == 0 + return self._size == 0 def push(self, num: int, is_front: bool): """入列操作""" diff --git a/zh-Hant/docs/chapter_stack_and_queue/queue.md b/zh-Hant/docs/chapter_stack_and_queue/queue.md index 0d94f81a2..62bab9ff5 100755 --- a/zh-Hant/docs/chapter_stack_and_queue/queue.md +++ b/zh-Hant/docs/chapter_stack_and_queue/queue.md @@ -416,7 +416,7 @@ comments: true def is_empty(self) -> bool: """判斷佇列是否為空""" - return not self._front + return self._size == 0 def push(self, num: int): """入列""" diff --git a/zh-Hant/docs/chapter_stack_and_queue/stack.md b/zh-Hant/docs/chapter_stack_and_queue/stack.md index 475e05082..13b469ed9 100755 --- a/zh-Hant/docs/chapter_stack_and_queue/stack.md +++ b/zh-Hant/docs/chapter_stack_and_queue/stack.md @@ -412,7 +412,7 @@ comments: true def is_empty(self) -> bool: """判斷堆疊是否為空""" - return not self._peek + return self._size == 0 def push(self, val: int): """入堆疊""" @@ -1284,7 +1284,7 @@ comments: true def is_empty(self) -> bool: """判斷堆疊是否為空""" - return self._stack == [] + return self._size == 0 def push(self, item: int): """入堆疊"""