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