From 13bb76c283542693c418053db20ee65cd0050a7b Mon Sep 17 00:00:00 2001 From: WangSL <48207171+WSL0809@users.noreply.github.com> Date: Wed, 26 Jul 2023 15:42:47 +0800 Subject: [PATCH] feat: add rust code for build_in_hash and hash_collision (#629) * Create hash_map_chaining.rs * Create hash_map_open_addressing.rs * Create build_in_hash.rs * Update Cargo.toml --- codes/rust/Cargo.toml | 17 +- codes/rust/chapter_hashing/build_in_hash.rs | 50 +++++ .../rust/chapter_hashing/hash_map_chaining.rs | 164 ++++++++++++++++ .../hash_map_open_addressing.rs | 181 ++++++++++++++++++ 4 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 codes/rust/chapter_hashing/build_in_hash.rs create mode 100644 codes/rust/chapter_hashing/hash_map_chaining.rs create mode 100644 codes/rust/chapter_hashing/hash_map_open_addressing.rs diff --git a/codes/rust/Cargo.toml b/codes/rust/Cargo.toml index 12065cf8..1b311391 100644 --- a/codes/rust/Cargo.toml +++ b/codes/rust/Cargo.toml @@ -89,6 +89,21 @@ path = "chapter_hashing/hash_map.rs" name = "array_hash_map" path = "chapter_hashing/array_hash_map.rs" +# Run Command: cargo run --bin build_in_hash +[[bin]] +name = "build_in_hash" +path = "chapter_hashing/build_in_hash.rs" + +# Run Command: cargo run --bin hash_map_chaining +[[bin]] +name = "hash_map_chaining" +path = "chapter_hashing/hash_map_chaining.rs" + +# Run Command: cargo run --bin hash_map_open_addressing +[[bin]] +name = "hash_map_open_addressing" +path = "chapter_hashing/hash_map_open_addressing.rs" + # Run Command: cargo run --bin binary_search [[bin]] name = "binary_search" @@ -375,4 +390,4 @@ name = "max_product_cutting" path = "chapter_greedy/max_product_cutting.rs" [dependencies] -rand = "0.8.5" \ No newline at end of file +rand = "0.8.5" diff --git a/codes/rust/chapter_hashing/build_in_hash.rs b/codes/rust/chapter_hashing/build_in_hash.rs new file mode 100644 index 00000000..7ea7620b --- /dev/null +++ b/codes/rust/chapter_hashing/build_in_hash.rs @@ -0,0 +1,50 @@ +/* + * File: build_in_hash.rs + * Created Time: 2023-7-6 + * Author: WSL0809 (wslzzy@outlook.com) + */ + +include!("../include/include.rs"); + +use crate::list_node::ListNode; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; + +/* Driver Code */ +fn main() { + let num = 3; + let mut num_hasher = DefaultHasher::new(); + num.hash(&mut num_hasher); + let hash_num = num_hasher.finish(); + println!("整数 {} 的哈希值为 {}", num, hash_num); + + let bol = true; + let mut bol_hasher = DefaultHasher::new(); + bol.hash(&mut bol_hasher); + let hash_bol = bol_hasher.finish(); + println!("布尔量 {} 的哈希值为 {}", bol, hash_bol); + + let dec: f32 = 3.14159; + let mut dec_hasher = DefaultHasher::new(); + dec.to_bits().hash(&mut dec_hasher); + let hash_dec = dec_hasher.finish(); + println!("小数 {} 的哈希值为 {}", dec, hash_dec); + + let str = "Hello 算法"; + let mut str_hasher = DefaultHasher::new(); + str.hash(&mut str_hasher); + let hash_str = str_hasher.finish(); + println!("字符串 {} 的哈希值为 {}", str, hash_str); + + let arr = (&12836, &"小哈"); + let mut tup_hasher = DefaultHasher::new(); + arr.hash(&mut tup_hasher); + let hash_tup = tup_hasher.finish(); + println!("元组 {:?} 的哈希值为 {}", arr, hash_tup); + + let node = ListNode::new(42); + let mut hasher = DefaultHasher::new(); + node.borrow().val.hash(&mut hasher); + let hash = hasher.finish(); + println!("节点对象 {:?} 的哈希值为{}", node, hash); +} diff --git a/codes/rust/chapter_hashing/hash_map_chaining.rs b/codes/rust/chapter_hashing/hash_map_chaining.rs new file mode 100644 index 00000000..93e84c49 --- /dev/null +++ b/codes/rust/chapter_hashing/hash_map_chaining.rs @@ -0,0 +1,164 @@ +/* + * File: hash_map_chaining.rs + * Created Time: 2023-07-07 + * Author: WSL0809 (wslzzy@outlook.com) + */ + +#[derive(Clone)] +/* 键值对 */ +struct Pair { + key: i32, + val: String, +} + +/* 链式地址哈希表 */ +struct HashMapChaining { + size: i32, + capacity: i32, + load_thres: f32, + extend_ratio: i32, + buckets: Vec>, +} + +impl HashMapChaining { + /* 构造方法 */ + fn new() -> Self { + Self { + size: 0, + capacity: 4, + load_thres: 2.0 / 3.0, + extend_ratio: 2, + buckets: vec![vec![]; 4], + } + } + + /* 哈希函数 */ + fn hash_func(&self, key: i32) -> usize { + key as usize % self.capacity as usize + } + + /* 负载因子 */ + fn load_factor(&self) -> f32 { + self.size as f32 / self.capacity as f32 + } + + /* 删除操作 */ + fn remove(&mut self, key: i32) -> Option { + let index = self.hash_func(key); + let bucket = &mut self.buckets[index]; + + // 遍历桶,从中删除键值对 + for i in 0..bucket.len() { + if bucket[i].key == key { + let pair = bucket.remove(i); + self.size -= 1; + return Some(pair.val); + } + } + + // 若未找到 key 则返回 None + None + } + + /* 扩容哈希表 */ + fn extend(&mut self) { + // 暂存原哈希表 + let buckets_tmp = std::mem::replace(&mut self.buckets, vec![]); + + // 初始化扩容后的新哈希表 + self.capacity *= self.extend_ratio; + self.buckets = vec![Vec::new(); self.capacity as usize]; + self.size = 0; + + // 将键值对从原哈希表搬运至新哈希表 + for bucket in buckets_tmp { + for pair in bucket { + self.put(pair.key, pair.val); + } + } + } + + /* 打印哈希表 */ + fn print(&self) { + for bucket in &self.buckets { + let mut res = Vec::new(); + for pair in bucket { + res.push(format!("{} -> {}", pair.key, pair.val)); + } + println!("{:?}", res); + } + } + + /* 添加操作 */ + fn put(&mut self, key: i32, val: String) { + // 当负载因子超过阈值时,执行扩容 + if self.load_factor() > self.load_thres { + self.extend(); + } + + let index = self.hash_func(key); + let bucket = &mut self.buckets[index]; + + // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 + for pair in bucket { + if pair.key == key { + pair.val = val.clone(); + return; + } + } + let bucket = &mut self.buckets[index]; + + // 若无该 key ,则将键值对添加至尾部 + let pair = Pair { + key, + val: val.clone(), + }; + bucket.push(pair); + self.size += 1; + } + + /* 查询操作 */ + fn get(&self, key: i32) -> Option<&str> { + let index = self.hash_func(key); + let bucket = &self.buckets[index]; + + // 遍历桶,若找到 key 则返回对应 val + for pair in bucket { + if pair.key == key { + return Some(&pair.val); + } + } + + // 若未找到 key 则返回 None + None + } +} + +/* Driver Code */ +pub fn main() { + /* 初始化哈希表 */ + let mut map = HashMapChaining::new(); + + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.put(12836, "小哈".to_string()); + map.put(15937, "小啰".to_string()); + map.put(16750, "小算".to_string()); + map.put(13276, "小法".to_string()); + map.put(10583, "小鸭".to_string()); + println!("\n添加完成后,哈希表为\nKey -> Value"); + map.print(); + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + println!("\n输入学号 13276,查询到姓名 {}", match map.get(13276) { + Some(value) => value, + None => "Not a valid Key" + }); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(12836); + println!("\n删除 12836 后,哈希表为\nKey -> Value"); + map.print(); +} diff --git a/codes/rust/chapter_hashing/hash_map_open_addressing.rs b/codes/rust/chapter_hashing/hash_map_open_addressing.rs new file mode 100644 index 00000000..0be96e61 --- /dev/null +++ b/codes/rust/chapter_hashing/hash_map_open_addressing.rs @@ -0,0 +1,181 @@ +/* + * File: hash_map_open_addressing.rs + * Created Time: 2023-07-16 + * Author: WSL0809 (wslzzy@outlook.com) + */ + +#[derive(Clone, PartialEq)] +/* 键值对 */ +struct Pair { + key: i32, + val: String, +} + +/* 开放寻址哈希表 */ +struct HashMapOpenAddressing { + size: usize, + capacity: usize, + load_thres: f32, + extend_ratio: usize, + buckets: Vec>, + removed: Pair, +} + + +impl HashMapOpenAddressing { + /* 构造方法 */ + fn new() -> Self { + Self { + size: 0, + capacity: 4, + load_thres: 2.0 / 3.0, + extend_ratio: 2, + buckets: vec![None; 4], + removed: Pair { + key: -1, + val: "-1".to_string(), + }, + } + } + + /* 哈希函数 */ + fn hash_func(&self, key: i32) -> usize { + (key % self.capacity as i32) as usize + } + + /* 负载因子 */ + fn load_factor(&self) -> f32 { + self.size as f32 / self.capacity as f32 + } + + /* 查询操作 */ + fn get(&self, key: i32) -> Option<&str> { + let mut index = self.hash_func(key); + let capacity = self.capacity; + // 线性探测,从 index 开始向后遍历 + for _ in 0..capacity { + // 计算桶索引,越过尾部返回头部 + let j = (index + 1) % capacity; + match &self.buckets[j] { + // 若遇到空桶,说明无此 key ,则返回 None + None => return None, + // 若遇到指定 key ,则返回对应 val + Some(pair) if pair.key == key && pair != &self.removed => return Some(&pair.val), + _ => index = j, + } + } + + None + } + + /* 添加操作 */ + fn put(&mut self, key: i32, val: String) { + // 当负载因子超过阈值时,执行扩容 + if self.load_factor() > self.load_thres { + self.extend(); + } + + let mut index = self.hash_func(key); + let capacity = self.capacity; + + // 线性探测,从 index 开始向后遍历 + for _ in 0..capacity { + //计算桶索引,越过尾部返回头部 + let j = (index + 1) % capacity; + // 若遇到空桶、或带有删除标记的桶,则将键值对放入该桶 + match &mut self.buckets[j] { + bucket @ &mut None | bucket @ &mut Some(Pair { key: -1, .. }) => { + *bucket = Some(Pair { key, val }); + self.size += 1; + return; + } + // 若遇到指定 key ,则更新对应 val + Some(pair) if pair.key == key => { + pair.val = val; + return; + } + _ => index = j, + } + } + } + + /* 删除操作 */ + fn remove(&mut self, key: i32) { + let mut index = self.hash_func(key); + let capacity = self.capacity; + + // 遍历桶,从中删除键值对 + for _ in 0..capacity { + let j = (index + 1) % capacity; + match &mut self.buckets[j] { + // 若遇到空桶,说明无此 key ,则直接返回 + None => return, + // 若遇到指定 key ,则标记删除并返回 + Some(pair) if pair.key == key => { + *pair = Pair { + key: -1, + val: "-1".to_string(), + }; + self.size -= 1; + return; + } + _ => index = j, + } + } + } + + + /* 扩容哈希表 */ + fn extend(&mut self) { + // 暂存原哈希表 + let buckets_tmp = self.buckets.clone(); + // 初始化扩容后的新哈希表 + self.capacity *= self.extend_ratio; + self.buckets = vec![None; self.capacity]; + self.size = 0; + + // 将键值对从原哈希表搬运至新哈希表 + for pair in buckets_tmp { + if let Some(pair) = pair { + self.put(pair.key, pair.val); + } + } + } + /* 打印哈希表 */ + fn print(&self) { + for pair in &self.buckets { + match pair { + Some(pair) => println!("{} -> {}", pair.key, pair.val), + None => println!("None"), + } + } + } +} + +/* Driver Code */ +fn main() { + /* 初始化哈希表 */ + let mut hashmap = HashMapOpenAddressing::new(); + + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + hashmap.put(12836, "小哈".to_string()); + hashmap.put(15937, "小啰".to_string()); + hashmap.put(16750, "小算".to_string()); + hashmap.put(13276, "小法".to_string()); + hashmap.put(10583, "小鸭".to_string()); + + println!("\n添加完成后,哈希表为\nKey -> Value"); + hashmap.print(); + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + let name = hashmap.get(13276).unwrap(); + println!("\n输入学号 13276 ,查询到姓名 {}", name); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + hashmap.remove(16750); + println!("\n删除 16750 后,哈希表为\nKey -> Value"); + hashmap.print(); +}