HashMap中确定数组位置为什么要用hash进行扰动

HashMap数据存储的过程先根据key获得hash值,通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。

其中,jdk1.8中扰动函数hash的源码:

static final int hash(Object key) {
    int h;
    // key.hashCode():返回散列值也就是hashcode
    // ^ :按位异或
    // >>>:无符号右移,忽略符号位,空位都以0补齐
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

其中看到在获得hash值时将key的hashCode异或上其无符号右移16位,Hashmap这么做原因:

防止一些实现比较差的 hashCode() 方法,使用扰动函数之后可以减少碰撞,进一步降低hash冲突的几率

打个比方, 当我们的数组长度n为16的时候,哈希码(字符串“abcabcabcabcabc”的key对应的哈希码)对(16-1)与操作,对于多个key生成的hashCode,只要哈希码的后4位为0,不论不论高位怎么变化,最终的结果均为0。 如下图所示:

1954974080(HashCode) 111 0100 1000 0110 1000 1001 1000 0000
2^4-1=15(length-1) 000 0000 0000 0000 0000 0000 0000 1111
&运算 000 0000 0000 0000 0000 0000 0000 0000

而加上高16位异或低16位的“扰动函数”后,结果如下:

原HashCode 1954974080 111 0100 1000 0110 1000 1001 1000 0000
(>>>16)无符号右移16位 29830 000 0000 0000 0000 0111 0100 1000 0110
^(异或)运算 1955003654 111 0100 1000 0110 1111 1101 0000 0110
2^4-1=15(length-1) 15 000 0000 0000 0000 0000 0000 0000 1111
&(与)运算 6 000 0000 0000 0000 0000 0000 0000 0110

可以看到: 扰动函数优化前:1954974080 % 16 = 1954974080 & (16 - 1) = 0 扰动函数优化后:1955003654 % 16 = 1955003654 & (16 - 1) = 6 很显然,减少了碰撞的几率。

 

参考:https://zhuanlan.zhihu.com/p/76735726

posted @   猫不夜行  阅读(1900)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示