Hash冲突及解决办法 【建议收藏】
Hash冲突就是,不同的数据元素关键字K,计算出的哈希值相同,此时两个或多个数据,对应同一个存储地址,即产生冲突。
Hash冲突解决办法:
- 开放定址法
- 再哈希法
- 链地址法
- 建立公共溢出区
- 开放定址法
使用某种探测算法在散列表中寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到。就是即使key产生hash冲突,也不会形成链表,而是将所有元素都存入哈希表里。发生hash冲突时,就以当前地址为基准,进行再寻址的方法去寻址下一个地址,直到找到一个为空的地址为止。
实现方式有:
1.线性探查:发生hash冲突时,顺序查找下一个位置,直到找到一个空位置(固定步长1探测)
2.二次探查:在发生hash冲突时,在表的左右位置进行按一定步长跳跃式探测(固定步长n探测)
3.伪随机探测:在发生hash冲突时,根据公式生成一个随机数,作为此次探测空位置的步长(随机步长n探测)。
再哈希法
这种方式是同时构造多个哈希函数,当产生冲突时,计算另一个哈希函数的值。
这种方法不易产生聚集,但增加了计算时间。
链地址法(拉链法)
jdk1.8 中HashMap,ConcurrentHashMap都是采用这个方法,使用链表来保存发生hash冲突的key,即不同的key有一样的hash值,将这些发生冲突的 value 组成一个单向链表(只有next指针,没有pre指针)
|
|
注意:最坏的就是hash值全都映射在同一个地址上,这样哈希表就会退化成链表
jdk1.8采用红黑树解决这种情况
建立公共溢出区
将哈希表分为基本表和溢出表两部分,为所有发生hash冲突的关键字记录一个公共的溢出区来存放。在查找的时候,先与哈希表的相应位置比较,如果查找成功,则返回。否则去公共溢出区按顺序一一查找。在冲突数据少时性能好,冲突数据多的时候耗时
优缺点比较:
开放散列(open hashing)/ 拉链法(针对桶链结构)
优点:
在总数频繁变动的时候可以节省开销,避免了动态调整;
记录存储在节点里,动态分布,避免了指针的开销
删除时候比较方便
缺点:
因为存储是动态的,所以在查询的时候跳转需要更多的时间的开销
在key-value可以预知,以及没有后续增改操作时候,封闭散列性能优于开放散列
不容易序列化
封闭散列(closed hashing)/ 开放定址法
优点:
容易序列化
如果可以预知数据总数,可以创建完美哈希数列
缺点:
存储的记录数目不能超过桶组数,在交互时候会非常麻烦
使用探测序列,计算时间成本过高
删除的时候比较麻烦
- 原文作者:Ethan
- 原文链接:https://zhangxingong.fun/post/hashcode-conflict-solution/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。