ArrayList、Vector、LinkedList的區別及其優缺點? (轉載)

原文連接:http://blog.csdn.net/wangzff/article/details/7296648java

 

 ArrayList,LinkedList,Vestor這三個類都實現了java.util.List接口,但它們有各自不一樣的特性,主要以下:

1、同步性

ArrayList,LinkedList是不一樣步的,而Vestor是同步的。因此若是不要求線程安全的話,可使用ArrayList或 LinkedList,能夠節省爲同步而耗費的開銷。但在多線程的狀況下,有時候就不得不使用Vector了。固然,也能夠經過一些辦法包裝 ArrayList,LinkedList,使他們也達到同步,但效率可能會有所下降。

2、數據增加
從內部實現機制來說ArrayList和Vector都是使用Objec的數組形式來存儲的。當你向這兩種類型中增長元素的時候,若是元素的數目超出了內 部數組目前的長度它們都須要擴展內部數組的長度,Vector缺省狀況下自動增加原來一倍的數組長度,ArrayList是原來的50%,因此最後你得到 的這個集合所佔的空間老是比你實際須要的要大。因此若是你要在集合中保存大量的數據那麼使用Vector有一些優點,由於你能夠經過設置集合的初始化大小 來避免沒必要要的資源開銷。

3、檢索、插入、刪除對象的效率

ArrayList和Vector中,從指定的位置(用index)檢索一個對象,或在集合的末尾插入、刪除一個對象的時間是同樣的,可表示爲O(1)。 可是,若是在集合的其餘位置增長或移除元素那麼花費的時間會呈線形增加:O(n-i),其中n表明集合中元素的個數,i表明元素增長或移除元素的索引位 置。爲何會這樣呢?覺得在進行上述操做的時候集合中第i和第i個元素以後的全部元素都要執行(n-i)個對象的位移操做。
LinkedList中,在插入、刪除集合中任何位置的元素所花費的時間都是同樣的—O(1),但它在索引一個元素的時候比較慢,爲O(i),其中i是索引的位置。算法

通常你們都知道ArrayList和LinkedList的大體區別:
     1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
     2.對於隨機訪問get和set,ArrayList以爲優於LinkedList,由於LinkedList要移動指針。
     3.對於新增和刪除操做add和remove,LinedList比較佔優點,由於ArrayList要移動數據。

ArrayList和LinkedList是兩個集合 類,用於存儲一系列的對象引用(references)。例如咱們能夠用ArrayList來存儲一系列的String或者Integer。那麼 ArrayList和LinkedList在性能上有什麼差異呢?何時應該用ArrayList何時又該用LinkedList呢?


一.時間復 雜度
首先一點關鍵的是,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[i]=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消耗時間:2596
這個結果不是固定的,可是基本上ArrayList的 時間要明顯小於LinkedList的時間。所以在這種狀況下不宜用LinkedList。二分查找法使用的隨機訪問(random access)策略,而LinkedList是不支持快速的隨機訪問的。對一個LinkedList作隨機訪問所消耗的時間與這個list的大小是成比例 的。而相應的,在ArrayList中進行隨機訪問所消耗的時間是固定的。
這是否代表ArrayList老是比LinkedList性能要好呢?這並不必定,在某些狀況 下LinkedList的表現要優於ArrayList,有些算法在LinkedList中實現時效率更高。比方說,利用 Collections.reverse方法對列表進行反轉時,其性能就要好些。
看這樣一個例子,加入咱們有一個列表,要對其進行大量的插入和刪除操做,在這種狀況下 LinkedList就是一個較好的選擇。請看以下一個極端的例子,咱們重複的在一個列表的開端插入一個元素:安全

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在性能上各 有優缺點,都有各自所適用的地方,總的說來能夠描述以下:
1.對ArrayList和LinkedList而言,在列表末尾增長一個元素所花的開銷都是固定的。對 ArrayList而言,主要是在內部數組中增長一項,指向所添加的元素,偶爾可能會致使對數組從新進行分配;而對LinkedList而言,這個開銷是 統一的,分配一個內部Entry對象。 多線程

 

2.在ArrayList的 中間插入或刪除一個元素意味着這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。


3.LinkedList不 支持高效的隨機元素訪問。


4.ArrayList的空 間浪費主要體如今在list列表的結尾預留必定的容量空間,而LinkedList的空間花費則體如今它的每個元素都須要消耗至關的空間


能夠這樣說:當操做是在一列 數據的後面添加數據而不是在前面或中間,而且須要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操做是在一列數據的前面或中 間添加或刪除數據,而且按照順序訪問其中的元素時,就應該使用LinkedList了。

因此,若是隻是查找特定位置的元素或只在集合的末端增長、移除元素,那麼使用Vector或ArrayList均可以。若是是對其它指定位置的插入、刪除操做,最好選擇LinkedListdom

相關文章
相關標籤/搜索