hashmap取key下标详解+相关面试问题

hashmap中获取key数组下标index的步骤大致为一下散布:

  1. 获取到key的hashcode (32为的int值)
  2. 通过扰动函数(哈希函数)得到 newhash
  3. 下标 index = newhash & ( table.length - 1)
    在这里插入图片描述

下面展开对这三步进行分析:

  1. 第一步:key.hashCode()函数调用的是key键值类型自带的哈希函数,返回int型散列值。int值范围为**-2147483648~2147483647**

第一步就是拿到 hashcode 很好理解,重点在第二步和第三步,面试重点也是第二步和第三步。

  1. 第二步:通过扰动函数得到 newhash

面试一:这里的扰动函数具体是怎么实现的呢?
是用第一步的 hashcode(32位) 高16位和低16位异或 ,源码如下图:
在这里插入图片描述
面试二:什么是高16位和低16位异或呢?举个例子:
在这里插入图片描述

异或: 相同为0,不同为1;

  1. 第三步:index = newhash & ( table.length - 1)

第二步得到的 newhash 和数组长度-1 做与运算 就得到了下标index

面试三:这里一定会产生疑惑,为什么要 newhash & ( table.length - 1) 这样算呢?
先上图!!
在这里插入图片描述
面试四:这里就涉及到了 hashmap的容量为什么要是2的整数次幂了。

举例:16 = 2^4

转为二进制也就是 0000 0000 0000 0000 0000 0000 0001 0000

那么 16 - 1 二进制:0000 0000 0000 0000 0000 0000 0000 1111

高位都为0,相当于一个低位掩码,和 newhash 与操作的时候 就会保留下 后四位 正好可以作为数组下标。

面试五:那么,还有一个疑问:为什么不直接用hashcode 直接和 table - 1 做与操作呢?扰动函数不可以省略吗?实际意义是什么?
在这里插入图片描述
设计扰动函数的原因有两点:

  1. 一定要尽可能降低hash碰撞,越分散越好
  2. 算法一定要尽可能高效,因为这是高频操作, 因此采用位运算;

尽可能降低碰撞?怎么说?

hashcode —> newhash 只能说是一个更加散列的操作
通俗点说就是,hashcode还不够散列,通过扰动使它更加散列

假设hashmap容量为16,table - 1 肯定是取后四位 1111 去做与操作,如果没有扰动, hashcode 的后四位如果都是0 ,那么前面高位不管是多少结果下标 index 都是0,因为 0 和 任何做与都是0,所以碰撞的几率大。
而扰动后,前16位和后16位异或之后,混合了高位和地位,加大了随机性。

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

希望这篇文章对你有帮助!加油!

猜你喜欢

转载自blog.csdn.net/KuKu_Nao/article/details/118228395