算法图解-散列表

1. 散列表

  • 散列表由键和值组成,散列表将键映射到值。
  • 在复杂数据结构中,散列表可能是最有用的,也被称为散列映射、映射、字典和关联数组。散列表的速度很快!还记得数组和链表的讨论吗?你可以立即获取数组中的元素,而散列表也使用数组来存储数据,因此其获取元素的速度与数组一样快。
  • 你可能根本不需要自己去实现散列表,任一优秀的语言都提供了散列表实现。Python提供的散列表实现为字典,你可使用函数dict来创建散列表。

2. 应用
散列表适合用于:

  • 模拟映射关系;
  • 防止重复;
  • 缓存/记住数据,以免服务器再通过处理来生成它们。

3. 处理冲突
最简单的办法: 如果两个键映射到了同一个位置,就在这个位置存储一个链表。

4. 性能

  • 在平均情况下,散列表执行各种操作的时间都为O(1)。O(1)被称为常量时间。你以前没有见过常量时间,它并不意味着马上,而是说不管散列表多大,所需的时间都相同。
  • 在最糟情况下,散列表所有操作的运行时间都为O(n)——线性时间这真的很慢。我们来将散列表同数组和链表比较一下。
    算法图解-散列表_第1张图片
    4-1
  • 在平均情况下,散列表的查找(获取给定索引处的值)速度与数组一样快,而插入和删除速度与链表一样快,因此它兼具两者的优点!但在最糟情况下,散列表的各种操作的速度都很慢。
    因此,在使用散列表时,避开最糟情况至关重要。为此,需要避免冲突。而要避免冲突,需要有:
    1.较低的填装因子;
    2.良好的散列函数。

5. 装填因子
散列表的填装因子很容易计算。

算法图解-散列表_第2张图片
5-1

算法图解-散列表_第3张图片
5-2

算法图解-散列表_第4张图片
5-3

算法图解-散列表_第5张图片
5-4

这个新散列表的填装因子为3/8,比原来低多了!填装因子越低,发生冲突的可能性越小,散列表的性能越高。一个不错的经验规则是:一旦填装因子大于0.7,就调整散列表的长度。
你可能在想,调整散列表长度的工作需要很长时间!你说得没错,调整长度的开销很大,因此你不会希望频繁地这样做。但平均而言,即便考虑到调整长度所需的时间,散列表操作所需的时间也为O(1)。

6. 散列函数

  • 良好的散列函数让数组中的值呈均匀分布。


    算法图解-散列表_第6张图片
    6-1
  • 糟糕的散列函数让值扎堆,导致大量的冲突。


    算法图解-散列表_第7张图片
    6-2

小结

  1. 你可以结合散列函数和数组来创建散列表。
  2. 冲突很糟糕,你应使用可以最大限度减少冲突的散列函数。
  3. 散列表的查找、插入和删除速度都非常快。
  4. 散列表适合用于模拟映射关系。
  5. 一旦填装因子超过0.7,就该调整散列表的长度。
  6. 散列表可用于缓存数据(例如,在Web服务器上)。
  7. 散列表非常适合用于防止重复。

你可能感兴趣的:(算法图解-散列表)