首先通过一道例题来引出这篇博客的主旨:
[腾讯]已知一个线性表(38,25,74,63,52,48),假定采用散列函数 h(key)=key%7 计算散列地址,并散列存储在散列表A[0…6]中,若采用线性探测方法解决冲突,则在该散列表上进行等概率成功查找的平均查找长度为多少?
h(key)=key%7 求得哈希地址(存在地址冲突) | 线性探测再散列 当地址冲突时,每次地址+1 [2,3…] 直到找到空位 | 查找长度 |
---|---|---|
38%7=3 | A[3]=38 | 1 |
25%7=4 | A[4]=25 | 1 |
74%7=4 | A[4]=74 –> A[5]=74 | 2 |
63%7=0 | A[0]=63 | 1 |
52%7=3 | A[3]=52 –> A[4]=52 –> A[5]=52 –> A[6]=52 | 4 |
48%7=6 | A[6]=48 –> A[0]=48 –> A[1]=48 | 3 |
总的平均查找长度
=每个元素的查找长度之和
/总的元素个数
,即:(1+1+2+1+4+3)/6=2
处理冲突的方法
通过这道题不难看出,这里涉及了哈希表处理地址冲突的方法:线性探测再散列。下面就处理冲突的几种方法作整理:
1. 开放定址法
H[i]=(H(key)+d[i]) MOD m
其中H(key)为哈希函数;m为哈希表表长;d[i]为增量序列,下面的三种取法对应着三种探测类型:
(1)线性探测再散列:d[i]=1,2,3,…,m-1
(2)二次探测再散列:d[i]=1²,-1²,2²,-2²,3²,…,±k²
(3)随机探测再散列:d[i]=伪随机数序列
总结:用线性探测再散列可以保证做到:只要哈希表未填满,总能找到一个不发生冲突的地址H[k],而二次探测再散列只有在哈希表长m为形如4j+3(j为整数)
的素数时才可能,随机探测再散列,则取决于伪随机数列。
2. 再哈希法
在同义词(计算的hash值相同的记录)产生地址冲突时计算另一个哈希函数地址,直到冲突不再发生。这种方法不易产生”聚集”,但增加了计算的时间。
3. 链地址法
将所有关键字为同义词的记录存储在同一线性表中。在链表中的插入位置可以在表头或表尾;也可以在中间,以保持同义词在同一线性表中按关键字有序
例:已知一组关键字为(19,14,23,01,68,20,84,27,55,11,10,79) 则按哈希函数 H(key)=key MOD 13
和链地址法处理冲突构造所得的哈希表如下:
链表 | 链地址法 |
---|---|
0 | |
1 | –> [01] –> [14] –> [27] –> [79] |
2 | |
3 | –> [55] –> [68] |
4 | |
5 | |
6 | –> [19] –> [84] |
7 | –> [20] |
8 | |
9 | |
10 | –> [10] –> [23] |
11 | –> [11] |
12 |
查找成功时,01,55,19,20,10,11需要一次;14,68,84,23需要两次;27需要三次;79需要四次。
平均成功查找长度为:(6*1+4*2+1*3+1*4)/12=21/12
4. 建立一个公共溢出区
所有关键字和基本表中关键字为同义词的记录,不管它们右哈希函数得到的哈希地址是什么,一旦发生冲突,都填入溢出表。