一、
什么是哈希表?
以上两节讨论的表示查找表的各种
结构
的共同
特点
:
记录在表中的位置和它的
关键字之间不存在一个确定的关系,
查找的过程
为给定值依次和关键字集合
中各个关键字进行
比较
,
查找的效率
取决于和给定值
进行比较
的关键
字个数。
用这类方法表示的查找表,
其平均查找
长度都不为零。
不同的表示方法,其差别仅在于:
关键字和给定值进行比较的顺序不同
。
但是,对于
动态查找表
而言,
1)
表长不确定;
2)
在设计查找表时,只知道关键字所属范围,而
不知道确切的关键字。
因此在一般情况下,需在关键字与记录在表中的
存储位置之间建立一个
函数关系
,使每个关键码
与结构中一个唯一存储位置相对应
.
以 f(key) 作
为关键字为 key 的记录在表中的位置
,
通常
称
这
个函数
f(key) 为哈希函数
。
Address
=
f
(
key
)
1)
哈希函数是一个
映象
,即:
将关键字的集合映射到某个地址集合
上,
它的设置很灵活,只要这个地址集
合的
大小不超出允许范围即可;
(
由于哈希函数是一个
压缩映象
,因此,
在一般情况下,很容易产生
“
冲突
”
现
象,
即:
key1
¹
key2
,而
f(key1) = f(key2)
。
3)
很难
找到一个不产生冲突的哈希函数。
一般情况下,
只能选择恰当的哈希函数,
使冲突尽可能少地产生。
因此,在构造这种特殊的“查找表”
时,除了需要选择一个
“好”(尽可能
少产生冲突)的哈希函数之外;还需要
找到
一种
“处理冲突”
的方法。
哈希表的定义:
根据设定的
哈希函数
H(key)
和所选中的
处
理冲突的方法
,将一组关键字
映象到
一个有
限的、地址连续的地址集
(
区间
)
上,并以关
键字在地址集中的
“
象
”
作为相应记录在表中
的
存储位置
,如此构造所得的查找表称之为
“
哈希表
”
。
二、
构造哈希函数的方法
对
数字
的关键字可有下列构造方法:
1.
直接定址法
5.
除留余数法
1.
直接定址法
哈希函数为关键字的线性函数
H(key) = key 或者
H(key) = a ´ key + b
这类散列函数是一对一的映射,对于不同的关键字一定不会产生冲突。但是,它要求
地址集合的大小
= =
关键字集合的大小
5. 除留余数法
设定哈希函数为
:
H(key) = key MOD p
(%
、
取余
)
其中
,
p≤m (表长) 并且
p 应为素数
或是
不含 20 以下的质因子
为什么要对 p 加限制?
例如:
给定一组关键字为:
12, 39, 18, 24, 33, 21
,
若取
p=9,
则他们对应的哈希函数值将为:
3,
3, 0, 6, 6, 3
可见,若
p
中含质因子
3
,
则所有含质因子
3
的关键字均映射到
“
3
的倍数
”
的地址上
,
从而增加了
“
冲突
”
的可能。
三、
处理冲突的方法
1.
开放定址法
2.
链地址法
1.
开放定址法
为产生冲突的地址
H(key)
求得一个
地址序列(多次尝试的过程):
H0, H1, H2, …, Hs
1
≤
s
≤
m-1
其中:
H
0
= H(key)
H
i
= ( H(key) +
d
i
) MOD m
i=1, 2, …, s
对
增量
di
有三种取法:
•1)
线性探测再散列
di = c´ i 最简单的情况 c=1
di = c´ i 最简单的情况 c=1
•2)
平方探测再散列
di = 12, -12, 22, -22, …,
di = 12, -12, 22, -22, …,
•
3
)
随机探测再散列
d i 是一组 伪随机数列 或者
d i 是一组 伪随机数列 或者
•
d
i
=i
×
H
2
(key)
(
又称双散列函数探测
)
例如
:
关键字集合
{
19, 01, 23, 14, 55, 68, 11, 82, 36 }
设定
哈希函数
H(key) = key
MOD
11 (
表长
=11 )
若采用
线性探测再散列
处理冲突
四、
哈希表的查找
查找过程和造表过程一致。假设采用开
放定址处理冲突,则
查找过程
为:
对于
给定值
K
,
计算
哈希地址
i = H(K)
若 r[i] = NULL 则查找不成功
若 r[i].key = K 则查找成功
否则
“
求下一地址
Hi
”
,直至
r[Hi] = NULL
(
查找不成功
)
或
r[Hi].key = K
(
查找成功
)
为止。
哈希表查找的分析:
从查找过程得知,哈希表查找的平均查找长
度实际上并不等于零。
决定哈希表查找的
ASL
的因素:
•
1
)
选用的
哈希函数
;
•
2
)
选用的
处理冲突的方法
;
•
3
)
哈希表饱和的程度,称为
装载因子
α
=n/m
值的
大小
(
n
—
记录数,
m
—
表的长度)
可以证明:查找成功时有下列结果:
线性探测再散列
从以上结果可见:
•
散列表的装填因子
a
表明了表中的装满程度。越大,说明表越满,再插入新元素时发生冲突的可能性就越大。
•
哈希表的平均查找长度是
a
的函数
,而不是
n
的函数,即平均搜索长度依赖于散列表的装填因子,不直接依赖于
n
或
m
。
•
不论表的长度有多大,我们总能选择一个合适的装填因子,以把平均搜索长度限制在一定范围内。