簡體   English   中英

添加方法的時間比較:ArrayList,LinkedList,ArrayList(使用某些值初始化)

[英]Time comparison of add method for: ArrayList, LinkedList, ArrayList (initialized with some value)

我希望更多地了解數據結構及其實現(使用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實現的add方法要快。

任何人都可以解釋一下為什么add方法的數組比鏈表更快?

謝謝

阿萊西奧

這里有兩件事。

首先是您的計時不可靠,因為您沒有在每次運行之前“預熱”代碼。 Java在運行時會優化和編譯代碼,因此前幾次運行的速度比以后運行的速度慢得多。 您應該運行數百次測試循環,丟棄這些結果,然后進行計時。

但是要回答這個問題:

無論列表有多長, LinkedList都是恆定時間,但是每次添加LinkedList都需要做更多的工作。 它需要創建包裝對象,將其插入列表中,更新引用等。

另一方面, ArrayList只是在數組中設置一個值,然后增加大小計數器。 僅當它需要重新分配數組時,它才需要做很多工作。

進行測試,從頭開始添加新對象,然后比較結果,您會發現事情更多地轉向了鏈表,因為現在ArrayList每次都需要重新整理所有值。

通過第三個測試,通過提前知道ArrayList的大小變得更加高效,您也可以通過第三個測試來說明重新分配陣列的成本。

大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 <N,那么即使僅查看O特性,使用ArrayList的速度實際上也會更快,您可能會認為使用LinkedList會更好。

(如果您需要隨機訪問讀取,則鏈接列表也為O(n),這也是一個很大的因素)。

簡而言之:對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

我為您的結果感到驚訝,並嘗試自己運行您的代碼。 這是我的輸出:

ArrayBased: 5589
LinkedList:1219
ArrayBasedInitializedSize: 789
End

我認為,LinkedList的add方法應該比ArrayList慢一點(都是O(1),但常數不同)。 它們都創建新的Integer對象,而ArrayList只是將它們放在數組中,而LinkedList創建鏈接。

ArrayBased和ArrayBasedInitializedSize之間的區別是顯而易見的:數組重新分配和元素復制需要太多時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM