Hash表的有关概念(Hash函数、Hash冲突解决方法)总结

散列表(Hash)表

散列表的基本概念

在线性表和树表的查找中,记录在表中的位置和记录的关键字之间不存在特定的关系,在这些表中查找记录的时候就需要进行一系列的关键字比较。这一类查找的方法是建立在比较的基础上的,查找的效率取决于比较的次数
1.散列函数:将一个把查找表的关键字映射成该关键字对应的地址的函数,记为Hash(Key) = Addr这里的地址可以是数组下标,索引或者是内存的地址

散列函数可能会把两个以上的不同的关键字映射到同一个地址,称这种情况为冲突,这些发生碰撞的不同的关键字称之为同义词,一方面,设计良好的哈希函数应该尽量减少这样的冲突;另一方面由于这样的冲突是不可避免的,所以还要设计好处理冲突的方法

2.散列表是根据关键字直接进行访问的数据结构,也就是说,散列表建立了关键字和存储地址之间的一种直接的映射关系
理想情况下,对散列表进行查找的时间复杂度是O(1),即与表中元素的个数无关。

散列函数的构造方法

在构造散列函数之间,必须注意以下几点:

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

几种常用的散列函数:

  1. 直接定址发
    直接去关键字中的某个线性函数值作为散列地址,散列函数为:

Hash(key) = a * key + b

其中a和b是常数,在这种方式计算最为简单,并且不会产生冲突。它适合关键字的分布基本连续的情况,若关键字分布不连续,空位比较多,将造成存储空间的浪费

  1. 除留余数法
    这是一种最简单的、最常用的方法,假定散列表表长为m,取一个不大于m单是最接近或等于m的质数p,利用以下公式吧关键字转换为散列地址,散列函数为

Hash(key) = key % p

除留余数法的关键是选好p,使得每一个关键字通过该函数转换后等概率的映射到散列空间的任何一个地址,从而尽可能的减少冲突的可能性

  1. 数字分析法
    设关键字是r进制数,而r的个数在各位上出现的频率不一定相同,了能在某些位上分布的军训,每种数码出现的机会均等,而在某些位置上分布不均匀,只有某几种数码经常出现,则应该选取数码分布较为均匀的若干位作为散列地址,这种方法适合于已知关键字的集合,如果更换了关键字,就需要重新构造新的散列函数

  2. 平方取中法
    取关键字的平方值的中间即为作为散列地址,具体取多少位要看实际的情况而定,这种方法得到的散列地址与关键字的每一位都已联系,使得散列地址分布比较均匀,适用于关键字的每一位取值都不够均匀或者均小于散列地址所需的位数
    这样做是为了扩大差别,同时平方值的中间各位又能收到整个关键字中各位的影响,使用与关键字中每位都有某些重复数字或者出现频率高的

  3. 折叠法
    将挂件自分割成位数相同的几部分,最后一部分的位数可以短一些,然后取这几部分的叠加和作为散列地址,这种方法称为折叠法。关键字位数很多,而且关键字中的每一位数字分布大致均匀的时候,可以采用折叠法得到散列地址。

几种常用的散列函数:

任何设计出来的散列函数都不可能绝对的避免冲突,为此,必须考虑在发生冲突的时候应该如何进行处理,即为产生冲的关键字寻找下一个空的hash地址。

假设已经选定好了散列函数H(key),下面用Hi表示发生冲突后第i次探测的散列地址

1.开发地址法
	所谓开发地址发,值得时可存放新表项的空闲地址不仅向它的同义词表项开放,又向它的非同义词表开放。

Hi = (H(key) + di) % m m表示散列表表长,di为递增序列

(1)线性探测法:当di = 0, 1, 2 … m - 1的时候称为线性探测法。这种方法的特点是:
冲突发生的时候,顺序查看表中下一个单元,直到找出一个空闲单元

线性探测法可能使得第i个散列地址的同义词存入到了第i + 1个散列地址,这样本应该存入第i+1个散列地址的元素就争夺第i + 2个散列地址,从而造成了大量元素在相邻的散列地址上聚集起来,大大降低了查找效率

(2)平方探测法:当di = 0^2 , 1 ^2 , 2 ^2 ,- 1 ^2 …又称之为二次探测法
平放探测法是一种较好的处理冲突的方法,可以避免出现堆积的问题,它的绝点是不能探测到散列表上的所有单元,但至少能探测到一半的单元

(3)再Hash法:di = Hash2(key),又称为在Hash法,需要使用到两个散列函数,当通过一个散列函数得到的地址发生冲突的时候,则利用第二个散列函数Hash2计算关键字的地址增量
他们的具体散列函数的形式如下:

Hi = (H1(key) +i * H2(key) ) % m

(4)伪随机序列法:当di为伪随机序列的时候,称为伪随机序列法

注意 : 在开发地址的情形下,不能随便物理删除表中的元素,因为若删除元素将会截断他具有相同散列地址的元素的查找地址,所以若想删除一个元素,给它做一个删除标记,进行逻辑删除,但是这样做的副作用就是:在执行多次删除后,表面上看起来散列表很满,实际上有许多位置没有利用到。

拉链法

显然,对于不同关键字可能会通过散列函数映射到同一个地址,为了避免非同义词发生的冲突,可以把所有的同义词存储到一个线性链表中,这个线性链表由散列地址唯一标识。假设散列地址为i的同义词链表的头指针存放在散列表的第i个单元中,因而查找、插入和删除操作主要在链表中进行。拉链法使用于经常进行插入和删除的情况。

在这里插入图片描述

参考《数据结构考研复习指导》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值