当一个具有不同hashCode的元素被添加到HashSet时,是否需要添加一个新的权限?这个新桶的数据结构是什么?它是否再次使用某种数组并调整大小,每次添加一个新元素,从而在HashSet O(n)复合体中添加和删除?
在阅读了几篇文章后,我知道JDK的一些实现使用HashMap作为HashSet的备份集合,但后来HashMap使用了什么呢?
答案 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)
即使只是阅读HashSet和HashMap的Javadoc,也可以收集很多内容。 HashSet由HashMap支持。
根据HashMap Javadoc,它由初始容量和负载因子定义。在超出加载因子之前,不会调整支持哈希表的大小,因此,为了回答您的一个问题,不会,每次从地图添加/删除时都不会调整大小。
答案 2 :(得分:0)
HashMap
使用Map.Entry
数组:数组中的元素是key,value
对。
插入元素时,将根据哈希码计算存储桶的位置。 如果插入的密钥与已存储在存储桶中的密钥(哈希码冲突)不同,则选择下一个空桶。该算法的结果是,在阵列“几乎满”的哈希映射上的操作将相当昂贵:实际上,如果只有一个空闲桶,它们将是O(n)。
为了避免此问题,HashMap
当其当前计数大于内部阵列容量的某个百分比(“加载因子”,默认为75%)时自动调整大小。这意味着75个元素HashMap
将由100个元素阵列烘焙。降低负载系数会增加内存开销,但会将平均执行顺序偏向几乎恒定。
请注意,如果每个元素具有相同的hashCode,最坏情况插入可能仍为O(n)。