From 2bc6e3076d65c5ba267d9002865f3125fdbd0535 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 13 Dec 2022 01:36:40 +0800 Subject: [PATCH] Update hash map and hash collision. --- docs/chapter_hashing/hash_collision.md | 2 +- docs/chapter_hashing/hash_map.md | 282 +++++++++++++++++------ docs/chapter_introduction/what_is_dsa.md | 4 +- docs/chapter_preface/about_the_book.md | 2 +- docs/chapter_preface/suggestions.md | 18 +- 5 files changed, 220 insertions(+), 88 deletions(-) diff --git a/docs/chapter_hashing/hash_collision.md b/docs/chapter_hashing/hash_collision.md index d9b1f7277..d2d2f54f5 100644 --- a/docs/chapter_hashing/hash_collision.md +++ b/docs/chapter_hashing/hash_collision.md @@ -13,7 +13,7 @@ comments: true - 哈希表的桶的大小(地址范围)是有限的,只要数据量足够大,理论上一定会出现冲突; - 哈希函数很难使键值对完全均匀分布,这也增大了冲突发生的可能性。 -哈希冲突的常见的解决方案有「链式地址」和「开放寻址」。 +虽然理论上哈希冲突无法避免,但我们仍然可以在数据结构与算法的层面缓解冲突问题,尽量保证哈希表的增删查改操作效率。**常见的哈希冲突的解决方案有「链式地址」和「开放寻址」**。 ## 链式地址 diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 2b5f8be60..793d90323 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -37,44 +37,132 @@ comments: true 哈希表的基本操作包括 **初始化、查询操作、添加与删除键值对**。 -```java title="hash_map.java" -/* 初始化哈希表 */ -Map map = new HashMap<>(); +=== "Java" -/* 添加操作 */ -// 在哈希表中添加键值对 (key, value) -map.put(12836, "小哈"); -map.put(15937, "小啰"); -map.put(16750, "小算"); -map.put(13276, "小法"); -map.put(10583, "小鸭"); + ```java title="hash_map.java" + /* 初始化哈希表 */ + Map map = new HashMap<>(); -/* 查询操作 */ -// 向哈希表输入键 key ,得到值 value -String name = map.get(15937); + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); -/* 删除操作 */ -// 在哈希表中删除键值对 (key, value) -map.remove(10583); -``` + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + String name = map.get(15937); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(10583); + ``` + +=== "C++" + + ```cpp title="hash_map.cpp" + + ``` + +=== "Python" + + ```python title="hash_map.py" + + ``` + +=== "Go" + + ```go title="hash_map.go" + + ``` + +=== "JavaScript" + + ```js title="hash_map.js" + + ``` + +=== "TypeScript" + + ```typescript title="hash_map.ts" + + ``` + +=== "C" + + ```c title="hash_map.c" + + ``` + +=== "C#" + + ```csharp title="hash_map.cs" + + ``` 遍历哈希表有三种方式,即 **遍历键值对、遍历键、遍历值**。 -```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); -} -``` +=== "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" + + ``` + +=== "Python" + + ```python title="hash_map.py" + + ``` + +=== "Go" + + ```go title="hash_map.go" + + ``` + +=== "JavaScript" + + ```js title="hash_map.js" + + ``` + +=== "TypeScript" + + ```typescript title="hash_map.ts" + + ``` + +=== "C" + + ```c title="hash_map.c" + + ``` + +=== "C#" + + ```csharp title="hash_map.cs" + + ``` ## 哈希函数 @@ -97,57 +185,101 @@ $$

Fig. 哈希函数

-```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; - } -} +=== "Java" -/* 基于数组简易实现的哈希表 */ -class ArrayHashMap { - private List bucket; - public ArrayHashMap() { - // 初始化一个长度为 100 的桶(数组) - bucket = new ArrayList<>(); - for (int i = 0; i < 100; i++) { - bucket.add(null); + ```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; } } - /* 哈希函数 */ - private int hashFunc(int key) { - int index = key % 100; - return index; - } + /* 基于数组简易实现的哈希表 */ + class ArrayHashMap { + private List bucket; + public ArrayHashMap() { + // 初始化一个长度为 100 的桶(数组) + bucket = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + bucket.add(null); + } + } - /* 查询操作 */ - public String get(int key) { - int index = hashFunc(key); - Entry pair = bucket.get(index); - if (pair == null) return null; - return pair.val; - } + /* 哈希函数 */ + private int hashFunc(int key) { + int index = key % 100; + return index; + } - /* 添加操作 */ - public void put(int key, String val) { - Entry pair = new Entry(key, val); - int index = hashFunc(key); - bucket.set(index, pair); - } + /* 查询操作 */ + public String get(int key) { + int index = hashFunc(key); + Entry pair = bucket.get(index); + if (pair == null) return null; + return pair.val; + } - /* 删除操作 */ - public void remove(int key) { - int index = hashFunc(key); - // 置为空字符,代表删除 - bucket.set(index, null); + /* 添加操作 */ + public void put(int key, String val) { + Entry pair = new Entry(key, val); + int index = hashFunc(key); + bucket.set(index, pair); + } + + /* 删除操作 */ + public void remove(int key) { + int index = hashFunc(key); + // 置为空字符,代表删除 + bucket.set(index, null); + } } -} -``` + ``` + +=== "C++" + + ```cpp title="array_hash_map.cpp" + + ``` + +=== "Python" + + ```python title="array_hash_map.py" + + ``` + +=== "Go" + + ```go title="array_hash_map.go" + + ``` + +=== "JavaScript" + + ```js title="array_hash_map.js" + + ``` + +=== "TypeScript" + + ```typescript title="array_hash_map.ts" + + ``` + +=== "C" + + ```c title="array_hash_map.c" + + ``` + +=== "C#" + + ```csharp title="array_hash_map.cs" + + ``` ## 哈希冲突 diff --git a/docs/chapter_introduction/what_is_dsa.md b/docs/chapter_introduction/what_is_dsa.md index b4ec27223..12ba333b1 100644 --- a/docs/chapter_introduction/what_is_dsa.md +++ b/docs/chapter_introduction/what_is_dsa.md @@ -37,6 +37,6 @@ comments: true

Fig. 数据结构与算法的关系

-!!! tip "约定俗成的习惯" +!!! tip "约定俗成的简称" - 在实际讨论中,我们通常会将「数据结构与算法」简称为「算法」。例如,我们熟称的 LeetCode 算法题目,实际上同时考察了数据结构和算法两部分知识。 + 在实际讨论中,我们通常会将「数据结构与算法」直接简称为「算法」。例如,我们熟称的 LeetCode 算法题目,实际上同时考察了数据结构和算法两部分知识。 diff --git a/docs/chapter_preface/about_the_book.md b/docs/chapter_preface/about_the_book.md index bd98efac3..fdb27b87b 100644 --- a/docs/chapter_preface/about_the_book.md +++ b/docs/chapter_preface/about_the_book.md @@ -115,7 +115,7 @@ comments: true - 感谢我的女朋友泡泡担任本书的首位读者,从算法小白的视角为本书的写作提出了许多建议,使这本书更加适合算法初学者来阅读。 - 感谢腾宝、琦宝、飞宝为本书起了个响当当的名字,好听又有梗,直接唤起我最初敲下第一行代码 "Hello, World!" 的回忆。 -- 感谢我的导师李博,在小酌畅谈时你告诉我 “想做就去做” ,坚定了我写这本书的决心。 +- 感谢我的导师李博,在小酌畅谈时您告诉我 “觉得适合、想做就去做” ,坚定了我写这本书的决心。 - 感谢苏潼为本书设计了封面和 LOGO ,我有些强迫症,前后多次修改,谢谢你的耐心。 - 感谢 @squidfunk ,包括 [Material-for-MkDocs](https://github.com/squidfunk/mkdocs-material/tree/master) 顶级开源项目以及给出的写作排版建议。 diff --git a/docs/chapter_preface/suggestions.md b/docs/chapter_preface/suggestions.md index 31f85ffda..20cdac70a 100644 --- a/docs/chapter_preface/suggestions.md +++ b/docs/chapter_preface/suggestions.md @@ -12,11 +12,11 @@ comments: true ![algorithm_animation](suggestions.assets/algorithm_animation.gif) -## 使用源代码 +## 代码实践学 !!! tip "前置工作" - 安装本地编程环境。若无,可以参照下节 [编程环境安装](https://www.hello-algo.com/chapter_preface/installation/) 。 + 如果没有本地编程环境,可以参照下节 [编程环境安装](https://www.hello-algo.com/chapter_preface/installation/) 。 ### 下载代码仓 @@ -36,17 +36,17 @@ git clone https://github.com/krahets/hello-algo.git ![code_md_to_repo](suggestions.assets/code_md_to_repo.png) -这些源文件中包含测试样例,可以直接运行,帮助你省去不必要的调试时间,可以将精力集中在学习内容上。 - -!!! tip "代码学习建议" - - 若学习时间紧张,请至少 **将所有代码通读并运行一遍**。若时间允许,强力建议 **对照着代码自己敲一遍**,逐渐锻炼肌肉记忆。相比于读代码,自己写的过程会带来新的收获。 +这些源文件中包含详细注释,配有测试样例,可以直接运行,帮助你省去不必要的调试时间,可以将精力集中在学习内容上。 ![running_code](suggestions.assets/running_code.gif) -## 参与讨论区 +!!! tip "代码学习建议" -阅读本书时,请不要 “惯着” 那些弄不明白的知识点。如果有任何疑惑,可以在评论区留下你的问题,小伙伴们和我都会给予解答(我一般 2 ~ 3 天看一次评论区)。 + 若学习时间紧张,**请至少将所有代码通读并运行一遍**。若时间允许,**强烈建议对照着代码自己敲一遍**,逐渐锻炼肌肉记忆。相比于读代码,写代码的过程往往能带来新的收获。 + +## 提问讨论学 + +阅读本书时,请不要 “惯着” 那些弄不明白的知识点。如果有任何疑惑,**可以在评论区留下你的问题**,小伙伴们和我都会给予解答(您一般 3 天内会得到回复)。 同时,也希望你可以多花时间逛逛评论区。一方面,可以看看大家遇到了什么问题,反过来查漏补缺,这往往可以引起更加深度的思考。另一方面,也希望你可以慷慨地解答小伙伴们的问题、分享自己的见解,大家一起加油与进步!