HashMap 链表转红黑树的阈值为何为 8

目录

HashMap 将链表转化为红黑树的阈值设定为 8 的背后原因,与一个重要的统计学原理——泊松分布密切相关。该原理阐明了在单位时间(或面积、体积)内,随机事件的平均发生次数遵循泊松分布,其概率方程如下所示::

泊松分布

在哈希表中,我们将哈希桶作为单位面积,并将插入操作视为一系列随机事件,其中每个事件代表将一个 Key 映射到哈希桶内。因此,符号 λ \lambda λ 表示每个桶内平均存储元素的数量,而 P ( X = k ) P(X = k) P(X=k) 表示有 k k k 个 Key 被映射到同一个哈希桶的概率。

根据 HashMap 源码注释的信息,当 λ = 0.5 \lambda = 0.5 λ=0.5 时,以下是 k k k 从 0 到 8 对应的概率值:

* 0:    0.60653066
* 1:    0.30326533
* 2:    0.07581633
* 3:    0.01263606
* 4:    0.00157952
* 5:    0.00015795
* 6:    0.00001316
* 7:    0.00000094
* 8:    0.00000006

根据前述内容,可以得出在 λ = 0.5 \lambda = 0.5 λ=0.5 的情况下,哈希桶内哈希冲突元素数量 k = 8 k = 8 k=8 的概率极低。因此,HashMap 设定只有当链表长度超过 8 时,才会考虑将其转换为红黑树来处理,以在平衡查询效率和内存占用方面取得良好的性能平衡。

然而,还有一个重要问题需要解答:我们提到了 λ \lambda λ 被设定为 0.5,而泊松分布概率方程的准确性与频率 λ \lambda λ 的选择紧密相关。那么,Java是如何确定 λ = 0.5 \lambda = 0.5 λ=0.5 的呢?答案涉及到HashMap的扩容因子为0.75。

HashMap 扩容因子:
为了在容量和性能之间实现平衡,HashMap 将加载因子设置为 0.75。这一设定旨在维持合适的容器大小,以兼顾性能和空间的最佳折中。

首先,我们从一个理想情况出发:我们假设哈希算法能够完美地分散数据,因此在向 HashMap 中插入数据时,不会发生任何哈希冲突。然后,随着数据的连续插入,HashMap 会多次触发扩容操作。由于扩容因子设定为0.75,每次扩容前哈希表内的数据量占容器的比例为0.75,而每次扩容后,该比例为0.375。因此,在数据持续添加的过程中,哈希表内数据量的比例会在0.375和0.75之间呈锯齿状波动:

^
|
|           _______ 0.75
| /| /| /|    _____________0.5625
|/ |/ |/ |/ _______0.375
+--------------------------------->

在忽略方差的情况下,哈希表容量占比的期望值约为 0.5625,也就是说,平均每个桶内有 0.5 个元素,这便是源码中 λ \lambda λ 值的由来。

参考资料:Hashmap 底层原理

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值