HashMap精妙和面试常常问

HashMap的数组挂链,链到8变成红黑树,扩容

HashMap的加载因子为0.75

HashMap 初始容量是16,扩容方式为2N;
HashMap有两个参数影响其性能:初始容量和加载因子。容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动扩容之前可以达到多满的一种度量。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行扩容、rehash操作(即重建内部数据结构),扩容后的哈希表将具有两倍的原容量。那为啥是0.75呢,java的解释是提高空间利用率和 减少查询成本的折中,0.75的话碰撞最小,根据泊松分布计算应严格限制在0.7-0.8之间最好(计算的过程贴在下面,这里计算方式是引用别人的我只能看懂结果)因此,一些采用开放定址法的hash库,如Java使用了0.75,而.net中的HashTable则直接将a的最大值定义为0.72,问的深了就是数学原因。

HashMap的链表长度大于8为啥是8

HashMap的链表长度大于8就会变成红黑树,这个也是根据泊松分布计算出来的结果(计算过程贴在下面),8 个键值对同时存在于同一个桶的概率只有 0.00000006,比 8 大的概率更是小于千万分之一,就它了

HashMap为什么通过(n - 1) & hash 获取哈希桶数组下标

看过HashMap源码人应该都知道HashMap是如何根据hash值来计算哈希桶数组下标的,就是通过(n - 1) & hash来计算的,那么为什么用的是位运算而不是取模运算(hash % n)呢?

HashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法;
这个算法实际就是取模,hash%length,计算机中直接求余效率不如位移运算,源码中做了优化hash&(length-1),
hash%length==hash&(length-1)的前提是length是2的n次方;

因为数据集足够的大时,那么取模运算的时间将会是位运算时间的十几倍(每个人的测试结果都可能不一样,但位运算的时间远远小于取模运算)。

讲到这,我们也就为什么HashMap的容量是2的n次幂?而容量时2的n次幂也就是导致了n-1。
当 n 是2的次幂时, n - 1 通过 二进制表示即尾端一直都是以连续1的形式表示的。当(n - 1) 与 hash 做与运算时,会保留hash中 后 x 位的 1,这样就保证了索引值 不会超出数组长度。
同时当n为2次幂时,会满足一个公式:(n - 1) & hash = hash % n。

根据泊松分布计算

在这里插入图片描述
在这里插入图片描述
计算方式引用于https://zhuanlan.zhihu.com/p/263523069?utm_source=wechat_session

以上写的有点混乱之后会进行整理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值