forked from wangzheng0822/algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[19_hashtable] replace all CRLF -> LF.
- Loading branch information
Showing
1 changed file
with
59 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,59 @@ | ||
# 散列表 | ||
|
||
核心:散列表的效率并不总是 $O(1)$,仅仅是在理论上能达到 $O(1)$。实际情况中,恶意攻击者可以通过精心构造数据,使得散列表的性能急剧下降。 | ||
|
||
如何设计一个工业级的散列表? | ||
|
||
## 散列函数 | ||
|
||
* 不能过于复杂——避免散列过程耗时 | ||
* 散列函数的结果要尽可能均匀——最小化散列冲突 | ||
|
||
## 装载因子过大怎么办 | ||
|
||
动态扩容。涉及到 rehash,效率可能很低。 | ||
|
||
![](https://static001.geekbang.org/resource/image/67/43/67d12e07a7d673a9c1d14354ad029443.jpg) | ||
|
||
如何避免低效扩容? | ||
|
||
——将 rehash 的步骤,均摊到每一次插入中去: | ||
|
||
* 申请新的空间 | ||
* 不立即使用 | ||
* 每次来了新的数据,往新表插入数据 | ||
* 同时,取出旧表的一个数据,插入新表 | ||
|
||
![](https://static001.geekbang.org/resource/image/6d/cb/6d6736f986ec4b75dabc5472965fb9cb.jpg) | ||
|
||
## 解决冲突 | ||
|
||
开放寻址法,优点: | ||
|
||
* 不需要额外空间 | ||
* 有效利用 CPU 缓存 | ||
* 方便序列化 | ||
|
||
开放寻址法,缺点: | ||
|
||
* 查找、删除数据时,涉及到 `delete` 标志,相对麻烦 | ||
* 冲突的代价更高 | ||
* 对装载因子敏感 | ||
|
||
链表法,优点: | ||
|
||
* 内存利用率较高——链表的优点 | ||
* 对装载因子不敏感 | ||
|
||
链表法,缺点: | ||
|
||
* 需要额外的空间(保存指针) | ||
* 对 CPU 缓存不友好 | ||
|
||
——将链表改造成更高效的数据结构,例如跳表、红黑树 | ||
|
||
## 举个栗子(JAVA 中的 HashMap) | ||
|
||
* 初始大小:16 | ||
* 装载因子:超过 0.75 时动态扩容 | ||
* 散列冲突:优化版的链表法(当槽位冲突元素超过 8 时使用红黑树,否则使用链表) | ||
# 散列表 | ||
|
||
核心:散列表的效率并不总是 $O(1)$,仅仅是在理论上能达到 $O(1)$。实际情况中,恶意攻击者可以通过精心构造数据,使得散列表的性能急剧下降。 | ||
|
||
如何设计一个工业级的散列表? | ||
|
||
## 散列函数 | ||
|
||
* 不能过于复杂——避免散列过程耗时 | ||
* 散列函数的结果要尽可能均匀——最小化散列冲突 | ||
|
||
## 装载因子过大怎么办 | ||
|
||
动态扩容。涉及到 rehash,效率可能很低。 | ||
|
||
![](https://static001.geekbang.org/resource/image/67/43/67d12e07a7d673a9c1d14354ad029443.jpg) | ||
|
||
如何避免低效扩容? | ||
|
||
——将 rehash 的步骤,均摊到每一次插入中去: | ||
|
||
* 申请新的空间 | ||
* 不立即使用 | ||
* 每次来了新的数据,往新表插入数据 | ||
* 同时,取出旧表的一个数据,插入新表 | ||
|
||
![](https://static001.geekbang.org/resource/image/6d/cb/6d6736f986ec4b75dabc5472965fb9cb.jpg) | ||
|
||
## 解决冲突 | ||
|
||
开放寻址法,优点: | ||
|
||
* 不需要额外空间 | ||
* 有效利用 CPU 缓存 | ||
* 方便序列化 | ||
|
||
开放寻址法,缺点: | ||
|
||
* 查找、删除数据时,涉及到 `delete` 标志,相对麻烦 | ||
* 冲突的代价更高 | ||
* 对装载因子敏感 | ||
|
||
链表法,优点: | ||
|
||
* 内存利用率较高——链表的优点 | ||
* 对装载因子不敏感 | ||
|
||
链表法,缺点: | ||
|
||
* 需要额外的空间(保存指针) | ||
* 对 CPU 缓存不友好 | ||
|
||
——将链表改造成更高效的数据结构,例如跳表、红黑树 | ||
|
||
## 举个栗子(JAVA 中的 HashMap) | ||
|
||
* 初始大小:16 | ||
* 装载因子:超过 0.75 时动态扩容 | ||
* 散列冲突:优化版的链表法(当槽位冲突元素超过 8 时使用红黑树,否则使用链表) |