搜索结构之哈希表(线性探测法)

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。

若关键字为k,则其值存放在f(k)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数,按这个思想建立的表为散列表。

对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2),这种现象称为碰撞(英语:Collision)。具有相同函数值的关键字对该散列函数来说称做同义词。综上所述,根据散列函数f(k)和处理碰撞的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表便称为散列表,这一映射过程称为散列造表或散列,所得的存储位置称散列地址。

若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少碰撞。

散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位。散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位。

构造哈希函数需要注意以下几点:
1、哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域
2、哈希函数计算出来的地址能均匀分布在整个空间中
3、哈希函数应该比较简单

不管做什么事情都要达到优是不可能的,既要付出尽可能的少,又要得到大化的多,因此设计散 列函数,可以参看以下两个原则:
1、计算简单
2、散列地址尽量分布均匀

【常见哈希函数】

(1)直接定址法
取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B为常数。

这样的散列函数优点是简单、均匀,也不会产生冲突,但问题是需要 事先知道关键字的分布情况,适合查找表较小且连续的情况。

(2) 除留余数法
设散列表中允许的地址数为m,取一个不大于m,但接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key % p p<=m,将关键码转换成哈希地址。

(3)平方取中法
假设关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227作为散列地址;再比如关键字是4321,那么它的平方就是18671041,抽取中间的3位就可以是671或者710用作散列地址。

平方取中法比较适合:不知道关键字的分布,而位数又不是很大的情况。

(3) 折叠法
折叠法是将关键字从左到右分割成位数相等的几部分(注意:后一部分位数不够时可 以短些),然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。

比 如:关键字是9876543210,散列表表长为三位,我们将它分成四组987|654|321|0|,然后将它们叠加求和987+654+321+0=1962,再求后3位得到散列地址为962。有时可能 这还不能够保证分布均匀,不妨从一段向另一端来回折叠后对齐相加。比如将987和321反转,再与654和0相加,编程789+654+123+0=1566,此时的散列地址为566。

折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况。

(4)随机数法
选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key) = random(key),其中 random为随机数函数,通常应用于关键字长度不能采用此法。

(5) 数学分析法
分析一组数据,比如一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体相同,这样的话,出现冲突的几率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果用后面的数字来构成散列地址,则冲突的几率会明显降低。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。

散列冲突处理方法

任何一种散列函数也不能避免产生冲突,因此选择好的解决冲突溢出的方法十分重要。为了减少 冲突必须对散列表加以改造。 设散列表HT有m个地址,将其改为m个桶(bucket)。其桶号与散列地址一一对应,第i(0<= i < m)个桶的桶号即为第i个散列地址。每个桶可存放s个表项,这些表项的关键码应互为同义词。如 果对两个不同表项的关键码用散列函数计算得到同一个散列地址,就产生了冲突,它们可以放在 同一个桶内的不同位置。只有当桶内所有s个表项位置都放满表项后再加入表项才会产生溢出。

(1)【闭散列法】
闭散列,也叫开地址法。所有桶都直接放在散列表数组中。因此每个桶只有一个表项(s = 1)。若设散列表中各桶的编址为0到m-1,当要加入一个表项R是,用它的关键码R.key,通过散列 函数hash(R.key)的计算,得到它的存放桶号j,但是在存放时发现这个桶已经被另一个表项R占 据了,这时不但发生了冲突,还必须处理该溢出,为此必须把R存放到表中“下一个”空桶中。 如果表未被装满,则在允许的范围内必须还有空桶。

简而言之:就是一旦发生冲突,就去寻找下 一个空的散列表地址,只要散列表足够大,空的散列地址总能找到。

  • 10
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值