【问题标题】:Java iterate on a TreeMap/TreeSet in O(N) and remove other elements than current oneJava 在 O(N) 中迭代 TreeMap/TreeSet 并删除当前元素以外的其他元素
【发布时间】:2019-05-15 18:05:40
【问题描述】:

有没有办法在 O(N) 中迭代 TreeSet/TreeMap,同时能够删除迭代器当前指向的条目之外的其他条目?

这是一个使用 TreeSet 的简单示例。该集合包含正整数,我检查是否可以创建 N/2 对,例如每对包含 [x, 2*x]。我从最低键遍历地图,检查我们是否找到双精度并在找到时将其删除。 需要说明的是,这个例子只是为了说明,我不需要为例子本身寻找解决方案,而是要知道我是否可以在迭代时移除。

 public boolean checkTree(TreeSet<Integer> tree){
        for (Integer i: tree) {
                int twice = i*2;
                if(!tree.contains(twice)) return false;
                else tree.remove(twice);
        }
        return true;
}

当然,如果我这样做,我会得到一个ConcurrentModificationException,因为我删除了一个元素而不使用iterator.remove()。但我不能使用该方法,因为我想删除其他元素。

这是我能想到的一种解决方法:

 public boolean checkTree(TreeSet<Integer> tree){
        while (tree.size() > 0) {
                int twice = tree.pollFirst()*2;
                if(!tree.contains(twice)) return false;
                else tree.remove(twice);
        }

        return true;
    }

但它会执行得更慢,因为调用 N 次 pollFirst() 是 O(N log N) 而不是 treeIterator 的 O(N)。由于 contains()remove() 调用,整体复杂性确实会保持不变。

有没有办法在使用中序遍历遍历树的同时删除? TreeMap 类中有一个 successor() 方法,但它不是公开的。 这个问题实际上可能适用于所有 NavigableSet/NavigableMap 。

【问题讨论】:

    标签: java binary-search-tree treemap treeset red-black-tree


    【解决方案1】:

    我能想到的解决方案:

    • 将集合的内容复制到列表中,在更改集合的同时迭代列表
    • 迭代集合,列出要移除的元素的列表(集合?),在单独的迭代中移除这些元素
    • 使用从不抛出 CME 的数据结构,例如ConcurrentSkipListSet,但请注意,对于这个迭代器可能返回的数据在迭代器的生命周期内已经被删除

    【讨论】:

    • 在这 3 个解决方案中,我将对已删除的数据进行迭代。
    • 可以加个if("already removed") continue;到循环的开始。
    • 注意:你的第一个例子是 O(N*log(N)) 无论如何,O(N) 用于外循环,log(N) 用于 contains()。
    • ConcurrentSkipListSet 实际上更模糊,它可能会也可能不会给你旧数据或它的某些子集。
    猜你喜欢
    • 1970-01-01
    • 2020-12-11
    • 2020-12-08
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多