algo/notes/19_hashtable
2018-12-18 17:02:43 +08:00
..
.gitkeep [notes][19_hashtable] conflict. 2018-12-01 09:55:45 +08:00
readme.md [19_hashtable] replace all CRLF -> LF. 2018-12-18 17:02:43 +08:00

散列表

核心:散列表的效率并不总是 $O(1)$,仅仅是在理论上能达到 $O(1)$。实际情况中,恶意攻击者可以通过精心构造数据,使得散列表的性能急剧下降。

如何设计一个工业级的散列表?

散列函数

  • 不能过于复杂——避免散列过程耗时
  • 散列函数的结果要尽可能均匀——最小化散列冲突

装载因子过大怎么办

动态扩容。涉及到 rehash效率可能很低。

如何避免低效扩容?

——将 rehash 的步骤,均摊到每一次插入中去:

  • 申请新的空间
  • 不立即使用
  • 每次来了新的数据,往新表插入数据
  • 同时,取出旧表的一个数据,插入新表

解决冲突

开放寻址法,优点:

  • 不需要额外空间
  • 有效利用 CPU 缓存
  • 方便序列化

开放寻址法,缺点:

  • 查找、删除数据时,涉及到 delete 标志,相对麻烦
  • 冲突的代价更高
  • 对装载因子敏感

链表法,优点:

  • 内存利用率较高——链表的优点
  • 对装载因子不敏感

链表法,缺点:

  • 需要额外的空间(保存指针)
  • 对 CPU 缓存不友好

——将链表改造成更高效的数据结构,例如跳表、红黑树

举个栗子JAVA 中的 HashMap

  • 初始大小16
  • 装载因子:超过 0.75 时动态扩容
  • 散列冲突:优化版的链表法(当槽位冲突元素超过 8 时使用红黑树,否则使用链表)