[英]Performance of calculating Java Collection difference or intersection
Java允许通过Collection接口的removeAll()
和retainAll()
方法来计算(设置理论上的)差和两个Collection对象的交集 。
这两个方法在Java 6的AbstractCollection类中的实现是
public boolean removeAll(Collection<?> c) { // Difference
boolean modified = false;
Iterator<?> e = iterator();
while (e.hasNext()) {
if (c.contains(e.next())) {
e.remove();
modified = true;
}
}
return modified;
}
public boolean retainAll(Collection<?> c) { // Intersection
boolean modified = false;
Iterator<E> e = iterator();
while (e.hasNext()) {
if (!c.contains(e.next())) {
e.remove();
modified = true;
}
}
return modified;
}
有什么方法可以更快地实现或执行上述(显然是昂贵的)操作?
例如,在计算差异或交集之前对Collection进行排序会带来整体性能提升吗?
对于这些操作,是否有Collections框架的任何类更可取(在性能方面)?
是的,有一种更快的方法。 您提供的代码针对e的每个元素在c中循环。 使用100个元素的两个数组,它将比较大约100,000个元素。
如果先对两个数组进行排序,则只需比较前两个元素。 这将进行数百次比较。 这将类似于合并排序。 不要做排序的集合的交集left
和right
:
function intersect(left, right)
var list result
while length(left) > 0 and length(right) > 0
if first(left) == first(right)
append first(left) to result
left = rest(left)
right = rest(right)
else if first(left) < first(right)
left = rest(left)
else
right = rest(right)
end while
return result
这些实现位于AbstractCollection
,因此它们非常通用,因为在此抽象级别上,对集合的了解很少,可用操作的数量非常有限。 仅考虑Collection
接口允许的内容,并且不了解任何有关收集类型及其实现细节的信息,很难做到更聪明。 排序是否有效取决于所讨论的集合的大小和类型,在此级别上代码无法得知。
阅读AbstractCollection
的javadoc:
要实现不可修改的集合,程序员只需扩展此类并为iterator [...]提供实现。
因此,我相信您应该检查如何为特定的类实现Iterator,以真正了解这些方法的性能。
有什么方法可以更快地实现或执行上述(显然是昂贵的)操作?
这些操作的实际成本多少取决于作为参数传递的集合如何实现contains()。 如果它是HashSet
,则contains
是一个常数(预期)时间操作,导致removeAll
或retainAll
在线性(预期)时间内完成。
排序会更昂贵。
而且,在Set
上完成set操作是最高效的,这是合理的,不是吗?
如果集合中的元素是枚举或密集整数,则可以使用EnumSet
或BitSet
获得更快的速度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.