我的Java路上那些事兒

          快樂(lè)成長(zhǎng)
          posts - 110, comments - 101, trackbacks - 0, articles - 7
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          日歷

          <2012年11月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          搜索

          •  

          最新評(píng)論

          一般大家都知道ArrayList和LinkedList的大致區(qū)別:
               1.ArrayList是實(shí)現(xiàn)了基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)。
               2.對(duì)于隨機(jī)訪問(wèn)get和set,ArrayList覺(jué)得優(yōu)于LinkedList,因?yàn)長(zhǎng)inkedList要移動(dòng)指針。
               3.對(duì)于新增和刪除操作add和remove,LinedList比較占優(yōu)勢(shì),因?yàn)锳rrayList要移動(dòng)數(shù)據(jù)。

          ArrayList和LinkedList是兩個(gè)集合類,用于存儲(chǔ)一系列的對(duì)象引用(references)。例如我們可以用ArrayList來(lái)存儲(chǔ)一系列的String或者Integer。那么ArrayList和LinkedList在性能上有什么差別呢?什么時(shí)候應(yīng)該用ArrayList什么時(shí)候又該用LinkedList呢?


          一.時(shí)間復(fù)雜度
          首先一點(diǎn)關(guān)鍵的是,ArrayList的內(nèi)部實(shí)現(xiàn)是基于基礎(chǔ)的對(duì)象數(shù)組的,因此,它使用get方法訪問(wèn)列表中的任意一個(gè)元素時(shí)(random access),它的速度要比LinkedList快。LinkedList中的get方法是按照順序從列表的一端開(kāi)始檢查,直到另外一端。對(duì)LinkedList而言,訪問(wèn)列表中的某個(gè)指定元素沒(méi)有更快的方法了。
          假設(shè)我們有一個(gè)很大的列表,它里面的元素已經(jīng)排好序了,這個(gè)列表可能是ArrayList類型的也可能是LinkedList類型的,現(xiàn)在我們對(duì)這個(gè)列表來(lái)進(jìn)行二分查找(binary search),比較列表是ArrayList和LinkedList時(shí)的查詢速度,看下面的程序:

          Java代碼 復(fù)制代碼 收藏代碼
          1. package com.mangocity.test;    
          2. import java.util.LinkedList;    
          3. import java.util.List;    
          4. import java.util.Random;    
          5. import java.util.ArrayList;    
          6. import java.util.Arrays;    
          7. import java.util.Collections;    
          8. public class TestList ...{    
          9.      public static final int N=50000;    
          10.   
          11.      public static List values;    
          12.   
          13.      static...{    
          14.          Integer vals[]=new Integer[N];    
          15.   
          16.          Random r=new Random();    
          17.   
          18.          for(int i=0,currval=0;i<N;i++)...{    
          19.              vals=new Integer(currval);    
          20.              currval+=r.nextInt(100)+1;    
          21.          }    
          22.   
          23.          values=Arrays.asList(vals);    
          24.      }    
          25.   
          26.      static long timeList(List lst)...{    
          27.          long start=System.currentTimeMillis();    
          28.          for(int i=0;i<N;i++)...{    
          29.              int index=Collections.binarySearch(lst, values.get(i));    
          30.              if(index!=i)    
          31.                  System.out.println("***錯(cuò)誤***");    
          32.          }    
          33.          return System.currentTimeMillis()-start;    
          34.      }    
          35.      public static void main(String args[])...{    
          36.          System.out.println("ArrayList消耗時(shí)間:"+timeList(new ArrayList(values)));    
          37.          System.out.println("LinkedList消耗時(shí)間:"+timeList(new LinkedList(values)));    
          38.      }    
          39. }   

           
          我得到的輸出是:ArrayList消耗時(shí)間:15
                           LinkedList消耗時(shí)間:2596
          這個(gè)結(jié)果不是固定的,但是基本上ArrayList的時(shí)間要明顯小于LinkedList的時(shí)間。因此在這種情況下不宜用LinkedList。二分查找法使用的隨機(jī)訪問(wèn)(random access)策略,而LinkedList是不支持快速的隨機(jī)訪問(wèn)的。對(duì)一個(gè)LinkedList做隨機(jī)訪問(wèn)所消耗的時(shí)間與這個(gè)list的大小是成比例的。而相應(yīng)的,在ArrayList中進(jìn)行隨機(jī)訪問(wèn)所消耗的時(shí)間是固定的。
          這是否表明ArrayList總是比LinkedList性能要好呢?這并不一定,在某些情況下LinkedList的表現(xiàn)要優(yōu)于ArrayList,有些算法在LinkedList中實(shí)現(xiàn)時(shí)效率更高。比方說(shuō),利用Collections.reverse方法對(duì)列表進(jìn)行反轉(zhuǎn)時(shí),其性能就要好些。
          看這樣一個(gè)例子,加入我們有一個(gè)列表,要對(duì)其進(jìn)行大量的插入和刪除操作,在這種情況下LinkedList就是一個(gè)較好的選擇。請(qǐng)看如下一個(gè)極端的例子,我們重復(fù)的在一個(gè)列表的開(kāi)端插入一個(gè)元素:

          Java代碼 復(fù)制代碼 收藏代碼
          1. package com.mangocity.test;    
          2.   
          3. import java.util.*;    
          4. public class ListDemo {    
          5.      static final int N=50000;    
          6.      static long timeList(List list){    
          7.      long start=System.currentTimeMillis();    
          8.      Object o = new Object();    
          9.      for(int i=0;i<N;i++)    
          10.          list.add(0, o);    
          11.      return System.currentTimeMillis()-start;    
          12.      }    
          13.      public static void main(String[] args) {    
          14.          System.out.println("ArrayList耗時(shí):"+timeList(new ArrayList()));    
          15.          System.out.println("LinkedList耗時(shí):"+timeList(new LinkedList()));    
          16.      }    
          17. }   

           這時(shí)我的輸出結(jié)果是:ArrayList耗時(shí):2463

           


                                     LinkedList耗時(shí):15
          這和前面一個(gè)例子的結(jié)果截然相反,當(dāng)一個(gè)元素被加到ArrayList的最開(kāi)端時(shí),所有已經(jīng)存在的元素都會(huì)后移,這就意味著數(shù)據(jù)移動(dòng)和復(fù)制上的開(kāi)銷。相反的,將一個(gè)元素加到LinkedList的最開(kāi)端只是簡(jiǎn)單的未這個(gè)元素分配一個(gè)記錄,然后調(diào)整兩個(gè)連接。在LinkedList的開(kāi)端增加一個(gè)元素的開(kāi)銷是固定的,而在ArrayList的開(kāi)端增加一個(gè)元素的開(kāi)銷是與ArrayList的大小成比例的。


          二.空間復(fù)雜度
          在LinkedList中有一個(gè)私有的內(nèi)部類,定義如下:

          Java代碼 復(fù)制代碼 收藏代碼
          1. private static class Entry {    
          2.          Object element;    
          3.          Entry next;    
          4.          Entry previous;    
          5.      }   

           
          每個(gè)Entry對(duì)象reference列表中的一個(gè)元素,同時(shí)還有在LinkedList中它的上一個(gè)元素和下一個(gè)元素。一個(gè)有1000個(gè)元素的LinkedList對(duì)象將有1000個(gè)鏈接在一起的Entry對(duì)象,每個(gè)對(duì)象都對(duì)應(yīng)于列表中的一個(gè)元素。這樣的話,在一個(gè)LinkedList結(jié)構(gòu)中將有一個(gè)很大的空間開(kāi)銷,因?yàn)樗鎯?chǔ)這1000個(gè)Entity對(duì)象的相關(guān)信息。
          ArrayList使用一個(gè)內(nèi)置的數(shù)組來(lái)存儲(chǔ)元素,這個(gè)數(shù)組的起始容量是10.當(dāng)數(shù)組需要增長(zhǎng)時(shí),新的容量按如下公式獲得:新容量=(舊容量*3)/2+1,也就是說(shuō)每一次容量大概會(huì)增長(zhǎng)50%。這就意味著,如果你有一個(gè)包含大量元素的ArrayList對(duì)象,那么最終將有很大的空間會(huì)被浪費(fèi)掉,這個(gè)浪費(fèi)是由ArrayList的工作方式本身造成的。如果沒(méi)有足夠的空間來(lái)存放新的元素,數(shù)組將不得不被重新進(jìn)行分配以便能夠增加新的元素。對(duì)數(shù)組進(jìn)行重新分配,將會(huì)導(dǎo)致性能急劇下降。如果我們知道一個(gè)ArrayList將會(huì)有多少個(gè)元素,我們可以通過(guò)構(gòu)造方法來(lái)指定容量。我們還可以通過(guò)trimToSize方法在ArrayList分配完畢之后去掉浪費(fèi)掉的空間。


          三.總結(jié)
          ArrayList和LinkedList在性能上各有優(yōu)缺點(diǎn),都有各自所適用的地方,總的說(shuō)來(lái)可以描述如下:
          1.對(duì)ArrayList和LinkedList而言,在列表末尾增加一個(gè)元素所花的開(kāi)銷都是固定的。對(duì)ArrayList而言,主要是在內(nèi)部數(shù)組中增加一項(xiàng),指向所添加的元素,偶爾可能會(huì)導(dǎo)致對(duì)數(shù)組重新進(jìn)行分配;而對(duì)LinkedList而言,這個(gè)開(kāi)銷是統(tǒng)一的,分配一個(gè)內(nèi)部Entry對(duì)象。


          2.在ArrayList的中間插入或刪除一個(gè)元素意味著這個(gè)列表中剩余的元素都會(huì)被移動(dòng);而在LinkedList的中間插入或刪除一個(gè)元素的開(kāi)銷是固定的。


          3.LinkedList不支持高效的隨機(jī)元素訪問(wèn)。


          4.ArrayList的空間浪費(fèi)主要體現(xiàn)在在list列表的結(jié)尾預(yù)留一定的容量空間,而LinkedList的空間花費(fèi)則體現(xiàn)在它的每一個(gè)元素都需要消耗相當(dāng)?shù)目臻g


          可以這樣說(shuō):當(dāng)操作是在一列數(shù)據(jù)的后面添加數(shù)據(jù)而不是在前面或中間,并且需要隨機(jī)地訪問(wèn)其中的元素時(shí),使用ArrayList會(huì)提供比較好的性能;當(dāng)你的操作是在一列數(shù)據(jù)的前面或中間添加或刪除數(shù)據(jù),并且按照順序訪問(wèn)其中的元素時(shí),就應(yīng)該使用LinkedList了。

           


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 浮山县| 隆子县| 普陀区| 德阳市| 隆德县| 郯城县| 青铜峡市| 乐业县| 九江市| 革吉县| 郎溪县| 桐柏县| 桂东县| 自治县| 右玉县| 安徽省| 沾化县| 靖西县| 察雅县| 绵竹市| 樟树市| 大洼县| 河西区| 沙坪坝区| 五华县| 潜山县| 奈曼旗| 娱乐| 蓝山县| 巴彦淖尔市| 常州市| 通化市| 安宁市| 东乌珠穆沁旗| 庄河市| 陆丰市| 嘉峪关市| 济阳县| 咸宁市| 广汉市| 武山县|