java中的Hashcode bucket分发

java中的Hashcode bucket分发,java,collections,hash,bucket,Java,Collections,Hash,Bucket,假设我需要在Hashset中存储1000个对象,那么最好是让1000个bucket包含每个对象(通过为每个对象生成hashcode的唯一值),还是让10个bucket大致包含100个对象 拥有唯一bucket的好处是,我可以在调用equals()方法时节省执行周期 为什么设置桶的数量并尽可能均匀地分配桶中的对象很重要 理想的目标桶比应该是多少 为什么设置桶的数量并尽可能均匀地分配桶中的对象很重要 HashSet应该能够平均在O(1)时间内确定成员身份。从: 假设散列函数将元素正确地分散在存储桶中

假设我需要在Hashset中存储1000个对象,那么最好是让1000个bucket包含每个对象(通过为每个对象生成hashcode的唯一值),还是让10个bucket大致包含100个对象

拥有唯一bucket的好处是,我可以在调用equals()方法时节省执行周期

为什么设置桶的数量并尽可能均匀地分配桶中的对象很重要

理想的目标桶比应该是多少

为什么设置桶的数量并尽可能均匀地分配桶中的对象很重要

HashSet
应该能够平均在O(1)时间内确定成员身份。从:

假设散列函数将元素正确地分散在存储桶中,则该类为基本操作(添加、删除、包含和大小)提供恒定的时间性能

a
Hashset
用于实现此目的的算法是检索对象的哈希代码,并使用此代码查找正确的bucket。然后它遍历bucket中的所有项,直到找到一个相等的项。如果bucket中的项目数大于O(1),则查找所需的时间将长于O(1)

在最坏的情况下,如果所有项都散列到同一个bucket中,则需要O(n)个时间来确定对象是否在集合中

理想的目标桶比应该是多少

这里有一个时空权衡。增加桶的数量可以减少碰撞的机会。然而,它也增加了内存需求。哈希集有两个参数
initialCapacity
loadFactor
,允许您调整
HashSet
应创建的存储桶数量。默认负载系数为0.75,这在大多数情况下都可以,但如果有特殊要求,可以选择其他值

有关这些参数的更多信息,请参见以下文档:

这个实现为基本操作(get和put)提供了恒定的时间性能,假设哈希函数将元素正确地分散在存储桶中。对集合视图的迭代需要与HashMap实例的“容量”(bucket数)加上其大小(键值映射数)成比例的时间。因此,如果迭代性能很重要,那么不要将初始容量设置得太高(或负载系数太低),这一点非常重要

HashMap实例有两个影响其性能的参数:初始容量和负载因子。容量是哈希表中的存储桶数,初始容量只是创建哈希表时的容量。负载因子是在自动增加哈希表容量之前允许哈希表达到的满度的度量。当哈希表中的条目数超过负载因子和当前容量的乘积时,通过调用rehash方法,容量大约会增加一倍

作为一般规则,默认负载系数(.75)在时间和空间成本之间提供了良好的折衷。较高的值会减少空间开销,但会增加查找成本(反映在HashMap类的大多数操作中,包括get和put)。在设置初始容量时,应考虑map中的预期条目数及其负载系数,以尽量减少再灰化操作次数。如果初始容量大于最大入口数除以负载系数,则不会发生再灰化操作


大约每个元素一个存储桶对处理器更好,太多的存储桶对内存有害。Java将从少量bucket开始,并在HashSet开始填满时自动增加其容量,因此,除非您的应用程序出现性能问题,并且您已经确定了HashSet是原因,否则您不必太在意

如果在每个bucket中添加多个元素,则查找将花费更长的时间。如果有很多空存储桶,则使用的内存将超过需要的内存量,并且迭代元素所需的时间更长

不过,这似乎是一个有待实现的过早优化-默认构造函数在大多数情况下都很好。

Object.hashCode()
属于
int
类型,只能有2^32不同的值,这就是为什么要创建bucket并在它们之间分配对象


编辑:如果您使用
2^32
存储桶来存储2^32对象,那么违抗get操作将给您带来恒定的复杂性,但是当您逐个插入元素来存储
2^32
对象时,如果我们使用
object[]的话,重新灰化将比平均值更有效
作为存储桶,然后每次它超过
数组的长度时,它都将创建一个新的更大的数组,并将元素复制到该数组中。这一过程将增加复杂性。这就是为什么我们按比例使用
equals
hashcode
,这是由
HashSet
本身通过提供更好的
散列算法来实现的,那么每个bucket方法有1个对象更好吗?是的,但是HashSet为您做到了这一点,前提是hashcode()返回的值分布正确。例如,如果从hashCode()返回一个常量,则所有对象都将在同一个bucket中结束。@Jyotirup:没有必要实现每个bucket正好有一个对象的理想情况。会有一些碰撞是正常的。这对记忆有什么影响?要存储的元素数在两种情况下保持相同case@Jyotirup每个bucket都有一点开销,至少在我见过的大多数实现中是这样。我的意思不是说你应该避免有足够的桶来给你所有的元素一个一个,而是说你应该小心不要过分高估你需要多少桶