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