rust_algorithms/data_structures/
hash_table.rs1use std::collections::hash_map::DefaultHasher;
4use std::hash::{Hash, Hasher};
5
6#[derive(Debug, Clone)]
44pub struct HashTable<K, V> {
45 buckets: Vec<Vec<(K, V)>>,
46 len: usize,
47}
48
49impl<K: Hash + Eq, V> Default for HashTable<K, V> {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl<K: Hash + Eq, V> HashTable<K, V> {
56 const BOSHLANGICH: usize = 8;
57 const MAX_YUKLAMA: f64 = 0.75;
58
59 pub fn new() -> Self {
61 Self {
62 buckets: (0..Self::BOSHLANGICH).map(|_| Vec::new()).collect(),
63 len: 0,
64 }
65 }
66
67 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
69 if (self.len + 1) as f64 > self.buckets.len() as f64 * Self::MAX_YUKLAMA {
70 self.rehash();
71 }
72 let idx = self.bucket_index(&key);
73 for (k, v) in self.buckets[idx].iter_mut() {
74 if *k == key {
75 return Some(std::mem::replace(v, value));
76 }
77 }
78 self.buckets[idx].push((key, value));
79 self.len += 1;
80 None
81 }
82
83 pub fn get(&self, key: &K) -> Option<&V> {
85 let idx = self.bucket_index(key);
86 self.buckets[idx]
87 .iter()
88 .find(|(k, _)| k == key)
89 .map(|(_, v)| v)
90 }
91
92 pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
94 let idx = self.bucket_index(key);
95 self.buckets[idx]
96 .iter_mut()
97 .find(|(k, _)| k == key)
98 .map(|(_, v)| v)
99 }
100
101 pub fn contains_key(&self, key: &K) -> bool {
103 self.get(key).is_some()
104 }
105
106 pub fn remove(&mut self, key: &K) -> Option<V> {
108 let idx = self.bucket_index(key);
109 let pos = self.buckets[idx].iter().position(|(k, _)| k == key)?;
110 self.len -= 1;
111 Some(self.buckets[idx].swap_remove(pos).1)
112 }
113
114 pub fn len(&self) -> usize {
116 self.len
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.len == 0
122 }
123
124 pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
126 self.buckets
127 .iter()
128 .flat_map(|b| b.iter().map(|(k, v)| (k, v)))
129 }
130
131 fn bucket_index(&self, key: &K) -> usize {
132 let mut hasher = DefaultHasher::new();
133 key.hash(&mut hasher);
134 (hasher.finish() % self.buckets.len() as u64) as usize
135 }
136
137 fn rehash(&mut self) {
139 let yangi_hajm = self.buckets.len() * 2;
140 let eski = std::mem::replace(
141 &mut self.buckets,
142 (0..yangi_hajm).map(|_| Vec::new()).collect(),
143 );
144 for chelak in eski {
145 for (k, v) in chelak {
146 let idx = self.bucket_index(&k);
147 self.buckets[idx].push((k, v));
148 }
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156 use std::collections::HashMap;
157
158 #[test]
159 fn asosiy_amallar() {
160 let mut m = HashTable::new();
161 assert!(m.is_empty());
162 assert_eq!(m.insert("a", 1), None);
163 assert_eq!(m.insert("a", 2), Some(1));
164 assert_eq!(m.len(), 1);
165 assert_eq!(m.get(&"a"), Some(&2));
166 assert!(m.contains_key(&"a"));
167 assert_eq!(m.remove(&"a"), Some(2));
168 assert_eq!(m.remove(&"a"), None);
169 assert!(m.is_empty());
170 }
171
172 #[test]
173 fn get_mut_ishlaydi() {
174 let mut m = HashTable::new();
175 m.insert(1, String::from("bir"));
176 m.get_mut(&1).unwrap().push_str("inchi");
177 assert_eq!(m.get(&1).map(String::as_str), Some("birinchi"));
178 }
179
180 #[test]
181 fn std_hashmap_bilan_bir_xil_ishlaydi() {
182 let mut ours = HashTable::new();
183 let mut theirs = HashMap::new();
184
185 for i in 0..1000i32 {
186 let kalit = format!("kalit-{}", i * 7 % 337);
187 assert_eq!(ours.insert(kalit.clone(), i), theirs.insert(kalit, i));
188 }
189 assert_eq!(ours.len(), theirs.len());
190
191 for (k, v) in theirs.iter() {
192 assert_eq!(ours.get(k), Some(v));
193 }
194
195 for k in theirs.keys() {
196 assert!(ours.contains_key(k));
197 }
198 }
199
200 #[test]
201 fn rehashdan_keyin_hamma_kalit_joyida() {
202 let mut m = HashTable::new();
203 for i in 0..500 {
204 m.insert(i, i * i);
205 }
206 assert_eq!(m.len(), 500);
207 for i in 0..500 {
208 assert_eq!(m.get(&i), Some(&(i * i)));
209 }
210 assert_eq!(m.iter().count(), 500);
211 }
212}