11.4 开放寻址法
11.4-1 考虑用开放寻址法将关键字10,22,31,4,15,28,17,88,59插入到一长度为m = 11的散列表中,辅助散列函数为h’(k) = k。试说明分别用线性探查、二次探查(c1=1,c2=3)和双重散列(h1(k) = k,h2(k) = 1 + (k mod (m - 1)))将这些关键字插入散列表的过程。
线性探查:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
0 mod 11 | 22 | 22 | 22 | 22 | 22 | 22 | 22 | 22 | |
1 mod 11 | 88 | 88 | |||||||
2 mod 11 | |||||||||
3 mod 11 | |||||||||
4 mod 11 | 4 | 4 | 4 | 4 | 4 | 4 | |||
5 mod 11 | 15 | 15 | 15 | 15 | 15 | ||||
6 mod 11 | 28 | 28 | 28 | 28 | |||||
7 mod 11 | 17 | 17 | 17 | ||||||
8 mod 11 | 59 | ||||||||
9 mod 11 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | ||
10 mod 11 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 |
二次探查:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
0 mod 11 | 22 | 22 | 22 | 22 | 22 | 22 | 22 | 22 | |
1 mod 11 | |||||||||
2 mod 11 | 88 | 88 | |||||||
3 mod 11 | 17 | 17 | 17 | ||||||
4 mod 11 | 4 | 4 | 4 | 4 | 4 | 4 | |||
5 mod 11 | |||||||||
6 mod 11 | 28 | 28 | 28 | 28 | |||||
7 mod 11 | 59 | ||||||||
8 mod 11 | 15 | 15 | 15 | 15 | 15 | ||||
9 mod 11 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | ||
10 mod 11 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 |
双重散列:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
0 mod 11 | 22 | 22 | 22 | 22 | 22 | 22 | 22 | 22 | |
1 mod 11 | |||||||||
2 mod 11 | 59 | ||||||||
3 mod 11 | 17 | 17 | 17 | ||||||
4 mod 11 | 4 | 4 | 4 | 4 | 4 | 4 | |||
5 mod 11 | 15 | 15 | 15 | 15 | 15 | ||||
6 mod 11 | 28 | 28 | 28 | 28 | |||||
7 mod 11 | 88 | 88 | |||||||
8 mod 11 | |||||||||
9 mod 11 | 31 | 31 | 31 | 31 | 31 | 31 | 31 | ||
10 mod 11 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 |
11.4-2 试写出HASH-DELETE的伪代码;修改HASH-INSERT,使之能处理特殊值DELETED。
HASH-REMOVE(T, k)
pos := HashSearch(T, k)
if pos != NULL
T[pos] := DEL
return pos
HASH-INSERT(T, k)
i = 0
repeat
j = h(k, i)
if T[j] == NIL or T[j] == DEL
T[j] = k
return j
else i = i + 1
until i == m
return "overflow"
11.4-3 考虑一个采用均匀散列的开放寻址散列表。当装载因子为3/4和7/8时,试分别给出一次不成功查找和一次成功查找的探查期望数上界。
α=3/4:
不成功:1 / (1−3/4) = 4 次
成功:1 / (3/4)* ln (1/(1−3/4)) ≈ 1.848次
α=7/8:
不成功:1 / (1−7/8) = 8 次
成功:1 / (7/8)* ln (1/(1−7/8)) ≈ 2.377次
11.4-4 假设采用双重散列来解决冲突,即所有的散列函数为h(k,i) = (h1(k) + i * h2(k)) mod m。试证明:如果对某个关键字k,m和h2(k)有最大公约数d >= 1,则在对关键字k的一次不成功查找中,在返回槽h1(k)之前,要检查散列表中第(1/d)个元素。于是,当d = 1时,m与h2(k)互素,查找操作可能要检查整个散列表。
哈希冲突的处理方式: 当插入一个关键字时,如果发生哈希冲突,就意味着两个关键字被映射到了同一个槽位。为了解决这个问题,我们使用了双重散列,即尝试将关键字插入到下一个可能的槽位。
最大公约数 d 的作用: 如果哈希表的大小 m 和 h2(k) 有一个大于等于1的最大公约数 d,那么在查找时,我们不仅仅需要考虑 h1(k) 的位置,还需要检查哈希表中的另一个位置。
为什么要检查另一个位置: 这是因为在双重散列中,我们通过累加h2(k) 来寻找下一个可能的槽位。当 d>1 时,这个累加可能会导致我们错过一个本应插入的位置。因此,我们在查找过程中需要额外检查哈希表中的一个位置,以确保没有漏掉可能的插入位置。
特殊情况 d=1: 当 d=1 时,也就是说,哈希表的大小 m 与 h2(k) 互素(没有公约数),我们可能需要检查整个哈希表。这是因为在这种情况下,我们无法通过简单的检查一个特定位置来确保不会错过插入位置,所以可能需要遍历整个哈希表。
在这个问题中,我们考虑了h2(k) = d*c1,其中 m和h2(k)有最大公约数d,m = d*c2
假设 d>1,即 m 与 h2(k) 有公约数。
m = d*c2
h2(k) = d*c1
在探测 1/d 的表项时,即 i = d/m,我们有:
h(k,m/d)=(h1(k) + m/d * h2(k)) mod m
h(k,m/d)=(h1(k) + m/d * d * c1) mod (d * c2)
简化后:
h(k,m/d)=(h1(k)+ m * c1) mod (d * c2)
由于 m=d*c2,我们得到:
h(k,m/d)=(h1(k)+ d * c2 * c1) mod (d * c2)
这里我们可以看到d * c2 * c1是d*c2的倍数,所以有:
h(k,m/d)=h1(k) mod m
在探测了 1/d 的表项之后,我们实际上检查的表项等同于h1(k) 对 m 取模后的结果。这确保了我们不会错过可能的插入位置,因为在双重散列的过程中,我们通过累加 h2(k) 来寻找下一个可能的槽位。在这个特定的情况下,我们通过检查1/d 的表项,确保了在h2(k) 的整数倍上进行探测。
11.4-5 考虑一个装载因子为α的开放寻址散列表。找出一个非零的α值,使得一次不成功查找的探查期望数是一次成功查找的探查期望数的2倍。这两个探查期望数可以使用定理11.6和定理11.8中给定的上界。
1 / (1 - α) = 2 * 1 / α* ln(1/(1-α))
α=0.71533