为什么 HashMap 默认负载因子是0.75?

1、典型回答

负载因子 (Load Factor)也叫扩容因子,它是一个用于控制 HashMap 何时进行扩容的参数。当 HashMap 中存储的键值对数量,超过了 HashMap 总容量乘以扩容因子时,HashMap 就会进行扩容操作。

例如 HashMap 的总容量为 16,扩容因子为 0.75,那么当 HashMap 中存储的键值对大于 12 (16*0.75)时HashMap 就会进行扩容。

注:负载因子的值是 0 到 1 之间 (大于 0,小于 1)。

为什么负载因子是 0.75?

对于这个问题,官方给的答案是这样的:

As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Highervalues decrease the space overhead but increase the lookup cost reflected in most of the operations of theHashMap class, including get and put). The expected number of entries in the map and its load factor shouldbe taken into account when setting its initial capacity, so as to minimize the number of rehash operations. Ifthe initial capacity is greater than the maximum number of entries divided by the load factor, no rehashoperations will ever occur.

上面的意思大概来说就是,负载因子为 0.75 是一种经验性的权衡,这个值被认为是在时间和空间效率之间找到一个良好平衡。

  • 当负载因子比较大的时候,那么扩容就会比较晚,空间利用率就会比较高,但发生哈希冲突的概率就会增大那么插入的时间就会变长;
  • 当负载因子比较小的时候,那么扩容会比较早,发生哈希冲突的概率会变小,插入的时间会变快,但空间利用率就会很低。

因此选择 0.75 是空间和时间效率的一种平衡

2、全面剖析

负载因子(Load Factor) 也叫扩容因子,它是一个用于控制 HashMap 何时进行扩容的参数。负载因子的计算公式为:负载因子 = 元素数量/哈希表容量。

使用 0.75 的负载因子是空间 (内存占用率) 和时间 (添加元素的时间)的一种平衡。

因为内存利用率越高,发生哈希冲突的概率越大,发生哈希冲突的概率越大,那么添加元素的性能越低,而当内存利用率越低时,发生哈希冲突的概率越小,添加元素的性能就越高,所以此时就需要使用负载因子,来平衡二者之间的关系。

3、知识扩展

0.75 的科学推断

官方并未对负载因子为 0.75 做过明确的解释,只是大概的说了一下,0.75 是空间和时间复杂度的平衡,但更多的细节是未做说明的,然而 Stack Overflow 一位大神从科学的角度推测了这个问题的答案,链接如下:

https://stackoverflow.com/questions/10901752/what-is-the-significance-of-load-factor-in-hashmap

简单翻译一下,它是通过二项式哈希函数的冲突概率来解释 0.75 这个问题的。假设一个哈希桶为空和非空的概率为 0.5,我们用 s 表示容量,n 表示已添加元素个数,根据二项式定理,桶为空的概率为:

P(0) = C(n,0)*(1/s)^0 *(1 - 1/s)(n - 0)

因此,如果桶中元素个数小于以下数值,则桶可能是空的公式为:

log(2)/log(s/(s - 1))

也就是说,当 趋于无穷大时,如果增加的键的数量是 P(0) = 0.5,那么 n/s 很快趋近于 g(2),而 g(2)0.693。所以,合理值大概在 0.7 左右,这就是对负载因子为 0.75 的一个科学推测。

相关推荐
卡尔特斯1 小时前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
白鲸开源1 小时前
Ubuntu 22 下 DolphinScheduler 3.x 伪集群部署实录
java·ubuntu·开源
ytadpole2 小时前
Java 25 新特性 更简洁、更高效、更现代
java·后端
纪莫2 小时前
A公司一面:类加载的过程是怎么样的? 双亲委派的优点和缺点? 产生fullGC的情况有哪些? spring的动态代理有哪些?区别是什么? 如何排查CPU使用率过高?
java·java面试⑧股
JavaGuide3 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户3721574261353 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源3 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
Hilaku3 小时前
Token已过期,我是如何实现无感刷新Token的?
前端·javascript·面试
Mor_3 小时前
UE5核心宏标记 (UCLASS, UPROPERTY, UFUNCTION) 学习笔记
面试
沐怡旸3 小时前
【底层机制】std::shared_ptr解决的痛点?是什么?如何实现?如何正确用?
c++·面试