HashMap 的长度为什么是 2 的幂次方

        为了优化HashMap的查询效率并减少哈希冲突,需要尽量使键值对均匀分布在不同的桶中。理想情况下,哈希函数能为每个键值对生成一个均匀分布的哈希码,从而最小化哈希冲突的发生。然而,Java的哈希码取值范围为-2147483648到2147483647,这将近40亿的散列空间。直接使用该范围内的哈希码作为存储索引是不现实的,因为那需要一个巨大的数组,内存消耗将是不可接受的。

        因此,在实际应用中,通常将哈希码对数组长度取模,所得余数作为存储桶的索引。这种方法将键值对均匀分布到有限的桶区间内,在充分利用内存的同时,也有效缓解了哈希冲突的问题。这个数组下标的计算方法是“ (n - 1) & hash”。(n 代表数组长度)

        那为什么数组下标的计算方法不是hash%n呢?

        (n - 1) & hash 等于 hash % n 的原因是因为它们都能够获取hash值在一定范围内的余数,区别在于计算方式不同。

        在计算机中,通常使用&运算来快速获取一个数的最后几位二进制位。n - 1如果是2的幂次减1,那么它的二进制表示就是由n个1组成的数,例如7(111二进制)。当 (n-1) & hash时,结果就是保留hash值的后n位。而hash % n则是用常规的求余运算来计算hash在n范围内的余数。

        由于(n-1)&运算实际上是在二进制级获取末尾n位的快捷方式,而%运算则是十进制求余,两者在计算结果上是等价的。

        不过,位运算&由于直接对内存的二进制位进行操作,它的运算效率比%高得多,所以在Hash求余的算法中一般优先选择&。但是,要使(n-1)&hash等于hash%n,需要满足n是2的幂次数,否则&运算得到的结果就不等于求余了。因此,在设计Hash求余算法时,常常会选择一个接近2的幂次的质数作为n的值。

        总之,(n-1)&hash等于hash%n,前提是n是2的幂次数,它利用了位运算的高效性来加速求余过程。

举个例子:

假设你有一个储物柜,格子数量是16个(2的4次方)。格子从0到15编号。你手上有很多东西,每件东西都有一个号码(相当于hash值)。

你决定按照下面规则,将东西放进储物柜的格子里存放:

  1. 用除法求余运算: 东西号码 % 16 = 余数 将该东西放进编号为"余数"的格子
  2. 用位运算: (16-1)用二进制表示为1111 (16-1) & 东西号码 = 余数
    将该东西放进编号为"余数"的格子

不管用哪种方式,东西都会被均匀分布到0到15的格子里。由于格子数16是2的幂次数,两种运算得到的余数结果是完全相同的。

位运算的方式实际上是先把东西号码的二进制码限制在最后4位(余数最多只能是4位二进制),这4位二进制数字对应的就是0到15的余数。

而当格子数量不是2的幂次时,比如格子数是15,第二种位运算(15-1)&东西号码就不等于第一种求余号码%15了。

所以(n-1) & hash 等于 hash % n的前提,就是n必须是2的幂次数。这样可以保证两种运算得到的余数是一致的,从而可以被均匀分布到n个位置。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值