第11章 散列表
11.1 直接寻址表
我们用一个数组,记为T[0..m-1]。其中每一个位置。或称为槽,对应全域U中的一个关键字。
缺点:如果全域U很大,计算机要存储大小为|U|的一张表T不太可能。其次,实际存储的关键字集合K相对U来说可能很小,使得分配给T的大部分空间都将浪费掉。
11.2 散列表
在散列方式下,该元素放在槽 h(k) 中,即利用散列函数h,由关键字k计算出槽的位置。
11.3 散列函数
1、除法散列表
h(k)=k mod m
m不应为2的幂,最好取一个不太接近2的整数幂的素数
2、乘法散列表
h(k)=⌊m(kA mod 1)⌋
其中
A(0<A<1)
,
kA mod 1
是取kA的小数部分。m一般取2的某个幂次。
11.4 冲突
冲突:两个关键字映射到同一个槽。以下有两种方法解决冲突。
1、链接法
把散列到同一槽中的所有元素都放在一个链表中。
装载因子:
α=n/m
定理11.1:在简单均匀散列的假设下,对于用链接法解决冲突的散列表,一次不成功查找的平均时间为
Θ(1+α)
2、开放寻址法
在开放寻址法中,所有的元素都存放在散列表中。该方法导致的一个结果便是装载因子
α
绝对不会超过1。
有三种技术常用来计算开放寻址法中的探查序列:
- 线性探查: h(k,i)=(h′(k)+i)mod m ,先查找对应的槽,然后一直往后查找直到找到目标值。但存在“一次群集”问题,即连续被占用的槽不断增加。平均查找时间会越来越大。
- 二次探查: h(k,i)=(h′(k)+c1i+c2i2)mod m 。存在“二次群集”问题,即两个关键字的初始探查位置相同,那么它们的探查序列也是相同的。
- 双重散列: h(k,i)=(h1(k)+ih2(k))mod m 。 h2(k) 必须与表的大小m互素,简单取m为2的幂,并设计一个总产生奇数的 h2 ;或取m为素数,并设计一个总是返回较m小的正整数的 h2 。