Arraylist 與 LinkedList 異同

1. 是否保證線程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全;

2. 底層數據結構: Arraylist 底層使用的是Object數組;LinkedList 底層使用的是雙向鏈表數據結構(JDK1.6之前爲循環鏈表,JDK1.7取消了循環。注意雙向鏈表和雙向循環鏈表的區別);

3. 插入和刪除是否受元素位置的影響: ① ArrayList 採用數組存儲,所以插入和刪除元素的時間複雜度受元素位置的影響。 比如:執行add(E e) 方法的時候, ArrayList 會默認在將指定的元素追加到此列表的末尾,這種情況時間複雜度就是O(1)。但是如果要在指定位置 i 插入和刪除元素的話( add(int index, E element) )時間複雜度就爲 O(n-i)。因爲在進行上述操作的時候集合中第 i 和第 i 個元素之後的(n-i)個元素都要執行向後位/向前移一位的操作。 ② LinkedList 採用鏈表存儲,所以插入,刪除元素時間複雜度不受元素位置的影響,都是近似 O(1)而數組爲近似 O(n)。

4. 是否支持快速隨機訪問: LinkedList 不支持高效的隨機元素訪問,而 ArrayList 支持。快速隨機訪問就是通過元素的序號快速獲取元素對象(對應於get(int index) 方法)。

5. 內存空間佔用: ArrayList的空間浪費主要體現在在list列表的結尾會預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗比ArrayList更多的空間(因爲要存放直接後繼和直接前驅以及數據)。


補充內容:RandomAccess接口

public interface RandomAccess {
}

查看源碼我們發現實際上 RandomAccess 接口中什麼都沒有定義。所以,在我看來 RandomAccess 接口不過是一個標識罷了。標識什麼? 標識實現這個接口的類具有隨機訪問功能。

在binarySearch()方法中,它要判斷傳入的list 是否RamdomAccess的實例,如果是,調用 indexedBinarySearch()方法,如果不是,那麼調用iteratorBinarySearch()方法。

public static <T>
int binarySearch(List<? extends Comparable<? super T>> list, T key) {
    if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
        return Collections.indexedBinarySearch(list, key);
    else
        return Collections.iteratorBinarySearch(list, key);
}

ArrayList 實現了 RandomAccess 接口, 而 LinkedList 沒有實現。爲什麼呢?我覺得還是和底層數據結構有關!ArrayList 底層是數組,而 LinkedList 底層是鏈表。數組天然支持隨機訪問,時間複雜度爲 O(1),所以稱爲快速隨機訪問。鏈表需要遍歷到特定位置才能訪問特定位置的元素,時間複雜度爲 O(n),所以不支持快速隨機訪問。,ArrayList 實現了 RandomAccess 接口,就表明了他具有快速隨機訪問功能。 RandomAccess 接口只是標識,並不是說 ArrayList 實現 RandomAccess 接口才具有快速隨機訪問功能的!

下面再總結一下 list 的遍歷方式選擇:
實現了RandomAccess接口的list,優先選擇普通for循環 ,其次foreach,未實現RandomAccess接口的list, 優先選擇iterator遍歷(foreach遍歷底層也是通過iterator實現的),大size的數據,千萬不要使用普通for循環

補充:數據結構基礎之雙向鏈表
雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針,分別指向直接後繼和直接前驅。所以,從
雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。一般我們都構造雙向循環鏈表。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章