![](/img/trans.png)
[英]LinkedList vs ArrayList: get, add, remove performance comparison - unexpected results for add method
[英]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表示法在討論算法時很有用,但是您需要了解它的實際含義,否則可能會產生誤導。 它在談論操作的順序,而不是實際花費的時間。 對於大多數附加插入, ArrayList
和LinkedList
均為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
,寫入新條目的prev
和element
字段,寫入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.