一、构造哈希表的几种方法
1.1 直接定址法
f(key) = a × key + b
1.2 除留余数法
f( key ) = key mod p ( p ≤ m )
mod是取模(求余数)的意思。事实上,这方法不仅可以对关键字直接取模,也可在折叠、平方取中后再取模。
- 直接定址法(取关键字的某个线性函数为哈希地址)
- 除留取余法(取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址)
- 平方取中法
- 折叠法
- 随机数法
- 数学分析法
常用方法是 直接定址法 和 除留余数法
二、哈希冲突(碰撞)以及处理
不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。任意的散列函数都不能避免产生冲突。
2.1 开发定址法
所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。主要有以下几种:
2.1.1 线性探测法
f ( k e y ) = ( f ( k e y ) + d i ) M O D m ( d i = 1 , 2 , 3 , . . . . . . , m − 1 ) f(key) = (f(key)+di) MOD m (di=1,2,3,......,m-1) f(key)=(f(key)+di)MODm(di=1,2,3,......,m−1)
用开放定址法解决冲突的做法是:当冲突发生时,使用某种探测技术在散列表中形成一个探测序列。沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。查找时探测到开放的地址则表明表中无待查的关键字,即查找失败。
2.1.2 二次探测法
f ( k e y ) = ( f ( k e y ) + d i ) M O D m ( d i = 1 2 , − 1 2 , 2 2 , − 2 2 , … … , q 2 , − q 2 , q < = m / 2 ) f(key) = (f(key)+di) MOD m (di = 1^2, -1^2, 2^2, -2^2,……, q^2, -q^2, q <= m/2) f(key)=(f(key)+di)MODm(di=12,−12,22,−22,……,q2,−q2,q<=m/2)
注:1^2 表示是 1的平方
即:
key1:hash(key)+0
key2:hash(key)+1^2
key3:hash(key)+2^2
设哈希表长m=14,哈希函数 H ( k e y ) = k e y % 11 H(key)=key%11 H(key)=key%11。表中已有4个结点:addr(15)=4,addr(38)=5,addr(61)=6,addr(84)=7,其余地址为空。如果用二次探测再散列处理冲突,关键字为49的结点的地址是?
因为 f(49) = 5 与 f(38) 冲突
所以需要采用二次探测再散列来处理冲突
(f(49) + di) MOD 14(哈希表长m=14)
第一次 di = 1^2
(5 + 1)MOD 14 = 6 与addr(61)=6冲突
第二次 di = -1^2
(5 - 1)MOD 14 = 4 与addr(15)=4 冲突
第三次 di = 2^2
(5 + 4)MOD 14 = 9 没有冲突
所以 addr(49)=9
此方法有如下几条定律:
H
a
s
h
(
i
)
=
H
a
s
h
(
0
)
+
i
2
Hash(i) = Hash(0) + i^2
Hash(i)=Hash(0)+i2
H
a
s
h
(
i
)
=
H
a
s
h
(
0
)
+
(
i
−
1
)
2
Hash(i) = Hash(0) + (i-1)^2
Hash(i)=Hash(0)+(i−1)2
H
a
s
h
(
i
)
=
H
a
s
h
(
i
−
1
)
+
(
2
i
−
i
)
Hash(i) = Hash(i-1) + (2i-i)
Hash(i)=Hash(i−1)+(2i−i)
2.2 链地址法
前面我们谈到了散列冲突处理的开放定址法,它的思路就是一旦发生了冲突,就去寻找下一个空的散列地址。那么,有冲突就非要换地方呢,我们直接就在原地处理行不行呢?
答案是可以的,就是链地址法,就好比Java里的HashMap的数据结构一样。
参考链接:
https://www.jianshu.com/p/585f8882bbfb
https://blog.csdn.net/xyzbaihaiping/article/details/51607770