【数据结构之哈希表(一)】 解决哈希冲突的四种办法(举例推演)

导语

哈希表是我们在开发中经常使用到的一种数据结构。它的结构也决定了它不可避免地会产生冲突。那么,如何解决哈希冲突呢?

我搜索了一些资料,如今结合自己的理解做一个学习记录。

我们先给出一个产生哈希冲突的例子:

(16、25、3、29、5、2、19、17、34)
Hash(key)= key % 11。

对应的地址应该是:

5、3、3、7、5、2、8、6、1

很显然存在哈希冲突。
接下来我们来看一下不同方法分别是如何处理这种冲突的:

(一)开放定址法

第一种方法是开放定址法,也就是说当冲突发生时,使用某种探查技术生成一个探查序列,再按照该序列逐个寻找。

插入:

  • 寻找一个开放的地址,将待插入节点存入该地址单元,插入成功
  • 如果查找到了最后一个地址仍未找到,则代表该表已满,插入失败。

查找:

  • 寻找给定的关键字,查找成功;
  • 如果找到了开放的地址,或者查找到了最后一个地址,说明表中无待查关键字,查找失败。

有以下几种常见的探查技术:

(1)线性探查法

h(key) = d;
探查序列为:d、d+1、d+2、…、0、1、…、d-1。

解决方案

(16、25、3、29、5、2、19、17、34)
Hash(key)= key % 11。

哈希值: 533 475 6286 7 8 9、1

012345678910
342253165291917

缺点:

  • 容易造成堆聚现象。所谓堆聚现象,就是存入哈希表的记录在表中连成一片。这样一来,再有新的记录时更容易发生冲突,也就是说非同义词也可能发生冲突,进一步造成堆聚。
  • 删除工作困难,只能标记该节点已删除,而不能真正置空该位置因为会截断其后的同义词的查找这是所有开放定址法的共同缺陷。
  • 如果发生溢出,要另外设立顺序溢出表。

(2)线性补偿探查法

h(key)=d;
哈希表长度为n,q与n互质(能保证遍历所有位置)。
探查序列为:di = (d+q)%n(0<=i<=n-1)

解决方案

(16、25、3、29、5、2、19、17、34)
Hash(key)= key % 11。
不妨取q = 5。

哈希值: 533 875 1028 2 7 161 6 0

012345678910
341922516172935

缺点:

  • 同线性探测,删除困难。

(3)随机探测

随机探测就是将线性探测的步长从常数改为随机数。

不同的关键字随机产生不同的探测序列,可以减少堆聚。

优点:

  • 减少堆聚

缺点:

  • 尽管不同关键字具有不同的探测序列,但同一关键字的探测序列却是固定的,所以仍然不能直接删除,而只能打上删除标记。

(4)二次探查

探查序列为:di = h(key) + i2(i>=0).

不能遍历所有空位,但当用该办法查找不到空位时,也是该扩充哈希表的时候。

(二)再哈希法

再哈希法也叫再散列法,是指当发生冲突时,对得到的哈希值进行再次哈希,直至不再发生冲突为止。需要多个不同的哈希函数。
h1(key) = d1;
h2(key) = d2;

hi(key) = di;

解决方案

(16、25、3、29、5、2、19、17、34)
Hash1(key)= key % 11;
Hash2(key)= 3key % 7;
Hash3(key)= key2 % 3;

哈希值: 533 275 12 10861 4

012345678910
532534161729192

缺点:

  • 每次冲突都要重新散列,计算时间增加。

(三)链地址法

链地址法也叫拉链法,即 将具有相同哈希值的结点链接到对应地址上的单链表上。这样,整个哈希表实际是一个链表数组。

解决方案

(16、25、3、29、5、2、19、17、34)
Hash(key)= key % 11。
不妨取q = 5。

哈希值:
533752861

012345678910
3422516172919
35

优点:

  • 处理冲突简单,且无堆聚现象,平均查找长度较短;
  • 灵活,适合于造表前无法确定表长的情况;
  • 负担大于1的装载因子,且结点较大时,指针域所占空间可以忽略不计;
  • 删除结点的操作易于实现

缺点:

  • 当结点空间较小时,指针域所占空间不可忽略。

(四)建立公共溢出区

解决方案

(16、25、3、29、5、2、19、17、34)
Hash(key)= key % 11;

哈希值: 533 075 12861

哈希表012345678910
3422516172919
公共表012345678910
35

结束语

用例子推演了一遍,才发现自己之前对再哈希法的理解有误。

之前误以为是将哈希之后得到的值再哈希,遇到了哈希前哈希后值相同的问题,造成逻辑上的死循环。

推演时发现了该问题,实则是使用其他的哈希函数原关键字进行再哈希。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值