参考书籍:《算法笔记》
描述: 将元素通过一个函数(hash函数 H)转换为整数,使得该整数可以尽量唯一的代表这个元素。(key
变为 H(key)
)
思想: 用空间换时间
对于key是整数的情况来说,常用的hash函数有直接定址法
、平方取中法
、除留余数法
等。
- 直接定址法:恒等变换:
H(key) = key
,直接把key作为数组下标(最常见实用的)
线性变换:H(key) = a * key+b
- 平方取中法:取key平方的中间若干位作为hash值(很少用)
- 除留余数法:
H(key) = key % mod
把key对一个数取模的值作为hash值,一般取素数作为mod,且与表长TSize相等。
但一定会有两个数的hash值相等,这就是冲突。
解决冲突的方法(1和2重新计算了hash值):
线性探测法
:当得到key的hash值H(key),但表中的下标为H(key)的位置已经被占用了,这时候就检查H(key)+1
是否被占用,如果没有,就使用这个位置;否则就继续检查下一位。如果在检查的过程中超过了表长,就回到表的首位继续循环,知道找到一个可以使用的位置。
缺点: 容易扎堆,即表中连续的若干个位置都被占用,一定程度上影响效率。平方探测法
:为尽量避免扎堆,当表中下标为H(key)的位置被占时,将按以下的顺序检查表中的位置:H(key)+12、H(key)-12、H(key)+22、H(key)-22……
如果在检查的过程中H(key)+k^2^
超过了表长TSize,那么久把H(key)+K^2
对表长TSize取模;
注意:如果想避免负数的麻烦,也可以只做正向的平方探测。可以证明,如果k在[0, TSize)范围内都无法找到位置,那么当k≥TSize时,也一定无法找到位置。链地址法
:把所有的H(key)相同的key连接成一条单链表。这样可以设定一个数组Link,范围是Link[0]~Link[mod],其中Link[h]存放hash值为h的一条单链表,就可以直接把这些冲突的key用单链表连接起来,可以通过遍历这条单链表来寻找所有的hash值为h的key。
注意:可以使用STL中的map
来实现hash的功能(c++11 以后可以使用unordered_map
,速度更快)。