有没有一个时间复杂度为O(1)而不是O(n)的Java集合可用于addAll操作?还是我必须自己实现集合?使用高效的链表,Collection1.addAll(Collection2) 操作应该将第二个集合附加到第一个集合,将collection2的第一个节点添加到collection1的最后一个节点,其余节点依次跟随。但是,从文档中阅读到的并不是这样,似乎它使用了迭代器,所以我猜测其复杂度为O(collection2.size)。
这样对吗?
有没有一个时间复杂度为O(1)而不是O(n)的Java集合可用于addAll操作?还是我必须自己实现集合?使用高效的链表,Collection1.addAll(Collection2) 操作应该将第二个集合附加到第一个集合,将collection2的第一个节点添加到collection1的最后一个节点,其余节点依次跟随。但是,从文档中阅读到的并不是这样,似乎它使用了迭代器,所以我猜测其复杂度为O(collection2.size)。
这样对吗?
即使是对链表的优化也只能在将项目从一个链表移动到另一个链表时才能起作用。
但是,您可以构建一种具有更高间接性级别的集合,即包含一个集合的集合。这样,添加整个集合非常便宜,迭代也很便宜。然而,索引或长度确定可能会变得非常昂贵。
在这方面,ArrayList可能是最好的选择,但实际上它也取决于提供的集合。最优情况下的复杂度是O(1),但前提是提供的集合的toArray()
方法也具有常数复杂度。
执行实际分配的System.arrayCopy()调用无论如何都是O(1)很复杂,请参见下文:
// java.util.ArrayList.addAll
// Oracle JDK 1.8.0_91
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray(); // O(?) <-- depending on other type
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
关于System.arrayCopy
是否是常量时间操作存在一些争议。有人说不是。其他人则认为是。
根据我编写的基准测试,它处于中间水平。复制时间在大约100个数组项之前保持相当稳定,但从那时起呈线性增长,我猜测其中涉及某种分页。因此,实际上,除非数组很小,否则System.arrayCopy
具有线性时间复杂度。