编程语言
首页 > 编程语言> > 在Java中使用HashSets时,方法retainAll的时间和空间复杂度是多少?

在Java中使用HashSets时,方法retainAll的时间和空间复杂度是多少?

作者:互联网

例如,在下面的代码中:

public int commonTwo(String[] a, String[] b)
{
    Set common = new HashSet<String>(Arrays.asList(a));
    common.retainAll(new HashSet<String>(Arrays.asList(b)));
    return common.size();
} 

解决方法:

让我们在the code处进行细读.方法retainAll继承自AbstractCollection,并且(至少在OpenJDK中)如下所示:

public boolean retainAll(Collection<?> c) {
    boolean modified = false;
    Iterator<E> it = iterator();
    while (it.hasNext()) {
        if (!c.contains(it.next())) {
            it.remove();
            modified = true;
        }
    }
    return modified;
}

这里有一个很重要的注意事项,我们遍历this.iterator()并调用c.contains.所以时间复杂度是n次调用c.contains,其中n = this.size(),最多n次调用it.remove().

这个重要的是在另一个Collection上调用contains方法,因此复杂性取决于其他Collection包含的复杂性.

所以,同时:

Set<String> common = new HashSet<>(Arrays.asList(a));
common.retainAll(new HashSet<>(Arrays.asList(b)));

将是O(a.length),因为HashSet.contains和HashSet.remove都是O(1)(摊销).

如果你打电话

common.retainAll(Arrays.asList(b));

然后由于Arrays.ArrayList上的O(n)包含,这将变为O(a.length * b.length) – 即通过花费O(n)将数组复制到HashSet,您实际上更快地调用retainAll.

就空间复杂性而言,retainAll不需要额外的空间(超出Iterator),但是你的调用实际上是非常昂贵的,因为你分配了两个新的HashSet实现,它们实际上是完全成熟的HashMap.

还可以注意到另外两件事:

>没有理由从 – 中的元素中分配HashSet – 也可以使用从中间删除O(1)的更便宜的集合,例如LinkedList. (内存更便宜,也可以构建时间 – 不构建哈希表)
>在创建新的集合实例时,您的修改将丢失,并且仅返回b.size().

标签:java,big-o,hashset
来源: https://codeday.me/bug/20190927/1823569.html