我看了THIS和
并了解LinkedList add(E元素)是O(1) 和ArrayList add(E元素)是O(1)分摊的,但O(n)最坏情况,因为数组必须调整大小并复制
但是,当我尝试检查时
public class ArrayListVSLinkeedList {
public ArrayListVSLinkeedList() {
final int COUNTER = 15000000;
List<Integer> arrayList = new ArrayList<Integer>();
long tStart_add = System.currentTimeMillis();
for (int i = 0; i < COUNTER; i++) {
arrayList.add(i);
}
long tEnd_add = System.currentTimeMillis();
long tDelta_add = tEnd_add - tStart_add;
System.out.println("Adding to ArrayList: " +tDelta_add);
List<Integer> linkedList = new LinkedList<Integer>();
tStart_add = System.currentTimeMillis();
for (int i = 0; i < COUNTER; i++) {
linkedList.add(i);
}
tEnd_add = System.currentTimeMillis();
tDelta_add = tEnd_add - tStart_add;
System.out.println("Adding to LinkedList: " +tDelta_add);
}
public static void main(String[] args) {
new ArrayListVSLinkeedList();
}
}
我收到了输出:
添加到 ArrayList : 9122
添加到 LinkedList : 19859
我知道,这不是真正的基准,但...... 最后,将元素添加到ArrayList的末尾比使用LinkedList更快。为什么会这样?
答案 0 :(得分:5)
这仅仅是由于实施。
查看ArrayList.add
:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ArrayList
内部包含一个数组,其元素是对您使用该列表管理的对象的引用。方法ensureCapacityInternal
只是检查这个内部数组是否仍然足够大以添加另一个元素。
如果是,则添加元素并返回方法。这非常快(而且 - 顺便说一下 - 是O(1))。
如果数组已满,则将分配具有更大大小的新数组,每个引用将从旧数组复制到新数组。之后,将添加元素。这当然是O(n)。但这种情况很少发生,并且由于调整大小的策略(尺寸加倍),它将变得越来越少。
另一方面,我们来看看LinkedList.add
:
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
在这里,您可以看到,对于每个添加的元素,必须创建一个新的节点对象,然后将其添加为最后一个元素。没有进行大小调整,因此该方法始终为O(1),但创建节点对象比仅存储引用需要更多时间。
答案 1 :(得分:0)
嗯,这取决于你在机器上有多少内存,认为你正在创建的ArrayList已经在内存中,而LinkedList必须分配新的内存。尝试以相反的方式运行它并查看结果。
更好的是 - 尝试在不同的方法中运行它们并看到一个公平的结果。