第十一章 散列表
总结:这一章讲了直接寻址表和散列表,并介绍了一些散列函数等。
1. 直接寻址表
直接将关键字作为数组下标。复杂度O(1)
2. 散列表
k->h(k)
降低了空间开销,会产生碰撞,解决碰撞的简单方法是链接法。
对链接法散列,平均情况下,复杂度也是O(1)
3. 散列函数
1) 除法散列法
h(k)=k mod m,m最好选取与2的整数幂不太接近的质数
2) 乘法散列法
h(k)=[m(kA mod 1)], A为一个常数(0<A<1)。
乘法方法的优点是对m的选择没有什么特别的要求,一般选择它为2的某个幂次。
3) 全域散列
随机的选择散列函数
从一组散列函数中随机地选择一个散列函数,当(k!=l)时,两者发生碰撞的概率不大于1/m,这样的函数组称为全域的。
4. 开放寻址法
开放寻址法指所有的元素都存放在散列表里。
在开放寻址法里,当要插入一个元素时,可以连续地检查散列表的各项,直到遇到一个空槽存放待插入的关键字。对每一个关键字k,探查序列<h(k,0),h(k,1),…h(k,m-1)>必须是<0,1,..,m-1>的一个排列。
伪代码
HASH-INSERT(T,k)
i <- 0
repeat j <- h(k,i)
if T[j] = NIL
then T[j] <- k
return j
else i <- i+1
until i=m
error “hash table overflow”
伪代码
HASH-SEARCH(T,k)
i <- 0
repeat j <- h(k,i)
if T[j] = k
then return j
i <- i+1
until i =m or T[j]=NIL
return NIL
1) 线性探查
h(k,i)=(h’(k)+i) mod m, i=0,1,…,m-1
初始探查位置确定了整个序列,只有m种不同的探查序列。
存在问题,一次群集,即随着时间的推移,连续被占用的槽不断增加,平均查找时间也随着不断增加。
2) 二次探查
h(k,i)=(h’(k)+a*i+b*i^2) mod m
初始探查位置确定了整个序列,只有m种不同的探查序列。
存在问题,程度较轻的群集现象,二次群集
3) 双重散列
h(k,i)=(h1(k)+i*h2(k)) mod m
为能查找整个散列表,h2(k)要与表的大小m互质。
用了O(m^2)种探查序列
5. 完全散列
一种两级的散列方案
每一级上都采用全域散列。
第一级将n个关键字散列到m个槽中,每个槽j中有一个较小的二次散列表Sj。通过仔细的选择第二级散列函数,可以确保在第二级上不出现碰撞。
期望使用的总体存储空间为O(n)