数据结构 散列表

散列表(Hash Table)

散列表定义:根据给定的关键字来计算出关键字在表中的地址的数据结构。也就是说,散列表建立了关键字和存储地址之间的直接映射关系。(通过关键字访问地址,从而得到地址所存储的值)

散列表函数定义:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr。(将关键字带入散列函数中计算,就能得到对应存储地址)

** 散列函数可能会把两个或两个以上的不同关键字映射到同一地址,这种情况称为“冲突”,发生碰撞的不同关键字称为同义词。**

构造散列函数的tips:

(1)散列函数的定义域必须包含全部需要存储的关键字,值域范围则依赖与散列表的大小或地址范围。
(2)散列函数计算出来的地址应该能等概率,均匀分布的整个地址空间,从而减少冲突的发生。
(3)散列函数应尽量简单,能够在较短时间内计算出关键字对应的散列地址。

常用Hash函数的构造方法:

(1)直接地址法:直接取关键字的某个线性函数值为散列表地址,散列函数为H(key)=a×key+b。式中,a和b是常数。这种方法计算最简单,并且不会产生冲突。

(2)除留余数法:假定散列表表长为m,取一个不大于m但接近或等于m的质数p,利用以下公式把关键字转换成散列表地址。散列函数为H(key)=key%p。
关键是选好p,使得每一个关键字通过该函数转换后等概率地映射到散列空间上的任一地址,从而尽可能减少冲突可能性。

(3)数字分析法:设关键字是r的进制数(如十进制),而r个数码在各位上出现频率不一定相同,可能在某些位上分布均匀些,每种数码出现的聚会均等;而在某些上分布不均匀,只有某几种数码经常出现,则应该取数码分布为均匀的若干位作为散列地址。这种方法适合已知的关键字集合。(如手机号码)

(4)平方取中法:顾名思义,取关键字的平方值的中间几位作为散列地址。具体取多少看实际情况而定。这种方法得到的散列地址与关键字的每一位都有关系,使得散列地址分布比较均匀。
例如: 1234^2 = 1522756 取中间三位227作为散列地址
2345^2 = 5499025取中间三位990作为散列地址

(5)折叠法:折叠法是将关键字从左到右分割成位数相等的几部分(注意最后一部分位数不够时可以短些)然后将这几部分叠加求和并按散列表表长,取后几位作为散列地址。关键字位数很多,而且关键字中每一位上数字分布大致均匀时,可以采用折叠法得到散列地址。
例如:关键字为1234567890 列表表长为3位,可将关键字分为四组,每组3位
123|456|789|0 然后四组叠加求和 123+456+789+0=1368然后取后三位得到散列表地址368

常用Hash函数的冲突处理办法:

一.开放定址发:将产生冲突的Hash地址作为自变量,通过某种冲突解决函数得到一个新的空闲的Hash地址。
(1)线性探测法:冲突发生时,顺序查看表中下一个单元,知道找出下一个空闲单元或查遍全表。(会出现聚集问题)

(2)平方探测法:设发生冲突的地址为d,平方探测法得到的新地址序列为d+1^2, …。可以避免出现堆积问题,不能探测到散列表上所有单元,但至少能探测到一半单元。

(3)再散列法:又称为双散列法。需要使用两个散列函数,当通过第一个散列函数H(key)得到的地址发生冲突时,则利用第二个散列函数H2(key)计算地址增量。

(4)伪随机数序列法:当发生地址冲突时,地址增量为伪随机序列,称为伪随机序列法。

二.拉链法(chaining)
把散列到同一槽中的所有元素都存放在一个链表中。每个槽中有一个指针,指向所有散列到该槽的元素构成的链表的头。如果不存在这样的元素,则指针为空。

三.散列表的查找过程:类十余构造散列表,给定一个关键字key。
先根据散列函数计算出其散列地址。然后检查散列地址位置有没有关键字。
(1)如果没有,表明该关键字不存在,返回查找失败。
(2)如果有,则检查记录是否等于关键字。①等于则查找成功。 ②不等于,则按照给定的冲突处理办法计算下一个散列地址,再用改地址,执行上述过程。

四.散列表的查找性能:和装填因子有关。
装填因子一般几位α,定义为表的装满程度。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42368728/article/details/113128760
今日推荐