HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导

简介: HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。

PS:由于文档是我在本地编写好之后再复制过来的,有些文本格式没能完整的体现,故提供下述图片,供大家阅览,以便有更好的阅读体验:
image.png
HashMap在扩容时,需要先创建一个新数组,然后再将旧数组中的数据转移到新数组上来
此时,旧数组上的数据就会根据(e.hash & oldCap) 是否等于0这个算法,被很巧妙地分为2类:
① 等于0时,则将该头节点放到新数组时的索引位置等于其在旧数组时的索引位置,记为低位区链表lo开头-low;
② 不等于0时,则将该头节点放到新数组时的索引位置等于其在旧数组时的索引位置再加上旧数组长度,记为高位区链表hi开头high.
具体,详见下述的算法推导解析:
算法:
(e.hash & oldCap)=0
前提:
 e.hash代表的是旧数组中节点或元素或数据e的hash值,该hash值是根据key确定过的:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16) ;
 oldCap为旧数组的数组长度,是2的n次幂的整数。即e.hash&2^n=0

推导过程1(e.hash & oldCap)=0:

  1. 因为oldCap是2的n次幂的整数,其二进制表达为1个1后面跟n个0:1000…0,若想要e.hash&oldCap的结果为0,则e.hash的二进制形式中与对应oldCap的二进制的1的位置一定为0,其他位置的可以随意,这样即可保证结果为0;
  2. 假设:
    oldCap= 2 ^ 3 =8 = 1000
    则e.hash可以是 0101

e.hash&oldCap 0000=0

  1. (2oldCap -1)=2 ^ 4-1=01111,其二进制位数比oldCap多一位,但多的这一位是0,其余都是1(其低三位肯定也是1);(oldCap-1)=2 ^ 3-1=0111,其二进制位数与oldCap相同,且其低3位的值都是1。故(2oldCap-1)和(oldCap -1)两者与只有4位且首位为0的e.hash=0101计算时,其实只有低3位真正能影响计算结果,而两者的低3位相同,都是111;
  2. 故在前提条件下,(2oldCap-1)和(oldCap -1)两者与e.hash进行&运算之后的结果一样:
    (2oldCap -1)=2 ^ 4-1= 01111 (oldCap-1)=2 ^ 3-1= 0111
    e.hash 0101 e.hash 0101

e.hash&oldCap 00101=5 e.hash&oldCap 0101=5

  1. 而(oldCap -1) &e.hash恰巧代表的就是e元素在旧数组中的索引位置;
    而(2oldCap -1) &e.hash则代表的就是e元素在旧数组长度扩容2倍后的新数组里的索引位置
  2. 综上,可得出满足e.hash&oldCap=0的元素,其在新旧数组中的索引位置不变;

推导过程2(e.hash & oldCap)不等于0:

  1. 因为oldCap是2的n次幂的整数,其二进制表达为1个1后面跟n个0:1000…0,若想要e.hash&oldCap的结果不为0,则e.hash的二进制形式中与对应oldCap的二进制的1的位置一定不为0,其他位置的可以随意,这样即可保证结果不为0;
  2. 假设:
    oldCap= 2 ^ 3 =8 = 1000
    则e.hash可以是 1101

e.hash&oldCap 1000=13

  1. (2oldCap -1)=2 ^ 4-1=01111,其二进制位数比oldCap多一位,但多的这一位是0,其余都是1(其低三位肯定也是1,其从左到右数的第4位为1);(oldCap-1)=2 ^ 3-1=0111,其二进制位数与oldCap相同,且其低3位的值都是1, 其从左到右数的第4位为0,。故(2oldCap-1)和(oldCap -1)两者与只有4位且首位为1的e.hash=1101计算时,其实也只有从左到右数的第4位(0)真正能影响计算结果,,因为低3位完全一样都是1;
  2. 故在前提条件下,(2oldCap-1)和(oldCap -1)两者与e.hash进行&运算后结果相差了oldCap:
    (2oldCap -1)=2^4-1= 01111 ( oldCap - 1 ) =2 ^ 3-1= 0111
    e.hash 1101 e.hash 1101

(2oldCap -1)& e.hash 01101=8+5 (oldCap -1)&e.hash 0101=5

  1. 而(oldCap -1) &e.hash恰巧代表的就是e元素在旧数组中的索引位置;
    而(2oldCap -1) &e.hash则代表的就是e元素在旧数组长度扩容2倍后的新数组里的索引位置
  2. 综上,可得出满足e.hash&oldCap不等于0的元素,其在新数组中的索引位置是其在旧数组中索引位置的基础上再加上旧数组长度个偏移量。
目录
相关文章
|
26天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
53 5
|
1月前
|
算法 索引
让星星⭐月亮告诉你,HashMap的resize()即扩容方法源码解读(已重新完善,如有不足之处,欢迎指正~)
`HashMap`的`resize()`方法主要用于数组扩容,包括初始化或加倍数组容量。该方法首先计算新的数组容量和扩容阈值,然后创建新数组。接着,旧数组中的数据根据`(e.hash & oldCap)`是否等于0被重新分配到新数组中,分为低位区和高位区两个链表,确保数据迁移时的正确性和高效性。
63 3
|
1月前
|
机器学习/深度学习 算法
让星星⭐月亮告诉你,HashMap之tableSizeFor(int cap)方法原理详解(分2的n次幂和非2的n次幂两种情况讨论)
`HashMap` 的 `tableSizeFor(int cap)` 方法用于计算一个大于或等于给定容量 `cap` 的最小的 2 的幂次方值。该方法通过一系列的无符号右移和按位或运算,逐步将二进制数的高位全部置为 1,最后加 1 得到所需的 2 的幂次方值。具体步骤包括: 1. 将 `cap` 减 1,确保已经是 2 的幂次方的值直接返回。 2. 通过多次无符号右移和按位或运算,将最高位 1 后面的所有位都置为 1。 3. 最终加 1,确保返回值为 2 的幂次方。 该方法保证了 `HashMap` 的数组容量始终是 2 的幂次方,从而优化了哈希表的性能。
32 1
|
22天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
7天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。
|
8天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
9天前
|
存储 算法 决策智能
基于免疫算法的TSP问题求解matlab仿真
旅行商问题(TSP)是一个经典的组合优化问题,目标是寻找经过每个城市恰好一次并返回起点的最短回路。本文介绍了一种基于免疫算法(IA)的解决方案,该算法模拟生物免疫系统的运作机制,通过克隆选择、变异和免疫记忆等步骤,有效解决了TSP问题。程序使用MATLAB 2022a版本运行,展示了良好的优化效果。
|
8天前
|
机器学习/深度学习 算法 芯片
基于GSP工具箱的NILM算法matlab仿真
基于GSP工具箱的NILM算法Matlab仿真,利用图信号处理技术解析家庭或建筑内各电器的独立功耗。GSPBox通过图的节点、边和权重矩阵表示电气系统,实现对未知数据的有效分类。系统使用MATLAB2022a版本,通过滤波或分解技术从全局能耗信号中提取子设备的功耗信息。
|
8天前
|
机器学习/深度学习 算法 5G
基于MIMO系统的SDR-AltMin混合预编码算法matlab性能仿真
基于MIMO系统的SDR-AltMin混合预编码算法通过结合半定松弛和交替最小化技术,优化大规模MIMO系统的预编码矩阵,提高信号质量。Matlab 2022a仿真结果显示,该算法能有效提升系统性能并降低计算复杂度。核心程序包括预编码和接收矩阵的设计,以及不同信噪比下的性能评估。
25 3