散列函数(散列映射、映射、字典、关联数组)
散列函数是这样的函数,即无论你给它什么数据,它都还你一个数字。即散列函数“将输入映射到数字”,散列函数必须满足一些要求:
- ①它必须是一致的。
- ②它应将不同的输入映射到不同的数字。
以下一个商品价格的图例说明了散列表的结构:
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1.49 | 0.67 | ||||
→milk | →apple |
将商品名称作为输入给散列函数,散列函数给出对应的索引值,将商品对应的价格放入索引值对应的数组位置。为何可以在O(1)的时间复杂度下找到相应的结果,主要得益于以下几点:
- ①散列函数总是将同样的输入映射到相同的索引。
- ②散列函数将不同的输入映射到不同的索引。(
这里实际是一种理想的状态,见下文 冲突 部分
) - ③散列函数知道数组有多大,只返回有效的索引。
散列表
是一种包含额外逻辑的数据结果(散列函数),与数组和链表被直接映射到内存不同。python提供dict{}创建散列表(键值对)。
散列表的应用
- 用于查找(类似手机的电话薄功能、DNS解析等)
- 防止重复(投票等)
- 用于缓存(站点数据访问等)
- 还有更多的列举…
冲突(collision)
给两个键分配的位置相同就是冲突,如何处理?
可取的一个办法是,如果两个键映射到了同一个位置,就在这个位置储存一个链表。糟糕的情况下,就像下面这样子了:
- | - |
---|---|
A | →(apple<>0.67) →(almonds<>0.98) |
B | |
C | |
D |
链表太长,而其它的分配的空间又浪费掉了。因此,散列函数很重要。
性能
在平均情况下,散列表执行各种操作的时间都为O(1),O(1)被称为常量时间。
而要避免上述呈现的最糟的情况,就要避免冲突,那么就需要做好下面两点:
①较低的填装因子
填装因子=散列表包含的元素数 / 位置总数
一个不错的经验规则:当大于0.7
时,就要调整散列表的长度。
②良好的散列函数
扩展:SHA函数1 了解一下。
- SHA家族- 维基百科
(https://zh.wikipedia.org/zh-hans/SHA%E5%AE%B6%E6%97%8F)
python hashlib
(http://www.liujiangblog.com/course/python/58) ↩