HashMap 中的取模和扩容公式推导

为什么 HashMap 容量 capacity 大小是 2 的 n 次幂?
为什么使用 e.hash & (capacity - 1) 位运算作取模公式?
为什么扩容时使用 e.hash & oldCap 来计算扩容后的数组索引?
本文通过推导 HashMap 中的取模和扩容公式以回答上述问题。

1. 按位与(&)运算的理解

位运算的运算规则如下:
位运算
两个二进制的数按位与,如 A & B,当 B 中某一位为 1,则保留 A 上对应位上的数。
假设 B = 1000(二进制),第四位为 1。
当 A = 1001(二进制),A & B 取得第四位为 1,得到 A & B = 1000(二进制);
当 A = 0110(二进制),A & B 取得第四位为 0,得到 A & B = 0000(二进制);

理解了按位与的这一层含义之后,再来看 HashMap 中的取模和扩容算法。

2. 取模运算

HashMap 的取模公式为 e.hash & (capacity - 1) 。

这里 capacity 是 HashMap 数组结构的大小,约定为 2 的 n 次幂,记为 capacity = 2n
对于节点 e,它的哈希值用 e.hash 表示。

正常来说,取模公式为 e.hash % capacity,为什么 HashMap 中可以用位运算来替代呢?

2.1 当 e.hash 为正数

从二进制角度来看,e.hash / capacity = e.hash / 2n = e.hash >> n,即把 e.hash 右移 n 位,此时得到了 e.hash / 2n 的商。
而被移掉的部分(低 n 位),则是 e.hash % 2n,也就是余数

如何取得 e.hash 的低 n 位呢?

已知 2n 的二进制形式为 1 后面跟着 n 个 0,则 2n - 1 的二进制形式为 n 个 1。
如 8 = 23,其二进制形式为 1000,7 = 23 - 1,其二进制形式为 111。

根据对按位与(&)操作的理解,e.hash & (2n - 1) 就是取得 e.hash 的低 n 位,同样是余数

因此我们可以推导出 e.hash & (capacity - 1) = e.hash % capacity。

验证:


                
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值