让我们仔细阅读一下代码。该方法
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()。
重要的是该
contains方法是在 另一个 方法上调用的
Collection,因此复杂度取决于 另一个 方法的复杂度
Collection
contains。
因此,虽然:
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));
然后,由于
O(n)
contains在
Arrays.ArrayList此将成为
O(a.length *b.length)-即通过花费
O(n)的阵列复制到
HashSet您实际拨打电话来
retainAll要快得多。
就空间复杂度而言,不需要任何额外的空间(
Iterator)
retainAll,但是在您分配两个
HashSet实际上完全成熟的新实现时,从空间角度来说,您的调用实际上是相当昂贵的
HashMap。
还可以注意两点:
- 没有理由
HashSet
从中的元素分配a
- 可以使用也O(1)
从中间删除的便宜集合linkedList
。(更便宜的内存以及建立时间-不会建立哈希表) - 创建新的集合实例并仅返回时,所做的修改会丢失
b.size()
。



