散列表(hashing)
常见查找
- 顺序查找,O(N)
- 二分查找 静态查找
- 散列
查找方法:快速搜索到需要的关键词或关键词不方便比较怎么办
散列查找的两个基本工作
- 计算位置
- 解决冲突(collision) 多个关键词同一位置
时间复杂度几乎是常量,查找与问题规模无关,以空间换时间
填装因子(loading factor):设散列表空间大小为m,填入表中元素个数为n,则称 α = n / m \alpha =n/m α=n/m为散列表的填装因子
散列函数构造
好的散列函数
- 计算简单
- 关键字对应的地址空间分布均匀,尽量减少冲突
关键字是数字
- 直接取值
- 取余 ,一般取数组长度,或质数
- 数字组成有一定的规律,如身份证号,取随机的那部分做地址
- 折叠法 ,对较长对数字,截成等长对部分,求和
- 平方取中法,对数字平方后,取中间几位
关键字是字符
- ascII码求和,范围较小
- 利用ascII码,求出数字后,视为较大进制的数(如使用27进制,一共有26个字母),再转回十进制,取余。
- 可以使用32进制,等价与左移5位。每读一位,左移,再加下一位
char key[];
int i,count=0;
while(*key !='\0'){
count = count <<5 +*key;
key++;
}
处理冲突
开放地址法 open adress(换一个地址)
发生冲突,按某种规则再找地址。
发生了第i次冲突后,试探下一个地址
h
i
(
k
e
y
)
=
(
h
(
k
e
y
)
+
d
i
)
m
o
d
T
a
b
l
e
S
i
z
e
h_i(key)=(h(key)+d_i)mod TableSize
hi(key)=(h(key)+di)modTableSize
常见的方法(
d
i
d_i
di不同)
- 线性探测 d i = i d_i=i di=i,易聚集
- 平方探测
d
i
=
+
‾
i
2
d_i ={ \underline+ }i^2
di=+i2
2.1.若散列长度为4k+3形式的质数(k为正整数),平方探测可以探测整个散列空间
2.2 若 d i = + ‾ i 2 d_i ={ \underline+ }i^2 di=+i2找不到空位,则 d i = i 2 d_i =i^2 di=i2也找不到空位 - 双散列
d
i
=
i
∗
h
2
(
k
e
y
)
d_i=i*h_2(key)
di=i∗h2(key)
3.1 对任意key h 2 ( k e y ) ! = 0 h_2(key)!=0 h2(key)!=0
3.2 应该保证所有散列单元都能被探测到,可以选择 h 2 ( k e y ) = p − ( k e y m o d p ) h_2(key)=p-(key mod p) h2(key)=p−(keymodp)
懒惰删除:开放地址删除时,不能删除,只能标记,否则回断链,使部分元素找不到
再散列 Rehashing
当元素太多时,散列当效率回下降
一般
0.5
≤
α
≤
0.85
0.5 \leq \alpha \leq 0.85
0.5≤α≤0.85
当装载因子太大时,需要扩容,这个过程叫再散列
链地址法 (不改变地址)
将所有冲突的元素放在同一个链表上
装填因子
α
\alpha
α:所有地址链表的平均长度定义称装填因子
散列表性能分析
关键指标
- 成功平均查找长度(ASLs),冲突次数加一
- 不成功平均查找长度(ASLu) ,将不再散列表中的元素分类(如按h(key)的值分类)
影响产生冲突的因素:
- 散列是否均匀
- 处理冲突的方法
- 装填因子$\alpha $
应用:统计文本单词
reference
浙大 数据结构 mooc https://www.icourse163.org/course/ZJU-93001