对哈希函数的构造和冲突处理方法的理解

哈希函数

哈希函数是从关键字集合到地址集合的映射。这一映射过程称为哈希造表或散列,所得存储位置为哈希地址或散列地址。

哈希函数的构造方法

1.1直接定址法

取关键字或关键字的某个线性函数值为哈希地址。即:

H(key)=key或H(key)=a*key+b  (其中a和b为常数。)

由于直接定址所得地址集合和关键字集合的大小相同。因此,对于不同的关键字不会发生冲突。实际中使用这种哈希函数的情况很少。

1.2数字分析法

将设关键字是以r为基的数(如:以10为基的十进制数),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。

1.3平方取中法

取关键字平方后的中间几位为哈希地址。这是一种较常用的构造哈希函数方法。(通常在选定哈希函数时不一定能知道关键字的全部情况,取其中那几位也不一定合适,而一个数平方后的中间几位数和数的每一位都相关,由此使随机分布的关键字得到的哈希地址也是随机的。取的位数由表长决定)

1.4折叠法

将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。关键字位数很多,而且关键字中每一位上的数字分布大致均匀时,可以采用折叠法得到哈希地址。在折叠法中数位叠加可以有移位叠加和间界叠加两种方法。

1.5除留余数法

取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。即:

H(key)=key MOD p,  p<=m

这是一种最简单,也是最常用的构造哈希函数的方法。他不仅可以对关键字直接取模(mod),也可以在折叠,平方取中等运算后取模。使用除留余数法时,对p的选择很重要,若p选择不好容易产生同义词。

1.6随机数法

选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),其中random为随机函数。通常,当关键字长度不等时采用此方法构造哈希函数较恰当。

总结:

实际工作中不同情况需要采用不同的哈希函数,通常,考虑的因素有:

(1)计算哈希函数所需时间(包括硬件指令因素);

(2)关键字的长度。

(3)哈希表的大小。

(4)关键字的分布情况。

(5)记录的查找频率。

处理冲突的方法

将设哈希表的地址集为0~(n-1),冲突是指由关键字得到的哈希地址为j(0<=j<=n-1)的位置上已存有记录,则处理冲突就是为该关键字的记录找到另一个空的哈希地址。在处理冲突的过程中可能得到一个地址序列Hi i=1,2,.....k,(Hi属于[0,n-1])即在处理哈希地址的冲突时,若得到的另外一个哈希地址H1仍然发生冲突,则求下一个地址H2。若H2仍冲突,则求H3.一次类推。直至Hk不发生冲突为止,则HK为记录在哈希表中的地址。常用的方法有:

  1. 开放定址法

Hi=(H(key)+di)MODm  i=1,2,...,k(k<=m-1) 其中:H(key)为哈希函数,m为哈希表表长;di为增量序列,可由下列三种取法:

A.di=1,2,3,...m-1称线性探测再散列

B.di=12,-12,22,-22,...,+_k2(k<=m/2)称二次探测在散列

C.di=伪随机数序列,称伪随机探测在散列。

(引入二次聚集,在处理同义词的冲突过程中又添加了非同义词的冲突,这种现象对查找不利)

用线性探测再散列处理冲突可以保证做到:只要哈希表未填满,总能找到一个不发生冲突的地址HK。而二次探测再散列只有在哈希表长m为形如4j+3(j为整数)的素数才有可能,随机探测在散列则取决于伪随机数列。

2.再哈希法

Hi=RHi(key)   i=1,2,...k   RHi均为不同的哈希函数,即在同义词产生地址冲突时,计算另一个哈希函数地址,直到冲突不再发生。这种方法不易产生聚集,但是增加了计算的时间。

3链地址法

将所有关键字为同义词的记录存储在同一线性链表中。将设某哈希函数产生的哈希地址在区间[0,m-1]上,则设立一个指针型变量。 Chain ChainHash[m];

其中每个分量的初始状态都是空指针。凡哈希地址为i的记录都插入到头指针为ChainHash[i]的链表中。在链表中插入的位置可以是表头和表未,也可以是中间,以保持同义词在同一线性链表中按关键字有序。

4..建立一个公共的溢出区

这也是处理冲突的一种方法。将设哈希函数值域为[0,m-1],则设向量HashTable[0...m-1]为基本表,每个分量存放一个记录,另设立向量OverTable[0...v]为溢出表。所有关键字和基本表中关键字为同义词的记录,不管他们由哈希函数得到的哈希地址是什么,一旦发生冲突,都填入溢出表。(建立一个公共溢出区域,就是把冲突的都放在另一个地方,不在表里面。)

哈希表的查找及其分析

在哈希表上进行查找的过程和哈希造表的过程基本一致。给定K,根据造表时设定的哈希函数求得哈希地址,若表中此位置上没有记录,则查找不成功。否则比较关键字,若和给定值相同,则查找成功。否则根据造表时设定的处理冲突的方法找下一地址,直至哈希表中某个位置为空或者表中所填记录的关键字等于给定值为止。

总结:

从哈希表的查找过程可见:

(1)虽然哈希表在关键字与记录的存储位置之间建立了直接映射,但由于冲突的产生,是的哈希表的查找过程仍然是一个给定值和关键字进行比较的过程。仍需以平均查找长度作为衡量哈希表的查找效率的度量。

(2)查找过程中需和给定值进行比较的关键字的个数取决于三要素:哈希函数,处理冲突的方法,哈希表的填充因子。(哈希函数的好坏影响出现冲突的频繁程度)

对同样一组关键字,设定相同的哈希函数,则不同的处理冲突的方法得到的哈希表不同。如下例1例2两个哈希表,在记录中查找概率相同的前提下,前者的平均查找长度为:

ASL(12)=1/12(1*6+2*4+3+4)=1.75(前者链地址法)

ASL(12)=1/12(1*6+2+3*3+4+9)=2.5(后者线性探测再散列)

线性探测再散列在处理冲突的过程中容易产生记录的二次聚集,如哈希地址不相同的记录又产生新的冲突,而链地址法处理冲突不会发生类似情况,因为哈希地址不同的记录在不同的链表中。

在一般情况下,处理冲突方法相同的哈希表,其平均查找长度依赖于哈希表的装填因子

哈希表的装填因子定义为: a=(表中填入的记录数)/(哈希表的长度)

a标志哈希表的装满程度,a越小,发生冲突的可能性越小,a越大,表中填入的记录越多,发生冲突的可能性越大,查找时给定值与之进行比较的关键字的个数也就越多。

案例

例1:

例2

查找成功和查找不成功的平均查找长度

  1. 查找成功
  1. 线性探测再散列的哈希表查找成功时的平均查找长度

Snl=1/2(1+1/(1-a))

  1. 随机探测再散列,二次探测再散列和再哈希的哈希表查找成功时的平均查找长度为:

Snr=-1/aln(1-a)

链地址法处理冲突的哈希表查找成功时的平均查找长度为:

Snc=1+a/2

由于哈希表在查找不成功时所用的比较次数也和给定值有关,则可类似定义哈希表在查找不成功时的平均查找长度为:查找不成功时需和给定值进行比较的关键字个数的期望值。

不同的处理冲突的方法构成的哈希表查找不成功的平均查找长度分别为:

Unl=1/2(1+1/(1-a)2)           ---->-线性探测再散列

Unr=1/(1-a)                  ------->伪随机探测再散列

Unc=a+e-a                               ---------------->链地址

分析:

长度为m的哈希表中装填有n个记录时查找不成功的平均查找长度。这个问题相当于要求在这张表中填入第n+1个记录时所需作的比较次数的期望值。

(假定:a.哈希函数是均匀的。即产生表中各个地址的概率相等。B.处理冲突后产生的地址也是随机的。)

由于哈希表中n个记录是先后填入的,查找每一个记录所需比较次数的期望值,恰为填入此记录时找到此哈希地址时所进行的比较次数的期望值。

总结:

哈希表的平均查找长度是a的函数,而不是n的函数。不管n多大,总可以选择一个合适的装填因子以便将平均查找长度限定在一个范围内。(注意:若要在非链地址处理冲突的哈希表中删除一个记录,则需在该位置的记录上填入一个特殊符号,以免找不到他后面填入的同义词的记录)。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值