1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。 2.對於隨機訪問get和set,ArrayList優於LinkedList,由於ArrayList能夠隨機定位,而LinkedList要移動指針一步一步的移動到節點處。(參考數組與鏈表來思考) 3.對於新增和刪除操做add和remove,LinedList比較佔優點,只須要對指針進行修改便可,而ArrayList要移動數據來填補被刪除的對象的空間。javascript
ArrayList和LinkedList是兩個集合類,用於存儲一系列的對象引用(references)。例如咱們能夠用ArrayList來存儲一系列的String或者Integer。那麼ArrayList和LinkedList在性能上有什麼差異呢?何時應該用ArrayList何時又該用LinkedList呢?java
一.時間複雜度算法
首先一點關鍵的是,ArrayList的內部實現是基於基礎的對象數組的,所以,它使用get方法訪問列表中的任意一個元素時(random-access),它的速度要比LinkedList快。LinkedList中的get方法是按照順序從列表的一端開始檢查,直到另一端。對LinkedList而言,訪問列表中的某個指定元素沒有更快的方法了。編程
假設咱們有一個很大的列表,它裏面的元素已經排好序了,這個列表多是ArrayList類型的也多是LinkedList類型的,如今咱們對這個列表來進行二分查找(binary search),比較列表是ArrayList和LinkedList時的查詢速度,看下面的程序:數組
package com.mangocity.test; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; public class TestList ...{ public static final int N=50000; public static List values; static...{ Integer vals[]=new Integer[N]; Random r=new Random(); for(int i=0,currval=0;i<N;i++)...{ vals=new Integer(currval); currval+=r.nextInt(100)+1; } values=Arrays.asList(vals); } static long timeList(List lst)...{ long start=System.currentTimeMillis(); for(int i=0;i<N;i++)...{ int index=Collections.binarySearch(lst, values.get(i)); if(index!=i) System.out.println("***錯誤***"); } return System.currentTimeMillis()-start; } public static void main(String args[])...{ System.out.println("ArrayList消耗時間:"+timeList(new ArrayList(values))); System.out.println("LinkedList消耗時間:"+timeList(new LinkedList(values))); } }
我獲得的輸出是:ArrayList消耗時間:15數據結構
LinkedList消耗時間:2596dom
這個結果不是固定的,可是基本上ArrayList的時間要明顯小於LinkedList的時間。所以在這種狀況下不宜用LinkedList。二分查找法使用的隨機訪問(randomaccess)策略,而LinkedList是不支持快速的隨機訪問的。對一個LinkedList作隨機訪問所消耗的時間與這個list的大小是成比例的。而相應的,在ArrayList中進行隨機訪問所消耗的時間是固定的。函數
這是否代表ArrayList老是比LinkedList性能要好呢?這並不必定,在某些狀況下LinkedList的表現要優於ArrayList,有些算法在LinkedList中實現時效率更高。比方說,利用Collections.reverse方法對列表進行反轉時,其性能就要好些。性能
看這樣一個例子,假如咱們有一個列表,要對其進行大量的插入和刪除操做,在這種狀況下LinkedList就是一個較好的選擇。請看以下一個極端的例子,咱們重複的在一個列表的開端插入一個元素:spa
package com.mangocity.test; import java.util.*; public class ListDemo { static final int N=50000; static long timeList(List list){ long start=System.currentTimeMillis(); Object o = new Object(); for(int i=0;i<N;i++) list.add(0, o); return System.currentTimeMillis()-start; } public static void main(String[] args) { System.out.println("ArrayList耗時:"+timeList(new ArrayList())); System.out.println("LinkedList耗時:"+timeList(new LinkedList())); } }
這時個人輸出結果是:ArrayList耗時:2463
LinkedList耗時:15
這和前面一個例子的結果截然相反,當一個元素被加到ArrayList的最開端時,全部已經存在的元素都會後移,這就意味着數據移動和複製上的開銷。相反的,將一個元素加到LinkedList的最開端只是簡單的爲這個元素分配一個記錄,而後調整兩個鏈接。在LinkedList的開端增長一個元素的開銷是固定的,而在ArrayList的開端增長一個元素的開銷是與ArrayList的大小成比例的。
二.空間複雜度
在LinkedList中有一個私有的內部類,定義以下:
private static class Entry { Object element; Entry next; Entry previous; }
每一個Entry對象reference列表中的一個元素,同時還有在LinkedList中它的上一個元素和下一個元素。一個有1000個元素的LinkedList對象將有1000個連接在一塊兒的Entry對象,每一個對象都對應於列表中的一個元素。這樣的話,在一個LinkedList結構中將有一個很大的空間開銷,由於它要存儲這1000個Entity對象的相關信息。
ArrayList使用一個內置的數組來存儲元素,這個數組的起始容量是10.當數組須要增加時,新的容量按以下公式得到:新容量=(舊容量*3)/2+1,也就是說每一次容量大概會增加50%。這就意味着,若是你有一個包含大量元素的ArrayList對象,那麼最終將有很大的空間會被浪費掉,這個浪費是由ArrayList的工做方式自己形成的。若是沒有足夠的空間來存放新的元素,數組將不得不被從新進行分配以便可以增長新的元素。對數組進行從新分配,將會致使性能急劇降低。若是咱們知道一個ArrayList將會有多少個元素,咱們能夠經過構造方法來指定容量。咱們還能夠經過trimToSize方法在ArrayList分配完畢以後去掉浪費掉的空間。
三.總結
ArrayList和LinkedList在性能上各有優缺點,都有各自所適用的地方,總的說來能夠描述以下:
性能總結:
- | add()操做 | delete()操做 | insert操做 | index取值操做 | iterator取值操做 |
---|---|---|---|---|---|
ArrayList/Vector/Stack | 好 | 差 | 差 | 極優 | 極優 |
LinkedList | 好 | 好 | 好 | 差 | 極優 |
1.對ArrayList和LinkedList而言,在列表末尾增長一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部數組中增長一項,指向所添加的元素,偶爾可能會致使對數組從新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry對象。
2.在ArrayList的中間插入或刪除一個元素意味着這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
3.LinkedList不支持高效的隨機元素訪問。
4.ArrayList的空間浪費主要體如今在list列表的結尾預留必定的容量空間,而LinkedList的空間花費則體如今它的每個元素都須要消耗至關的空間
能夠這樣說:當操做是在一列數據的後面添加數據而不是在前面或中間,而且須要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操做是在一列數據的前面或中間添加或刪除數據,而且按照順序訪問其中的元素時,就應該使用LinkedList了。
Java中ArrayList 、List區別
List集合 List繼承自Collection接口。List是一種有序集合,List中的元素能夠根據索引(順序號:元素在集合中處於的位置信息)進行取得/刪除/插入操做。
跟Set集合不一樣的是,List容許有重複元素。對於知足e1.equals(e2)條件的e1與e2對象元素,能夠同時存在於List集合中。固然,也有List的實現類不容許重複元素的存在。 同時,List還提供一個listIterator()方法,返回一個ListIterator接口對象,和Iterator接口相比,ListIterator添加元素的添加,刪除,和設定等方法,還能向前或向後遍歷。
List跟Collection的關係: java.util.Collection [I] +--java.util.List [I] +--java.util.ArrayList [C] +--java.util.LinkedList [C] +--java.util.Vector [C] +--java.util.Stack [C]
List接口的實現類主要有ArrayList,LinkedList,Vector,Stack等。
父子關係. List是一個接口,ArrayList繼承與這個接口並實現了它. 用的時候通常都用ArrayList.沒用過List. 能夠這麼用:List list = new ArrayList();
Collection接口 Collection是最基本的集合接口,一個Collection表明一組Object,即Collection的元素(Elements)。一些Collection容許相同的元素而另外一些不行。一些能排序而另外一些不行。Java SDK不提供直接繼承自Collection的類,JavaSDK提供的類都是繼承自Collection的「子接口」如List和Set。 全部實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用於建立一個空的Collection,有一個Collection參數的構造函數用於建立一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。後一個構造函數容許用戶複製一個Collection。
如何遍歷Collection中的每個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子便可逐一訪問Collection中每個元素。典型的用法以下: Iterator it = collection.iterator(); // 得到一個迭代子 while(it.hasNext()) { Object obj = it.next(); // 獲得下一個元素 } 由Collection接口派生的兩個接口是List和Set。
List接口: List是有序的Collection,使用此接口可以精確的控制每一個元素插入的位置。用戶可以使用索引(元素在List中的位置,相似於數組下標)來訪問List中的元素,這相似於Java的數組。 和下面要提到的Set不一樣,List容許有相同的元素。 除了具備Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,容許添加,刪除,設定元素,還能向前或向後遍歷。 實現List接口的經常使用類有LinkedList,ArrayList,Vector和Stack。
LinkedList類 LinkedList實現了List接口,容許null元素。此外LinkedList提供額外的get,remove,insert方法在LinkedList的首部或尾部。這些操做使LinkedList可被用做堆棧(stack),隊列(queue)或雙向隊列(deque)。 注意LinkedList沒有同步方法。若是多個線程同時訪問一個List,則必須本身實現訪問同步。一種解決方法是在建立List時構造一個同步的List: List list = Collections.synchronizedList(new LinkedList(...));
ArrayList類 ArrayList實現了可變大小的數組。它容許全部元素,包括null。ArrayList沒有同步。 size,isEmpty,get,set方法運行時間爲常數。可是add方法開銷爲分攤的常數,添加n個元素須要O(n)的時間。其餘的方法運行時間爲線性。 每一個ArrayList實例都有一個容量(Capacity),即用於存儲元素的數組的大小。這個容量可隨着不斷添加新元素而自動增長,可是增加算法並無定義。當須要插入大量元素時,在插入前能夠調用ensureCapacity方法來增長ArrayList的容量以提升插入效率。 和LinkedList同樣,ArrayList也是非同步的(unsynchronized)。
總結 若是涉及到堆棧,隊列等操做,應該考慮用List,對於須要快速插入,刪除元素,應該使用LinkedList,若是須要快速隨機訪問元素,應該使用ArrayList。 儘可能返回接口而非實際的類型,如返回List而非ArrayList,這樣若是之後須要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。