Java HashSet如何维护存储桶?用于此目的的数据结构是什么?

Java HashSet如何维护存储桶?用于此目的的数据结构是什么?,java,hash,Java,Hash,当将具有不同哈希代码的元素添加到哈希集中时,必须添加新的哈希代码,对吗?这个新bucket将添加到什么数据结构中?它是否再次求助于某种数组,并在每次添加新元素时调整大小,从而将添加和删除操作添加到HashSet O(n)复合体中 在阅读了几篇文章之后,我了解到JDK的一些实现使用HashMap作为HashSet的备份集合,但是HashMap在这方面使用了什么呢?您可以随时查看 在这里,您将看到HashMap有一个bucket数组: transient Entry[] table; 每个buck

当将具有不同哈希代码的元素添加到哈希集中时,必须添加新的哈希代码,对吗?这个新bucket将添加到什么数据结构中?它是否再次求助于某种数组,并在每次添加新元素时调整大小,从而将添加和删除操作添加到HashSet O(n)复合体中

在阅读了几篇文章之后,我了解到JDK的一些实现使用HashMap作为HashSet的备份集合,但是HashMap在这方面使用了什么呢?

您可以随时查看

在这里,您将看到HashMap有一个bucket数组:

transient Entry[] table;
每个bucket本质上都是一个链表:

static class Entry<K,V> implements Map.Entry<K,V> {
         final K key;
         V value;
         Entry<K,V> next;
         final int hash;
静态类条目实现Map.Entry{
最终K键;
V值;
进入下一步;
最终整数散列;
该数组为您提供了对给定哈希代码的bucket的恒定时间访问,然后您必须循环遍历该列表(希望列表中不会有超过一个或两个条目):

final Entry getEntry(对象键){
int hash=(key==null)?0:hash(key.hashCode());
for(条目e=表[indexFor(hash,table.length)];
e!=null;
e=e.next){
对象k;
如果(e.hash==hash&&
((k=e.key)==key | |(key!=null&&key.equals(k)))
返回e;
}
返回null;
}

当将具有不同哈希代码的元素添加到哈希集中时,必须添加新的哈希代码,对吗

当添加与现有元素具有相同哈希代码的元素时,它将进入同一个bucket(在链表的末尾)

当添加一个具有新hashCode的元素时,它可能会也可能不会转到另一个bucket(因为您的hashCode比bucket多得多)

地图调整大小时,所有存储桶都会提前创建。如果达到容量限制,则会使用更多存储桶调整其大小,并将所有内容放入新的存储桶中

这个新bucket将添加到什么数据结构中

不添加存储桶。存储桶有一个固定的数组。当您需要更多容量时,整个结构将使用更大的数组重建

它是否再次求助于某种数组,并在每次添加新元素时调整大小,从而将添加和删除操作添加到HashSet O(n)复合体中


不是每次。理想情况下永远不会。只有当您错误计算了容量并最终需要更多容量时,它才会变得昂贵,因为所有数据都被复制到一个新数组中。此过程基本上与ArrayList相同。

甚至只需读取和的Javadoc就可以收集到很多信息。哈希集由哈希映射支持


根据HashMap Javadoc,它是由初始容量和负载因子定义的。在超过负载因子之前,不会调整备份哈希表的大小,因此要回答您的一个问题,不,不会对映射中的每个新添加/删除都进行调整。

HashMap
使用一个
映射数组。Entry
:eleme数组中的nt是一对
键,值

插入元素时,将根据哈希代码计算存储桶的位置。 如果插入的密钥与存储在存储桶中的密钥不同(哈希代码冲突),则选择下一个空存储桶。此算法的结果是,在数组“几乎满”的哈希映射上进行操作将非常昂贵:实际上,它们将是O(n)如果只有一个空桶

为了避免此问题,
HashMap
在其当前计数大于内部阵列容量的某个百分比(默认情况下为75%)时自动调整大小。这意味着75个元素的
HashMap
将由100个元素的数组烘焙。降低加载因子将增加内存开销,但将使平均执行顺序偏向于接近常量


请注意,如果每个元素都有相同的哈希代码,则最坏情况下的插入可能仍然是O(n)。

Luke,使用源代码。查看此线程“注意,如果每个元素都有相同的哈希代码,则最坏情况下的插入可能仍然是O(n)。”我认为这个属性是在最近针对Java应用服务器的哈希表攻击中使用的:构造查询参数,生成一个非常不幸的哈希表。源代码链接不起作用
final Entry<K,V> getEntry(Object key) {
         int hash = (key == null) ? 0 : hash(key.hashCode());
         for (Entry<K,V> e = table[indexFor(hash, table.length)];
              e != null;
              e = e.next) {
             Object k;
             if (e.hash == hash &&
                 ((k = e.key) == key || (key != null && key.equals(k))))
                 return e;
         }
         return null;
}