--- comments: true --- # 6.1.   哈希表 哈希表通过建立「键 key」与「值 value」之间的映射,实现高效的元素查询。具体而言,我们向哈希表输入一个 key,则可以在 $O(1)$ 时间内获取对应的 value 。 以一个包含 $n$ 个学生的数据库为例,每个学生都有“姓名 `name`”和“学号 `id`”两项数据。假如我们希望实现查询功能,例如“输入一个学号,返回对应的姓名”,则可以采用哈希表来实现。 ![哈希表的抽象表示](hash_map.assets/hash_map.png)

Fig. 哈希表的抽象表示

## 6.1.1.   哈希表效率 除哈希表外,还可以使用以下数据结构来实现上述查询功能: 1. **无序数组**:每个元素为 `[学号, 姓名]` ; 2. **有序数组**:将 `1.` 中的数组按照学号从小到大排序; 3. **链表**:每个节点的值为 `[学号, 姓名]` ; 4. **二叉搜索树**:每个节点的值为 `[学号, 姓名]` ,根据学号大小来构建树; 各项操作的时间复杂度如下表所示(详解可见[二叉搜索树章节](https://www.hello-algo.com/chapter_tree/binary_search_tree/))。无论是查找元素还是增删元素,哈希表的时间复杂度都是 $O(1)$ ,全面胜出!
| | 无序数组 | 有序数组 | 链表 | 二叉搜索树 | 哈希表 | | -------- | -------- | ----------- | ------ | ----------- | ------ | | 查找元素 | $O(n)$ | $O(\log n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | | 插入元素 | $O(1)$ | $O(n)$ | $O(1)$ | $O(\log n)$ | $O(1)$ | | 删除元素 | $O(n)$ | $O(n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ |
## 6.1.2.   哈希表常用操作 哈希表的基本操作包括 **初始化、查询操作、添加与删除键值对**。 === "Java" ```java title="hash_map.java" /* 初始化哈希表 */ Map map = new HashMap<>(); /* 添加操作 */ // 在哈希表中添加键值对 (key, value) 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); ``` === "C++" ```cpp title="hash_map.cpp" /* 初始化哈希表 */ unordered_map map; /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map[12836] = "小哈"; map[15937] = "小啰"; map[16750] = "小算"; map[13276] = "小法"; map[10583] = "小鸭"; /* 查询操作 */ // 向哈希表输入键 key ,得到值 value string name = map[15937]; /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.erase(10583); ``` === "Python" ```python title="hash_map.py" # 初始化哈希表 mapp: Dict = {} # 添加操作 # 在哈希表中添加键值对 (key, value) mapp[12836] = "小哈" mapp[15937] = "小啰" mapp[16750] = "小算" mapp[13276] = "小法" mapp[10583] = "小鸭" # 查询操作 # 向哈希表输入键 key ,得到值 value name: str = mapp[15937] # 删除操作 # 在哈希表中删除键值对 (key, value) mapp.pop(10583) ``` === "Go" ```go title="hash_map.go" /* 初始化哈希表 */ mapp := make(map[int]string) /* 添加操作 */ // 在哈希表中添加键值对 (key, value) mapp[12836] = "小哈" mapp[15937] = "小啰" mapp[16750] = "小算" mapp[13276] = "小法" mapp[10583] = "小鸭" /* 查询操作 */ // 向哈希表输入键 key ,得到值 value name := mapp[15937] /* 删除操作 */ // 在哈希表中删除键值对 (key, value) delete(mapp, 10583) ``` === "JavaScript" ```javascript title="hash_map.js" /* 初始化哈希表 */ const map = new ArrayHashMap(); /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map.set(12836, '小哈'); map.set(15937, '小啰'); map.set(16750, '小算'); map.set(13276, '小法'); map.set(10583, '小鸭'); /* 查询操作 */ // 向哈希表输入键 key ,得到值 value let name = map.get(15937); /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.delete(10583); ``` === "TypeScript" ```typescript title="hash_map.ts" /* 初始化哈希表 */ const map = new Map(); /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map.set(12836, '小哈'); map.set(15937, '小啰'); map.set(16750, '小算'); map.set(13276, '小法'); 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); console.info('\n删除 10583 后,哈希表为\nKey -> Value'); console.info(map); ``` === "C" ```c title="hash_map.c" ``` === "C#" ```csharp title="hash_map.cs" /* 初始化哈希表 */ Dictionary map = new (); /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map.Add(12836, "小哈"); map.Add(15937, "小啰"); map.Add(16750, "小算"); map.Add(13276, "小法"); map.Add(10583, "小鸭"); /* 查询操作 */ // 向哈希表输入键 key ,得到值 value String name = map[15937]; /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.Remove(10583); ``` === "Swift" ```swift title="hash_map.swift" /* 初始化哈希表 */ var map: [Int: String] = [:] /* 添加操作 */ // 在哈希表中添加键值对 (key, value) map[12836] = "小哈" map[15937] = "小啰" map[16750] = "小算" map[13276] = "小法" map[10583] = "小鸭" /* 查询操作 */ // 向哈希表输入键 key ,得到值 value let name = map[15937]! /* 删除操作 */ // 在哈希表中删除键值对 (key, value) map.removeValue(forKey: 10583) ``` === "Zig" ```zig title="hash_map.zig" ``` 遍历哈希表有三种方式,即 **遍历键值对、遍历键、遍历值**。 === "Java" ```java title="hash_map.java" /* 遍历哈希表 */ // 遍历键值对 key->value for (Map.Entry kv: map.entrySet()) { System.out.println(kv.getKey() + " -> " + kv.getValue()); } // 单独遍历键 key for (int key: map.keySet()) { System.out.println(key); } // 单独遍历值 value for (String val: map.values()) { System.out.println(val); } ``` === "C++" ```cpp title="hash_map.cpp" /* 遍历哈希表 */ // 遍历键值对 key->value for (auto kv: map) { cout << kv.first << " -> " << kv.second << endl; } // 单独遍历键 key for (auto key: map) { cout << key.first << endl; } // 单独遍历值 value for (auto val: map) { cout << val.second << endl; } ``` === "Python" ```python title="hash_map.py" # 遍历哈希表 # 遍历键值对 key->value for key, value in mapp.items(): print(key, "->", value) # 单独遍历键 key for key in mapp.keys(): print(key) # 单独遍历值 value for value in mapp.values(): print(value) ``` === "Go" ```go title="hash_map_test.go" /* 遍历哈希表 */ // 遍历键值对 key->value for key, value := range mapp { fmt.Println(key, "->", value) } // 单独遍历键 key for key := range mapp { fmt.Println(key) } // 单独遍历值 value for _, value := range mapp { fmt.Println(value) } ``` === "JavaScript" ```javascript title="hash_map.js" /* 遍历哈希表 */ console.info('\n遍历键值对 Key->Value'); for (const [k, v] of map.entries()) { console.info(k + ' -> ' + v); } console.info('\n单独遍历键 Key'); for (const k of map.keys()) { console.info(k); } console.info('\n单独遍历值 Value'); for (const v of map.values()) { console.info(v); } ``` === "TypeScript" ```typescript title="hash_map.ts" /* 遍历哈希表 */ console.info('\n遍历键值对 Key->Value'); for (const [k, v] of map.entries()) { console.info(k + ' -> ' + v); } console.info('\n单独遍历键 Key'); for (const k of map.keys()) { console.info(k); } console.info('\n单独遍历值 Value'); for (const v of map.values()) { console.info(v); } ``` === "C" ```c title="hash_map.c" ``` === "C#" ```csharp title="hash_map.cs" /* 遍历哈希表 */ // 遍历键值对 Key->Value foreach (var kv in map) { Console.WriteLine(kv.Key + " -> " + kv.Value); } // 单独遍历键 key foreach (int key in map.Keys) { Console.WriteLine(key); } // 单独遍历值 value foreach (String val in map.Values) { Console.WriteLine(val); } ``` === "Swift" ```swift title="hash_map.swift" /* 遍历哈希表 */ // 遍历键值对 Key->Value for (key, value) in map { print("\(key) -> \(value)") } // 单独遍历键 Key for key in map.keys { print(key) } // 单独遍历值 Value for value in map.values { print(value) } ``` === "Zig" ```zig title="hash_map.zig" ``` ## 6.1.3.   哈希函数 哈希表的底层实现为数组,同时可能包含链表、二叉树(红黑树)等数据结构,以提高查询性能(将在下节讨论)。 首先考虑最简单的情况,**仅使用一个数组来实现哈希表**。通常,我们将数组中的每个空位称为「桶 Bucket」,用于存储键值对。 我们将键值对 key, value 封装成一个类 `Entry` ,并将所有 `Entry` 放入数组中。这样,数组中的每个 `Entry` 都具有唯一的索引。为了建立 key 和索引之间的映射关系,我们需要使用「哈希函数 Hash Function」。 设哈希表的数组为 `buckets` ,哈希函数为 `f(x)` ,那么查询操作的步骤如下: 1. 输入 `key` ,通过哈希函数计算出索引 `index` ,即 `index = f(key)` ; 2. 通过索引在数组中访问到键值对 `entry` ,即 `entry = buckets[index]` ,然后从 `entry` 中获取对应的 `value` ; 以学生数据 `key 学号 -> value 姓名` 为例,我们可以设计如下哈希函数: $$ f(x) = x \% 100 $$ ![哈希函数工作原理](hash_map.assets/hash_function.png)

Fig. 哈希函数工作原理

=== "Java" ```java title="array_hash_map.java" /* 键值对 int->String */ class Entry { public int key; public String val; public Entry(int key, String val) { this.key = key; this.val = val; } } /* 基于数组简易实现的哈希表 */ class ArrayHashMap { private List buckets; public ArrayHashMap() { // 初始化数组,包含 100 个桶 buckets = new ArrayList<>(); for (int i = 0; i < 100; i++) { buckets.add(null); } } /* 哈希函数 */ private int hashFunc(int key) { int index = key % 100; return index; } /* 查询操作 */ public String get(int key) { int index = hashFunc(key); Entry pair = buckets.get(index); if (pair == null) return null; return pair.val; } /* 添加操作 */ public void put(int key, String val) { Entry pair = new Entry(key, val); int index = hashFunc(key); buckets.set(index, pair); } /* 删除操作 */ public void remove(int key) { int index = hashFunc(key); // 置为 null ,代表删除 buckets.set(index, null); } /* 获取所有键值对 */ public List entrySet() { List entrySet = new ArrayList<>(); for (Entry pair : buckets) { if (pair != null) entrySet.add(pair); } return entrySet; } /* 获取所有键 */ public List keySet() { List keySet = new ArrayList<>(); for (Entry pair : buckets) { if (pair != null) keySet.add(pair.key); } return keySet; } /* 获取所有值 */ public List valueSet() { List valueSet = new ArrayList<>(); for (Entry pair : buckets) { if (pair != null) valueSet.add(pair.val); } return valueSet; } /* 打印哈希表 */ public void print() { for (Entry kv : entrySet()) { System.out.println(kv.key + " -> " + kv.val); } } } ``` === "C++" ```cpp title="array_hash_map.cpp" /* 键值对 int->String */ struct Entry { public: int key; string val; Entry(int key, string val) { this->key = key; this->val = val; } }; /* 基于数组简易实现的哈希表 */ class ArrayHashMap { private: vector buckets; public: ArrayHashMap() { // 初始化数组,包含 100 个桶 buckets = vector(100); } ~ArrayHashMap() { // 释放内存 for (const auto &bucket : buckets) { delete bucket; } buckets.clear(); } /* 哈希函数 */ int hashFunc(int key) { int index = key % 100; return index; } /* 查询操作 */ string get(int key) { int index = hashFunc(key); Entry *pair = buckets[index]; if (pair == nullptr) return nullptr; return pair->val; } /* 添加操作 */ void put(int key, string val) { Entry *pair = new Entry(key, val); int index = hashFunc(key); buckets[index] = pair; } /* 删除操作 */ void remove(int key) { int index = hashFunc(key); // 释放内存并置为 nullptr delete buckets[index]; buckets[index] = nullptr; } /* 获取所有键值对 */ vector entrySet() { vector entrySet; for (Entry *pair : buckets) { if (pair != nullptr) { entrySet.push_back(pair); } } return entrySet; } /* 获取所有键 */ vector keySet() { vector keySet; for (Entry *pair : buckets) { if (pair != nullptr) { keySet.push_back(pair->key); } } return keySet; } /* 获取所有值 */ vector valueSet() { vector valueSet; for (Entry *pair : buckets) { if (pair != nullptr) { valueSet.push_back(pair->val); } } return valueSet; } /* 打印哈希表 */ void print() { for (Entry *kv : entrySet()) { cout << kv->key << " -> " << kv->val << endl; } } }; ``` === "Python" ```python title="array_hash_map.py" class Entry: """键值对 int->String""" def __init__(self, key: int, val: str): self.key = key self.val = val class ArrayHashMap: """基于数组简易实现的哈希表""" def __init__(self): """构造方法""" # 初始化数组,包含 100 个桶 self.buckets: list[Entry | None] = [None] * 100 def hash_func(self, key: int) -> int: """哈希函数""" index: int = key % 100 return index def get(self, key: int) -> str: """查询操作""" index: int = self.hash_func(key) pair: Entry = self.buckets[index] if pair is None: return None return pair.val def put(self, key: int, val: str) -> None: """添加操作""" pair = Entry(key, val) index: int = self.hash_func(key) self.buckets[index] = pair def remove(self, key: int) -> None: """删除操作""" index: int = self.hash_func(key) # 置为 None ,代表删除 self.buckets[index] = None def entry_set(self) -> list[Entry]: """获取所有键值对""" result: list[Entry] = [] for pair in self.buckets: if pair is not None: result.append(pair) return result def key_set(self) -> list[int]: """获取所有键""" result: list[int] = [] for pair in self.buckets: if pair is not None: result.append(pair.key) return result def value_set(self) -> list[str]: """获取所有值""" result: list[str] = [] for pair in self.buckets: if pair is not None: result.append(pair.val) return result def print(self) -> None: """打印哈希表""" for pair in self.buckets: if pair is not None: print(pair.key, "->", pair.val) ``` === "Go" ```go title="array_hash_map.go" /* 键值对 int->String */ type entry struct { key int val string } /* 基于数组简易实现的哈希表 */ type arrayHashMap struct { buckets []*entry } /* 初始化哈希表 */ func newArrayHashMap() *arrayHashMap { // 初始化数组,包含 100 个桶 buckets := make([]*entry, 100) return &arrayHashMap{buckets: buckets} } /* 哈希函数 */ func (a *arrayHashMap) hashFunc(key int) int { index := key % 100 return index } /* 查询操作 */ func (a *arrayHashMap) get(key int) string { index := a.hashFunc(key) pair := a.buckets[index] if pair == nil { return "Not Found" } return pair.val } /* 添加操作 */ func (a *arrayHashMap) put(key int, val string) { pair := &entry{key: key, val: val} index := a.hashFunc(key) a.buckets[index] = pair } /* 删除操作 */ func (a *arrayHashMap) remove(key int) { index := a.hashFunc(key) // 置为 nil ,代表删除 a.buckets[index] = nil } /* 获取所有键对 */ func (a *arrayHashMap) entrySet() []*entry { var pairs []*entry for _, pair := range a.buckets { if pair != nil { pairs = append(pairs, pair) } } return pairs } /* 获取所有键 */ func (a *arrayHashMap) keySet() []int { var keys []int for _, pair := range a.buckets { if pair != nil { keys = append(keys, pair.key) } } return keys } /* 获取所有值 */ func (a *arrayHashMap) valueSet() []string { var values []string for _, pair := range a.buckets { if pair != nil { values = append(values, pair.val) } } return values } /* 打印哈希表 */ func (a *arrayHashMap) print() { for _, pair := range a.buckets { if pair != nil { fmt.Println(pair.key, "->", pair.val) } } } ``` === "JavaScript" ```javascript title="array_hash_map.js" /* 键值对 Number -> String */ class Entry { constructor(key, val) { this.key = key; this.val = val; } } /* 基于数组简易实现的哈希表 */ class ArrayHashMap { #buckets; constructor() { // 初始化数组,包含 100 个桶 this.#buckets = new Array(100).fill(null); } /* 哈希函数 */ #hashFunc(key) { return key % 100; } /* 查询操作 */ get(key) { let index = this.#hashFunc(key); let entry = this.#buckets[index]; if (entry === null) return null; return entry.val; } /* 添加操作 */ set(key, val) { let index = this.#hashFunc(key); this.#buckets[index] = new Entry(key, val); } /* 删除操作 */ delete(key) { let index = this.#hashFunc(key); // 置为 null ,代表删除 this.#buckets[index] = null; } /* 获取所有键值对 */ entries() { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { if (this.#buckets[i]) { arr.push(this.#buckets[i]); } } return arr; } /* 获取所有键 */ keys() { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { if (this.#buckets[i]) { arr.push(this.#buckets[i]?.key); } } return arr; } /* 获取所有值 */ values() { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { if (this.#buckets[i]) { arr.push(this.#buckets[i]?.val); } } return arr; } /* 打印哈希表 */ print() { let entrySet = this.entries(); for (const entry of entrySet) { if (!entry) continue; console.info(`${entry.key} -> ${entry.val}`); } } } ``` === "TypeScript" ```typescript title="array_hash_map.ts" /* 键值对 Number -> String */ class Entry { public key: number; public val: string; constructor(key: number, val: string) { this.key = key; this.val = val; } } /* 基于数组简易实现的哈希表 */ class ArrayHashMap { private readonly buckets: (Entry | null)[]; constructor() { // 初始化数组,包含 100 个桶 this.buckets = (new Array(100)).fill(null); } /* 哈希函数 */ private hashFunc(key: number): number { return key % 100; } /* 查询操作 */ public get(key: number): string | null { let index = this.hashFunc(key); let entry = this.buckets[index]; if (entry === null) return null; return entry.val; } /* 添加操作 */ public set(key: number, val: string) { let index = this.hashFunc(key); this.buckets[index] = new Entry(key, val); } /* 删除操作 */ public delete(key: number) { let index = this.hashFunc(key); // 置为 null ,代表删除 this.buckets[index] = null; } /* 获取所有键值对 */ public entries(): (Entry | null)[] { let arr: (Entry | null)[] = []; for (let i = 0; i < this.buckets.length; i++) { if (this.buckets[i]) { arr.push(this.buckets[i]); } } return arr; } /* 获取所有键 */ public keys(): (number | undefined)[] { let arr: (number | undefined)[] = []; for (let i = 0; i < this.buckets.length; i++) { if (this.buckets[i]) { arr.push(this.buckets[i]?.key); } } return arr; } /* 获取所有值 */ public values(): (string | undefined)[] { let arr: (string | undefined)[] = []; for (let i = 0; i < this.buckets.length; i++) { if (this.buckets[i]) { arr.push(this.buckets[i]?.val); } } return arr; } /* 打印哈希表 */ public print() { let entrySet = this.entries(); for (const entry of entrySet) { if (!entry) continue; console.info(`${entry.key} -> ${entry.val}`); } } } ``` === "C" ```c title="array_hash_map.c" [class]{entry}-[func]{} [class]{arrayHashMap}-[func]{} ``` === "C#" ```csharp title="array_hash_map.cs" /* 键值对 int->String */ class Entry { public int key; public String val; public Entry(int key, String val) { this.key = key; this.val = val; } } /* 基于数组简易实现的哈希表 */ class ArrayHashMap { private List buckets; public ArrayHashMap() { // 初始化数组,包含 100 个桶 buckets = new(); for (int i = 0; i < 100; i++) { buckets.Add(null); } } /* 哈希函数 */ private int hashFunc(int key) { int index = key % 100; return index; } /* 查询操作 */ public String? get(int key) { int index = hashFunc(key); Entry? pair = buckets[index]; if (pair == null) return null; return pair.val; } /* 添加操作 */ public void put(int key, String val) { Entry pair = new Entry(key, val); int index = hashFunc(key); buckets[index] = pair; } /* 删除操作 */ public void remove(int key) { int index = hashFunc(key); // 置为 null ,代表删除 buckets[index] = null; } /* 获取所有键值对 */ public List entrySet() { List entrySet = new(); foreach (Entry? pair in buckets) { if (pair != null) entrySet.Add(pair); } return entrySet; } /* 获取所有键 */ public List keySet() { List keySet = new(); foreach (Entry? pair in buckets) { if (pair != null) keySet.Add(pair.key); } return keySet; } /* 获取所有值 */ public List valueSet() { List valueSet = new(); foreach (Entry? pair in buckets) { if (pair != null) valueSet.Add(pair.val); } return valueSet; } /* 打印哈希表 */ public void print() { foreach (Entry kv in entrySet()) { Console.WriteLine(kv.key + " -> " + kv.val); } } } ``` === "Swift" ```swift title="array_hash_map.swift" /* 键值对 int->String */ class Entry { var key: Int var val: String init(key: Int, val: String) { self.key = key self.val = val } } /* 基于数组简易实现的哈希表 */ class ArrayHashMap { private var buckets: [Entry?] = [] init() { // 初始化数组,包含 100 个桶 for _ in 0 ..< 100 { buckets.append(nil) } } /* 哈希函数 */ private func hashFunc(key: Int) -> Int { let index = key % 100 return index } /* 查询操作 */ func get(key: Int) -> String? { let index = hashFunc(key: key) let pair = buckets[index] return pair?.val } /* 添加操作 */ func put(key: Int, val: String) { let pair = Entry(key: key, val: val) let index = hashFunc(key: key) buckets[index] = pair } /* 删除操作 */ func remove(key: Int) { let index = hashFunc(key: key) // 置为 nil ,代表删除 buckets[index] = nil } /* 获取所有键值对 */ func entrySet() -> [Entry] { var entrySet: [Entry] = [] for pair in buckets { if let pair = pair { entrySet.append(pair) } } return entrySet } /* 获取所有键 */ func keySet() -> [Int] { var keySet: [Int] = [] for pair in buckets { if let pair = pair { keySet.append(pair.key) } } return keySet } /* 获取所有值 */ func valueSet() -> [String] { var valueSet: [String] = [] for pair in buckets { if let pair = pair { valueSet.append(pair.val) } } return valueSet } /* 打印哈希表 */ func print() { for entry in entrySet() { Swift.print("\(entry.key) -> \(entry.val)") } } } ``` === "Zig" ```zig title="array_hash_map.zig" // 键值对 int->String const Entry = struct { key: usize = undefined, val: []const u8 = undefined, pub fn init(key: usize, val: []const u8) Entry { return Entry { .key = key, .val = val, }; } }; // 基于数组简易实现的哈希表 fn ArrayHashMap(comptime T: type) type { return struct { buckets: ?std.ArrayList(?T) = null, mem_allocator: std.mem.Allocator = undefined, const Self = @This(); // 构造方法 pub fn init(self: *Self, allocator: std.mem.Allocator) !void { self.mem_allocator = allocator; // 初始化数组,包含 100 个桶 self.buckets = std.ArrayList(?T).init(self.mem_allocator); var i: i32 = 0; while (i < 100) : (i += 1) { try self.buckets.?.append(null); } } // 析构方法 pub fn deinit(self: *Self) void { if (self.buckets != null) self.buckets.?.deinit(); } // 哈希函数 fn hashFunc(key: usize) usize { var index = key % 100; return index; } // 查询操作 pub fn get(self: *Self, key: usize) []const u8 { var index = hashFunc(key); var pair = self.buckets.?.items[index]; return pair.?.val; } // 添加操作 pub fn put(self: *Self, key: usize, val: []const u8) !void { var pair = Entry.init(key, val); var index = hashFunc(key); self.buckets.?.items[index] = pair; } // 删除操作 pub fn remove(self: *Self, key: usize) !void { var index = hashFunc(key); // 置为 null ,代表删除 self.buckets.?.items[index] = null; } // 获取所有键值对 pub fn entrySet(self: *Self) !*std.ArrayList(T) { var entry_set = std.ArrayList(T).init(self.mem_allocator); for (self.buckets.?.items) |item| { if (item == null) continue; try entry_set.append(item.?); } return &entry_set; } // 获取所有键 pub fn keySet(self: *Self) !*std.ArrayList(usize) { var key_set = std.ArrayList(usize).init(self.mem_allocator); for (self.buckets.?.items) |item| { if (item == null) continue; try key_set.append(item.?.key); } return &key_set; } // 获取所有值 pub fn valueSet(self: *Self) !*std.ArrayList([]const u8) { var value_set = std.ArrayList([]const u8).init(self.mem_allocator); for (self.buckets.?.items) |item| { if (item == null) continue; try value_set.append(item.?.val); } return &value_set; } // 打印哈希表 pub fn print(self: *Self) !void { var entry_set = try self.entrySet(); defer entry_set.deinit(); for (entry_set.items) |item| { std.debug.print("{} -> {s}\n", .{item.key, item.val}); } } }; } ``` ## 6.1.4.   哈希冲突 细心的你可能已经注意到,**在某些情况下,哈希函数 $f(x) = x % 100$ 可能无法正常工作**。具体来说,当输入的 key 后两位相同时,哈希函数的计算结果也会相同,从而指向同一个 value 。例如,查询学号为 $12836$ 和 $20336$ 的两个学生时,我们得到: $$ f(12836) = f(20336) = 36 $$ 这两个学号指向了同一个姓名,这显然是错误的。我们把这种情况称为「哈希冲突 Hash Collision」。在后续章节中,我们将讨论如何解决哈希冲突的问题。 ![哈希冲突示例](hash_map.assets/hash_collision.png)

Fig. 哈希冲突示例

综上所述,一个优秀的哈希函数应具备以下特性: - 尽可能减少哈希冲突的发生; - 查询效率高且稳定,能够在绝大多数情况下达到 $O(1)$ 时间复杂度; - 较高的空间利用率,即使“键值对占用空间 / 哈希表总占用空间”比例最大化;