HashSet如何维护存储桶?使用什么数据结构?

时间:2013-03-08 04:25:45

标签: java hash

当一个具有不同hashCode的元素被添加到HashSet时,是否需要添加一个新的权限?这个新桶的数据结构是什么?它是否再次使用某种数组并调整大小,每次添加一个新元素,从而在HashSet O(n)复合体中添加和删除?

在阅读了几篇文章后,我知道JDK的一些实现使用HashMap作为HashSet的备份集合,但后来HashMap使用了什么呢?

3 个答案:

答案 0 :(得分:3)

您可以随时look at the source code

在那里你会看到HashMap有一个桶数组:

transient Entry[] table;

每个存储桶本质上都是一个链表:

static class Entry<K,V> implements Map.Entry<K,V> {
         final K key;
         V value;
         Entry<K,V> next;
         final int hash;

对于给定的哈希代码,该数组为您提供了对存储桶的恒定时间访问,然后您必须遍历该列表(希望不会有多于一个或两个条目):

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;
}

  

当一个具有不同hashCode的元素被添加到HashSet时,是否需要添加一个新的权限?

当添加具有与现有hashCode相同的hashCode的元素时,它将进入同一个存储桶(在链接列表的末尾)。

当添加带有新hashCode的元素时,它可能会也可能不会转到另一个桶(因为你有更多的hashCodes而不是桶)。

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

  

添加此新存储桶的数据结构是什么?

未添加存储桶。有一个固定的桶阵列。当您需要更多容量时,整个结构将使用更大的阵列进行重建。

  

它是否再次使用某种数组并调整大小,每次添加一个新元素,从而在HashSet O(n)复合体中添加和删除?

不是每一次。理想情况下从不。只有当你错误估算了容量并最终需要更多时。然后它变得昂贵,因为所有都被复制到一个新的数组。此过程与ArrayList基本相同。

答案 1 :(得分:0)

即使只是阅读HashSetHashMap的Javadoc,也可以收集很多内容。 HashSet由HashMap支持。

根据HashMap Javadoc,它由初始容量和负载因子定义。在超出加载因子之前,不会调整支持哈希表的大小,因此,为了回答您的一个问题,不会,每次从地图添加/删除时都不会调整大小。

答案 2 :(得分:0)

HashMap使用Map.Entry数组:数组中的元素是key,value对。

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

为了避免此问题,HashMap当其当前计数大于内部阵列容量的某个百分比(“加载因子”,默认为75%)时自动调整大小。这意味着75个元素HashMap将由100个元素阵列烘焙。降低负载系数会增加内存开销,但会将平均执行顺序偏向几乎恒定。

请注意,如果每个元素具有相同的hashCode,最坏情况插入可能仍为O(n)。