【问题标题】:HashSet iterationHashSet 迭代
【发布时间】:2015-11-09 05:22:04
【问题描述】:

我有一个关于 Java 中 HashSet 迭代器的查询。 在“Java 泛型和集合”一书中,有如下说明:

集合的哈希表实现的主要吸引力在于(理想情况下)常量时间 添加、删除、包含和大小等基本操作的性能。它的主要 缺点是它的迭代性能;因为遍历表涉及 检查每个存储桶,其成本与表大小成正比,而与表大小无关 它包含的集合。

它声明迭代器在底层表的每个桶中查找。但是通过实际实现(JDK 8),我看到 HashIterator 存储下一个节点 参考。所以看起来迭代器不需要访问每个存储桶。

这里是书错了还是我的理解错了?

【问题讨论】:

  • 您在查看LinkedHashMapHashMap 的代码吗?
  • 我正在查看 HashMap,当我调试查看为 HashSet 返回了哪个迭代器时,我看到返回了 HashMap 中的 KeyIterator,这又扩展了 HashIterator.HashIterator 记录下一个节点。
  • 根据Javadocs,“迭代这个集合需要的时间与 HashSet 实例的大小(元素的数量)加上支持 HashMap 实例的“容量”(数量桶)。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或负载因子太低)。”

标签: java iterator hashset


【解决方案1】:

文件是正确的。虽然KeyIterator确实调用nextNode().key,像这样

final class KeyIterator extends HashIterator implements Iterator<K> {
    public final K More ...next() {
        return nextNode().key;
    }
}

基类HashIteratornextNode() 的代码具有文档所讨论的循环:

final Node<K,V> nextNode() {
    Node<K,V>[] t;
    Node<K,V> e = next;
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    if (e == null)
        throw new NoSuchElementException();
    if ((next = (current = e).next) == null && (t = table) != null) {
        do {} while (index < t.length && (next = t[index++]) == null);
    }
    return e;
}

带有空主体的do/while循环一个接一个地遍历桶,寻找下一个条目。

唯一可能与此相关的情况是,当您迭代一个预先分配有大量存储桶但尚未填充大量项目的哈希集时。当您让 HashSet 随着您添加更多项目而自行增长时,存储桶的数量将与您迄今为止插入的项目数量成正比,因此减速不会很明显。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-19
    • 2011-02-11
    • 1970-01-01
    • 2011-09-08
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    相关资源
    最近更新 更多