Java 在HashMap中,为什么阈值(要调整大小的下一个大小值)是容量*负载系数。为什么不和地图的大小或容量一样大呢

Java 在HashMap中,为什么阈值(要调整大小的下一个大小值)是容量*负载系数。为什么不和地图的大小或容量一样大呢,java,collections,Java,Collections,在HashMap中,为什么阈值(要调整大小的下一个大小值)是容量*负载因子。为什么不等于地图的大小或容量 例如,初始默认容量=16,负载系数=0.75,因此阈值=(容量*负载系数)=(16*0.75)=12 当我们添加第13个元素时,地图调整大小为什么会这样,为什么地图的作者决定保留它容量*负载系数(12)?为什么不同于容量(16) 为什么不保持阈值等于容量,以便只有当hashmap满时才进行重新灰化 从理论角度来看,与完整哈希表保持无冲突的可能性非常低,因此哈希表将调整大小以保持其所需的O(1

在HashMap中,为什么阈值(要调整大小的下一个大小值)是容量*负载因子。为什么不等于地图的大小容量

例如,初始默认容量=16,负载系数=0.75,因此
阈值=(容量*负载系数)=(16*0.75)=12

当我们添加第13个元素时,地图调整大小为什么会这样,为什么地图的作者决定保留它
容量*负载系数
(12)?为什么不同于容量(16)


为什么不保持阈值等于容量,以便只有当hashmap满时才进行重新灰化

从理论角度来看,与完整哈希表保持无冲突的可能性非常低,因此哈希表将调整大小以保持其所需的
O(1)
lookup属性-更少的冲突意味着更直接地访问条目和更少的搜索。
HashMap
实现允许您设置加载因子。这个设计决策为类的用户提供了一些对底层数据结构调整大小条件的控制措施

默认负载因子值
0.75
很可能被选择为内存使用和映射性能之间的合理平衡(由冲突率和调整大小开销决定)

对于
HashMap
的任何给定实例,您可以根据特定情况选择适当的负载因子。你需要考虑一个小内存占用的相对重要性,你对查找的性能敏感度,以及你对PUT的性能敏感度(这使得映射被重建的速度会非常慢)。 另一方面,您对“完整”哈希映射的概念有点偏颇。该实现可以很好地处理任意数量的冲突(尽管冲突会带来性能代价)。您可以使用负载因子为10亿的HashMap,它(可能)永远不会超过16的容量


将load factor设置为1.0没有问题,这将导致在将第17个元素添加到默认大小的HashMap时进行重新灰化操作。与默认值0.75相比,您将使用更少的空间,进行更少的重新灰化,并有更多的冲突(从而在链表中使用
equals()
进行搜索)。

HashMap上,它显示:

一般来说,默认负载系数(.75)提供了一个很好的折衷方案 在时间和空间成本之间。较高的值会减少空间开销 但会增加查找成本(反映在 HashMap类,包括get和put)。这个 应采用映射中的预期条目数及其加载系数 在设置其初始容量时应予以考虑,以尽量减少 再灰化操作的数量。如果初始容量更大 大于最大条目数除以负载系数,否 再灰化作业将永远不会发生

就像散列映射的理论一样——如果你的映射已经满了,那么你正在做一些非常非常错误的事情。到那时,你很可能会在
O(sqrt(N))
上使用随机数据进行查找-糟糕。您永远不希望hashmap已满。但是一个非常稀疏的贴图会浪费太多的空间(正如您所注意到的),并且需要太长的时间进行迭代。因此,应该有一个负载系数,对于大多数用例,该系数小于1

注:“浪费空间”与地图大小成正比,与负载系数成反比。但是,查找时间具有更复杂的预期性能函数。这意味着相同的加载因子将不适用于不同大小的哈希映射,因为这将意味着不同的比例权衡



在Knuth的《计算机编程的艺术》第3卷中可以找到权衡的一般概述。

在java 8中,当达到阈值时,bucket的内容从使用对象之间的链接切换到平衡树,从而将性能从O(n)提高到O(logn)。
这是java 8中有时需要记住的功能之一

感谢您的回答,我们如何确保碰撞将以低阈值低?当我在HashMap中添加500个元素时,阈值大小变为768,大小变为1024。所以,即使我有500个元素,大小是1024,当我添加769个元素时,它将是2048。所以在这里我们可以看到空间的浪费。我的问题是,当我们保持阈值=大小时,问题是什么?@niiraj874u我编辑了我的答案,专门针对这个问题。我从你的最后一段中理解了。谢谢+1@Ordus谢谢你的回答,但我非常清楚负载系数的重要性,但我的问题是,当我们保持阈值=大小时,问题是什么?。如果你对我的问题有任何疑问,请告诉我me@niiraj874u我在你输入评论时添加了一些内容。如果一个散列图满了,它的性能可能会很快下降,这取决于存储桶的组织方式。@Ordus所以我告诉你我的理解,然后告诉我我是否正确理解了你。当您保持阈值=大小时,对于较小的映射大小,它不会显示性能下降(当然可能有,但我们可以忽略的程度会非常小),但当大小为数千或lac时,它会对性能产生影响。@niiraj874u,是的。Knuth在《计算机编程的艺术》第三卷中对其进行了深入探讨。更深入的探索需要相当多的数学和概率知识。当然,这只是作为bucket实现的Javas链表。如果hashmap已满,分散寻址或开放寻址实现将停止工作。@niiraj874u:如果您“非常了解负载因子的重要性”,那么您的问题就不存在了?