Hash冲突及解决办法


Hash冲突就是,不同的数据元素关键字K,计算出的哈希值相同,此时两个或多个数据,对应同一个存储地址,即产生冲突。

Hash冲突解决办法:

  1. 开放定址法
  2. 再哈希法
  3. 链地址法
  4. 建立公共溢出区

开放定址法

使用某种探测算法在散列表中寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到。就是即使key产生hash冲突,也不会形成链表,而是将所有元素都存入哈希表里。发生hash冲突时,就以当前地址为基准,进行再寻址的方法去寻址下一个地址,直到找到一个为空的地址为止。

实现方式有:
1.线性探查:发生hash冲突时,顺序查找下一个位置,直到找到一个空位置(固定步长1探测)
2.二次探查:在发生hash冲突时,在表的左右位置进行按一定步长跳跃式探测(固定步长n探测)
3.伪随机探测:在发生hash冲突时,根据公式生成一个随机数,作为此次探测空位置的步长(随机步长n探测)。

 再哈希法

这种方式是同时构造多个哈希函数,当产生冲突时,计算另一个哈希函数的值。
这种方法不易产生聚集,但增加了计算时间。

链地址法(拉链法)

jdk1.8 中HashMap,ConcurrentHashMap都是采用这个方法,使用链表来保存发生hash冲突的key,即不同的key有一样的hash值,将这些发生冲突的 value 组成一个单向链表(只有next指针,没有pre指针)

    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

 

注意:最坏的就是hash值全都映射在同一个地址上,这样哈希表就会退化成链表

jdk1.8采用红黑树解决这种情况

建立公共溢出区

将哈希表分为基本表和溢出表两部分,为所有发生hash冲突的关键字记录一个公共的溢出区来存放。在查找的时候,先与哈希表的相应位置比较,如果查找成功,则返回。否则去公共溢出区按顺序一一查找。在冲突数据少时性能好,冲突数据多的时候耗时

优缺点比较:
开放散列(open hashing)/ 拉链法(针对桶链结构)
优点:
在总数频繁变动的时候可以节省开销,避免了动态调整;
记录存储在节点里,动态分布,避免了指针的开销
删除时候比较方便
缺点:
因为存储是动态的,所以在查询的时候跳转需要更多的时间的开销
在key-value可以预知,以及没有后续增改操作时候,封闭散列性能优于开放散列
不容易序列化

封闭散列(closed hashing)/ 开放定址法
优点:
容易序列化
如果可以预知数据总数,可以创建完美哈希数列
缺点:
存储的记录数目不能超过桶组数,在交互时候会非常麻烦
使用探测序列,计算时间成本过高
删除的时候比较麻烦
————————————————
版权声明:本文为CSDN博主「CommunicationGo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/DxhToStage/article/details/103991195


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM