add方法的时间比较:ArrayList,LinkedList,ArrayList(用一些值初始化)

时间:2013-12-06 14:46:36

标签: java performance list arraylist linked-list

我希望更多地了解数据结构及其实现(使用JAVA语言)。今天我写了一个测试来比较(时间比较)ADT列表的不同实现。具体来说,我比较了add方法,这是我的测试:

@Test
public void testTime() {
    long i = 10000000;
    long INITIALIZED_VALUE=5000000;
    List<Integer> arrayBasedList = new ArrayList<Integer>();
    List<Integer> linkedBasedList = new LinkedList<Integer>();
    List<Integer> arrayBasedInitialedSizeList = new ArrayList<Integer> (INITIALIZED_VALUE);

    long t1 = System.currentTimeMillis();
    for (int index = 0; index <= i; index++) {
        arrayBasedList.add(index);
    }
    long t1End = System.currentTimeMillis() - t1;

    long t2 = System.currentTimeMillis();

    for (int index = 0; index <= i; index++) {
        linkedBasedList.add(index);
    }
    long t2End = System.currentTimeMillis() - t2;

    long t3 = System.currentTimeMillis();
    for (int index = 0; index <= i; index++) {
        arrayBasedInitialedSizeList.add(index);
    }
    long t3End = System.currentTimeMillis() - t3;

    System.out.println("ArrayBased: " + t1End);
    System.out.println("LinkedList:" + t2End);
    System.out.println("ArrayBasedInitializedSize: " + t3End);

    System.out.println("End");
}

我得到了这个结果:

  

ArrayBased:5681 LinkedList:12830 ArrayBasedInitializedSize:858

为什么LinkedList比ArrayList实现慢?我认为对于LinkedList实现,add方法比为Array实现添加方法更快。

任何人都可以解释为什么数组比addlist的linkedlist更快?

由于

Alessio的

3 个答案:

答案 0 :(得分:4)

这里有两件事。

首先是你的时间不可靠,因为你没有在每次运行之前“预热”代码。 Java在运行时优化和编译代码,因此通过它的前几次比以后运行要慢得多。你应该通过你的测试循环几百次,扔掉那些结果,然后做时间。

回答这个问题:

无论列表有多长,

LinkedList都是固定时间,但每次添加它都需要做更多的工作。它需要创建包装器对象,将其插入列表,更新引用等。

另一方面,ArrayList只是在数组中设置一个值,然后递增大小计数器。只有当它需要重新分配数组时才需要做很多工作。

测试在开始时添加新对象并比较结果,然后你会发现事情更多地回到链接列表中,因为现在ArrayList需要每次都重新调整所有值。

重新分配数组的成本也通过第三次测试来说明,通过事先了解大小,ArrayList变得更加高效。

在讨论算法时,Big O表示法很有用,但您需要了解它实际意味着什么,或者它可能会产生误导。它谈论的是操作顺序,而不是它实际需要多长时间。对于大多数追加插入,ArrayListLinkedList都是O(1),如果需要重新分配,ArrayList插入是O(n)。

所有O(1)都表示,无论列表中有多少个对象,它仍然需要相同的时间。在10个项目列表的末尾添加一些内容,100个项目列表,10000个项目列表,它仍然需要相同的时间。

LinkedList虽然比ArrayList花费的时间更多 - 即使它们仍然具有相同的O(1)顺序。

实际上速度差异是这样的,即使你看到列表的开头添加了LinkedList是O(1)而ArrayList是O(n),对于小型列表,ArrayList仍然更快!

为了给出一些想法(这只是一个例子,不要试图从中获取精确的时间!)然后如果为LinkedList添加的时间是L并且ArrayList的时间是A则那么总数最后添加的时间是L * 1,A * 1。要在开始时添加L * 1,A * N。

所以如果L / A&lt; N然后使用ArrayList实际上更快,即使只是查看O特性,您可能认为使用LinkedList会更好。

(如果你需要随机访问读取,链接列表也是O(n),这也是一个很重要的因素。)

答案 1 :(得分:1)

简而言之:在ArrayList上添加操作比在LinkedList上更快,因为它涉及(读取,写入,更新)更少的内存位置:

  • ArrayList:更新int size字段,阅读Object[] elements字段,阅读elements.length,在索引处写入elements

  • LinkedList:更新int size字段,更新Entry tail字段,分配新Entry,写入新条目的prevelement字段,写tail.next字段。

更精确的时间安排:

@GenerateMicroBenchmark
public int arrayList_add() {
    List<Object> list = new ArrayList<>(1000);
    Object x = new Object();
    for (int i = 0; i < 1000; i++) {
        list.add(x);
    }
    return list.size();
}

@GenerateMicroBenchmark
public int linkedList_add() {
    List<Object> list = new LinkedList<>();
    Object x = new Object();
    for (int i = 0; i < 1000; i++) {
        list.add(x);
    }
    return list.size();

结果:

Benchmark             Mean   Mean error    Units
arrayList_add        5,234        0,019  usec/op
linkedList_add       6,417        0,032  usec/op

答案 2 :(得分:0)

我对您的结果感到惊讶,并试图自己运行您的代码。这是我的输出:

ArrayBased: 5589
LinkedList:1219
ArrayBasedInitializedSize: 789
End

我认为,LinkedList的add方法应该比ArrayList慢一点(两个都是O(1),但具有不同的常量)。它们都创建新的Integer对象,而ArrayList只是将它们放在数组中,而LinkedList则创建链接。

ArrayBased和ArrayBasedInitializedSize之间的区别很明显:数组重新分配和元素复制需要花费太多时间。