Hash函数及冲突解决办法

概念

又称散列。Hashing 将一段数据(无论长还是短)转成相对较短的一段数据,例如一个字符串或者一个整数。一个通常使用的 hash 函数的例子是 md5()。

哈希函数通常是由他们产生哈希值的方法来定义的,有两种主要的方法:1.基于加法和乘法的散列2.基于移位的散列将n个关键字映射到k个槽中

一个衡量的标准是哈希函数得到哈希值的效率。通常,包含哈希函数的算法的算法复杂度都假设为O(1)

常见Hash函数

  1. 除法散列(除k取余): h(k) = k mod m,其中m为槽的个数。将关键字k映射到m个槽的某一个中去。【m不能太小,m一定是质数】
  2. 乘法散列法: h(k) = floor(m(kA mod 1)),用关键字k乘上常数A[A的范围(0,1)],并抽取kA的小数部分;然后用m乘以这个值,再取结果的底(即整数部分)。【比除法好,因为乘法比除法快,一般A=(根号5 - 1)/2,m是2的幂次】
  3. 全域散列法(universal hashing) :预先定义一个有限的散列函数集(就是多个散列函数),等到真正开始执行时,随机选择一个散列函数(一旦开始执行,散列函数就不能改变),这样的优点是对手不知道你要选那个散列函数,看到的只是random()。
  4. 完全散列:适用于静态集合(只有search操作),利用两级哈希,使得最坏情况下查找只需要O(1)。要求:第二个散列函数必须是没有碰撞发生的。
    这里写图片描述

Hash冲突解决

根据鸽巢原理,n只要大于m,一定至少有一个槽放了多于1个元素。所以不能完全避免碰撞(冲突);

1. 开放寻址法(open addressing)

简单一致散列:如果任何一个关键字k,他映射到m个槽的任何一个的可能性都相同,并且k映射到哪个槽与其他关键字独立无关,则称为简单一致散列。

装载因子:n/m,即一个槽的链表的平均长度。

将散列函数扩展定义成探查序列,即每个关键字有一个探查序列h(k,0)、h(k,1)、…、h(k,m-1),这个探查序列一定是0….m-1的一个排列(一定要包含散列表全部的下标,不然可能会发生虽然散列表没满,但是元素不能插入的情况),如果给定一个关键字k,首先会看h(k,0)是否为空,如果为空,则插入;如果不为空,则看h(k,1)是否为空,以此类推。

所有的元素都存放在散列表中。因此,适用于动态集合大小n不大于散列表大小的情况,即装载因子不超过1。否则,可能发生散列表溢出。

缺点:不支持删除操作,只支持INSERT、SEARCH操作,因此如果有删除操作,就用链接法。

生成探查序列的方法有:

  1. **线性探查:**h(k,i)=(h’(k)+i) mod m,可能有“一次群集”问题,即随着插入的元素越来越多,操作时间越来越慢。
  2. 二次探查:h(k,i)=(h’(k)+ai+bi^2) mod m,可能有“二次群集”问题,即如果h(k1,0)=h(k2,0),则探查序列就一致。
  3. 二次哈希:h(k,i)=(h1(k)+ih2(k)) mod m ,要求m和h2(k)互质,不然探查序列不能覆盖到整个下标。二次哈希最好,因为他能够生成m^2种(离m!最接近)排列,而线性探查、二次探查只能生成m种排列,而理想中如果满足一致散列的话,则会生成m!种排列。

2. 链接法(chaining)

又叫拉链法

把散列到同一槽中的所有元素都存放在一个链表中。每个槽中有一个指针,指向所有散列到该槽的元素构成的链表的头。如果不存在这样的元素,则指针为空。如果链接法使用的是双向链表,那么删除操作的最坏情况运行时间与插入操作相同,都为O(1),而平均情况下一次成功的查找需要Θ(1+α)时间。α是装填因子。

将散列表定义为一个由m个头指针组成的指针数 组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于 1,但一般均取α≤1。

优点:处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;删除结点的操作易于实现。只要简单地删去链表上相应的结点即可

缺点:指针需要额外的空间,故当结点规模较小时,开放定址法较为节省空间,而若将节省的指

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值