散列表概念

本文详细介绍了散列表的概念,包括直接寻址表和散列表的构造。在散列表中,通过散列函数解决冲突是关键,文章讨论了链接法、散列法(除法、乘法和全域散列法)以及开放寻址法(线性、二次和双重散列)。完全散列提供了一种在最坏情况下查找时间复杂度为O(1)的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@散列表

hashtable,关键问题在于查找的时间优化和解决冲突。

1. 直接寻址表

index和key值直接相关,存储全域U

2. 散列表

即利用散列函数h由关键字k计算出槽的位置,采用函数h将全域U映射到散列表的槽位上。散列,顾名思义,希望h尽可能随机混杂,最大程度减少冲突。但由于h(k)的种数m<U, 所以一定会有冲突的情况产生。

2.1 解决冲突的方法
2.1.1 链接法

在链接法中,把散列到同一槽的所有元素都放在一个链表中。槽j中有一个指针,指向存储所有到j的元素的表头。其性能主要取决于散列函数。好的散列函数应满足简单均匀散列假设,即每个关键字都被等可能的散列到m个槽位中的任何一个。

2.2 散列法
2.2.1 除法散列法

h ( k ) = k   m o d   m , h(k)=k\ mod\ m, h(k)=k mod m,
其中 m m m应取一些不太接近2的整数幂的素数

2.2.2 乘法散列法

h ( k ) = f l o o r ( m ( k A   m o d   1 ) ) , h(k) = floor(m(kA\ mod\ 1)), h(k)=floor(m(kA mod 1)),
其中 f l o o r ( ⋅ ) floor(\cdot) floor()表示向下取整,先用k乘上常数A(0<A<1),提取小数部分,再乘上m,向下取整。m一般取2的幂次,比较好实现。而A有文献表明取 ( 5 − 1 ) / 2 (\sqrt{5}-1)/2 (5 1)/2是个比较好的值。

2.2.3 全域散列法

某些情况下,对于一个特定的散列函数,还是会出现关键字全部散列到一个槽中。为改善这一情况,可采用随机选择散列函数,使函数的性质和选择的关键字保持较好的独立性,这称为全域散列。设计一个全域散列函数类比较容易,常见的有
h a b ( k ) = ( ( a k + b )   m o d   p )   m o d   m h_{ab}(k) = ((ak+b)\ mod\ p)\ mod\ m hab(k)=((ak+b) mod p) mod m
其中a有p-1种选择,b有p种选择。

2.3 开放寻址法

在开放寻址法种,所有的元素都存放在散列表里。为使用开放寻址法插入一个元素,需要连续的检查散列表,找到适合的空位,这称为探查,其依赖于待插入的关键字。此时散列函数改为
h : U × { 0 , 1 , … , m − 1 } ↦ { 0 , 1 , … , m − 1 } . h: U\times \{ 0,1,\ldots,m-1 \} \mapsto \{0,1,\ldots,m-1\}. h:U×{0,1,,m1}{0,1,,m1}.
如果位置是空的,就用,否则将会继续向前找。注意这种方法可能会出现散列表满的情况。

找的时候也类似。但注意到这种情况,删除不方便,所以要考虑删除的话,还是会用链接法来解决冲突。

下面介绍一些探查法,以接近均匀散列的假设。但只是接近而已,双重散列的效果似乎是最好的。

2.3.1 线性探查

先假设一个普通的散列函数h’, 称之为辅助散列函数。线性探查采用的散列函数为:
h ( k , i ) = ( h ′ ( k , i ) + i )   m o d   m , i = 0 , 1 , … , m − 1. h(k,i) = (h'(k,i)+i)\ mod\ m, i=0,1,\ldots, m-1. h(k,i)=(h(k,i)+i) mod m,i=0,1,,m1.
给定一个关键字k,首先探查槽T[h’(k)],然后是T[h’(k)+1],…,一直到T[m-1]。随后返回T[0], T[1],…,一直到T[h’(k)-1]。有m种不同的探查序列。这个方法比较容易,但易出现一次群集的问题,即连续占用的槽越来越长,带来性能下降。

2.3.2 二次探查

h ( k , i ) = ( h ′ ( k ) + c 1 i + c 2 i 2 )   m o d   m , i = 0 , 1 , … , m − 1. h(k,i) = (h'(k)+c_1i+c_2i^2)\ mod\ m, i=0,1,\ldots, m-1. h(k,i)=(h(k)+c1i+c2i2) mod m,i=0,1,,m1.
群集现象轻,二次群集。为充分利用散列表, c 1 , c 2 , m c_1,c_2,m c1,c2,m值有限制。

2.3.3 双重散列

双重散列是用于开放寻址法的最好方法之一。其散列函数形式为
h ( k , i ) = ( h 1 ( k ) + i h 2 ( k ) )   m o d   m , i = 0 , 1 , … , m − 1. h(k,i) = (h_1(k)+ih_2(k))\ mod\ m, i=0,1,\ldots, m-1. h(k,i)=(h1(k)+ih2(k)) mod m,i=0,1,,m1.
这里 h 2 ( k ) h_2(k) h2(k)必须要与表的大小m互素,取m为2的幂,并设计一个总产生奇数的 h 2 h_2 h2就可以。

2.4 完全散列

使用完全散列进行查找时,能在最坏情况下用O(1)次访存完成。例如可设计两级散列方案,每级上都使用全域散列。为确保二次散列表不冲突,需此二次散列表 S j S_j Sj的大小 m j m_j mj为散列在槽 j j j中的关键字 n j n_j nj的平方。通过适当选择第一级散列函数,可以使总体存储空间限制为 O ( n ) O(n) O(n).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值