哈希表概述

哈希表

1. 定义

散列存储即在存储位置和存储内容之间建立一个对应关系f,使得存储位置 = f (key),这个f 即被称为哈希(Hash)函数,又称散列函数,采用这种存储方式将记录存储在一块连续的存储空间中,这块空间即称为哈希表(Hash table)散列表,关键字对应的记录位置称为散列地址

2. 哈希函数的构造方法

冲突:当 k e y 1 ≠ k e y 2 \sf key1\not =key2 key1=key2,但 f ( k e y 1 ) = f ( k e y 2 ) \sf f(key1) = f(key2) f(key1)=f(key2)时,即为发生了冲突,所以在设计哈希函数时要使这种情况尽可能地少。

  • 直接定址法

f(key)   =   a*key+b \colorbox{#D2E4EF}{\sf{f(key) = a*key+b}} f(key) = a*key+b

  • 数字分析法

适用于关键字位数较大,且分布比较均匀时(例如电话号码),可以抽取关键字中的一部分(例如后四位)用于计算散列地址

  • 平方取中法

适用于不知道关键字分布,重复频率又比较高的情况,例如若key = 1234,而12342 = 1522756,则取中间3为227为散列地址

  • 折叠法

适用于关键字位数较大,且不知道分布时,可以将关键字分为相等的几部分,作和并按哈希表表长取后几位为散列地址。

  • 除留取余法(常用

对于哈希表长为m的散列函数公式为
f(key)=key   mod    p      (p  < =   m) \colorbox{#D2E4EF}{\sf f(key)=key\ mod\ p\ \ \ \ (p <= m)} f(key)=key mod  p    (p <= m)
为了尽量减少冲突,使p为小于或等于表长m的最小质数或不包含小于20质因子的合数

  • 随机数法

适用于关键字长度不等的情况
f(key)=random(key) \colorbox{#D2E4EF}{\sf{}f(key)=random(key)} f(key)=random(key)

3. 处理冲突的方法

1)开放定址法
  • 线性探测法:一旦发生冲突,就去找下一个地址,直到找到空位为止。公式:

f i ( k e y ) = ( f ( k e y ) + d i ) m o d    m      ( d i = 1 , 2 , 3 , … , m − 1 ) \sf{}f_i(key)=(f(key)+d_i)\mod m\ \ \ \ (d_i=1,2,3,…,m-1) fi(key)=(f(key)+di)modm    (di=1,2,3,,m1)

例如若关键字集合为{12,67,56,16,25,37,22,29,15,47,48,34},我们使 f ( k e y ) = k e y   m o d   12 \sf f(key)=key\ mod\ 12 f(key)=key mod 12,在存储前5个数时都没有产生冲突,如表

下标01234567891011
关键字1225166756

但是当key = 37时,37 mod 12 = 1,与25所在的位置冲突,于是我们用上面的公式, f ( 37 ) = ( f ( 37 ) + 1 )   m o d   12 = 2 \sf{}f(37)=(f(37)+1)\ mod\ 12=2 f(37)=(f(37)+1) mod 12=2,所以将37存入下标为2的位置。

下标01234567891011
关键字122537166756

接下来22, 29, 15, 47都没有冲突

下标01234567891011
关键字12253715162967562247

当key = 48时, f ( 48 ) = 0 \sf{}f(48)=0 f(48)=0,与12所在位置冲突,则 f ( 48 ) = ( f ( 48 ) + 1 )   m o d   12 = 1 \sf{}f(48)=(f(48)+1)\ mod\ 12=1 f(48)=(f(48)+1) mod 12=1,又与25所在位置冲突,继续 f ( 48 ) = ( f ( 48 ) + 2 )   m o d   12 = 2 \sf{}f(48)=(f(48)+2)\ mod\ 12=2 f(48)=(f(48)+2) mod 12=2,还是与37所在位置冲突…这样直到 f ( 48 ) = ( f ( 48 ) + 6 )   m o d   12 = 6 \sf{}f(48)=(f(48)+6)\ mod\ 12=6 f(48)=(f(48)+6) mod 12=6,才不再冲突,存入下标为6的位置。

下标01234567891011
关键字1225371516294867562247

这种解决冲突的开放定址法称为线性探测法。而48本来和37不是同义词,但却需要争夺同一个地址,这种现象称为堆积

  • 二次探测法

增加平方运算使得关键字不会聚集在某一块区域,并且双向寻找可能的空位置,公式:

f i ( k e y ) = ( f ( k e y ) + d i ) m o d    m      ( d i = 1 2 , − ( 1 2 ) , 2 , − ( 2 2 ) , … , q 2 , − ( q 2 ) , q ≤ m / 2 \sf{}f_i(key)=(f(key)+d_i)\mod m\ \ \ \ (d_i=1^2,-(1^2),2,-(2^2),…,q^2,-(q^2),q\le m/2 fi(key)=(f(key)+di)modm    (di=12,(12),2,(22),,q2,(q2),qm/2

  • 随机探测法
    令di为一组伪随机数列
2)再散列法

f i ( k e y ) = R H i ( k e y )      ( i = 1 , 2 , … k ) \sf{}f_i(key)=RH_i(key)\ \ \ \ (i=1,2,…k) fi(key)=RHi(key)    (i=1,2,k)

即事先准备多个散列函数,如果发生冲突就替换至RHI

3)链地址法

我们可以先将所有同义词存在同一个单链表中,即为同义词子表,然后在哈希表中存储所有同义词子表的头指针即可。
链地址法

4)公共溢出区法

将所有有冲突的关键字存储在溢出区内,在查找使先在基本表中查,如果查不到再顺序查找溢出区,适用于冲突较少的情况。
在这里插入图片描述

4. 性能分析

影响平均查找长度的因素:
如果没有冲突,散列查找的时间复杂度为O(1)

  1. 散列函数是否均匀
    但不同的散列函数对同一组随机的关键字,产生冲突的可能性时相同的,因此我们可以不考虑它对平均查找长度的影响。
  2. 处理冲突的方法
    线性探测法处理冲突时产生堆积的可能性就比二次探测法要大,而链地址法不会产生任何堆积,因而具有更加的平均查找性能。
  3. 装填因子 α \alpha α
    α = \sf{}\alpha= α= 填入表中的记录个数/散列表长度,标志着散列表的装满程度, α \alpha α越大,产生冲突的可能性越大。例如散列表长度为12,填入的关键字个数为11,那么此时 α = 11 / 12 = 0.9167 \sf\alpha=11/12=0.9167 α=11/12=0.9167,那么填入最后一个关键字时产生冲突的可能性就非常大了。

来源:《大话数据结构》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值