JAVA集合框架--比較ArrayList和LinkedList區別(從源碼的角度)

今天有羣裏一個哥兒問面試官問他ArrayList和LinkedList區別,和適用場景,仔細想了一下如果自己去面試自己應該會從下面這幾個方面去回答一下

1:ArrayList和ListedList都是list的實現類(其實還有Vector和它的子類stack(同步效率底很少使用了)),

ArrayList和LinkedList都不是線程安全的,而vector是線程安全的這個算是兩者的相同之處吧

2:底層方面來說,ArrayList是用動態數組來實現的,LinkList是用鏈表來實現的

3:對於隨機訪問get()和set()方法-(相當於改查),ArrayList的效率要比linkList的效率好一點(linkList要移動指針啦,這個老鐵們應該理解吧).

4:對於add()和remove()方法

   4.1:.arrayList耗時主要在arraycopy這個函數上了函數覆蓋方式實現,增加的時候,函數後移,index空缺插入,刪除的時候,後面依次後移,刪除末尾.

    4.2 linkList主要耗時間在查找index位置上了,當index位置靠後,數量又大的時候,效率就低於arrrlist

二:看源碼

      2.1:我們在Eclipse中打開下ArrayList源碼(搜索下get關鍵字,剩下的方法你會發現是連這的)

  //隨機訪問查詢調用這個方法
  public E get(int index) {
	  //判斷index是否越界
        rangeCheck(index);

        return elementData(index);
    }
    //修改調用
	   public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
    //增加
	  public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
		//其實add方法增加最耗時間的在這,我們需要index後面的元素往後移
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
		//然後在index處插入元素
        elementData[index] = element;
        size++;
    }
   //刪除
   public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
	 // 刪除也是同樣的道理,這裏我就不多比比了(覆蓋index出元素位置,多出的一位刪掉)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }


2.2: 我們在打開下LinkedList源碼(搜索下get關鍵字,很巧你會發現也是連這的)

   //查
  public E get(int index) {
        checkElementIndex(index);
   //查的時候這個玩意最費時間,我們看下node方法點進去.
        return node(index).item;
    }
	//修改
   public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }
    //增
   public void add(int index, E element) {
        checkPositionIndex(index);


        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
     }
     //刪
   public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }


  //查找第index元素,我們通過for循環遍歷,(java開發人員牛逼的優化了一下,看if)
 Node<E> node(int index) {
        // assert isElementIndex(index);
   //小於1/2時候,從頭開始找,否者從尾(不得不說很牛逼,
   //但還是查改的時候不比ArrayList快,人家直接是直接返回index元素)
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
	//增加的時候我們遍歷indx的位置然後添加,問題就出現在這,看是遍歷更消耗時間,還是ArraLIst更消耗時間了
	 void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }

三:給個驗證例子吧(源碼說是這個理,但實踐是檢驗真理的唯一標準)

package com.vvut;

import java.util.ArrayList;    
import java.util.Collections;    
import java.util.LinkedList;    
import java.util.List; 

public class Test {
	
	static List<Integer> array=new ArrayList<Integer>();    
    static List<Integer> linked=new LinkedList<Integer>();    
    public static void main(String[] args) {    
    
        //首先分別給兩者插入5000條數據  
        for(int i=0;i<5000;i++){    
            array.add(i);    
            linked.add(i);    
        }    
        //獲得兩者隨機訪問的時間  
        System.out.println("array time:"+getTime(array));    
        System.out.println("linked time:"+getTime(linked));    
        //獲得兩者插入數據的時間  
        System.out.println("array insert time:"+insertTime(array));    
        System.out.println("linked insert time:"+insertTime(linked));    
    
    }    
    public static long getTime(List<Integer> list){    
        long time=System.currentTimeMillis();    
        for(int i = 0; i < 5000; i++){ 
        	//進行查找。若數組中存在要查找的元素,則返回改地址,若不存在,則返回比查找元素小的數組元素的地址加一個負號。(從1開始)
            int index = Collections.binarySearch(list, list.get(i));    
            if(index != i){    
                System.out.println("ERROR!");    
            }    
        }    
        return System.currentTimeMillis()-time;    
    }    
      
    //插入數據  
    public static long insertTime(List<Integer> list){   
        /* 
         * 插入的數據量和插入的位置是決定兩者性能的主要方面, 
         * 我們可以通過修改這兩個數據,來測試兩者的性能 
         */  
        long num = 5000; //表示要插入的數據量  
        
        int index=1000;//
        //int index = 5000; //表示從哪個位置插入   2/1
        //array insert time:56
       // linked insert time:125
        
        long time=System.currentTimeMillis();    
        for(int i = 1; i < num; i++){    
            list.add(index, i);       
        }    
        return System.currentTimeMillis()-time;    
            
    }    
}

三: 結果截圖

      3.1  當插入元素位置很前面的時候LinkedList比ArraList牛逼



3.2:當插入元素位置1/5的時候,兩個都差不多,


3.3: 當插入元素位置最後的時候,ArrayList翻身農奴把歌唱啦,比LinkList牛逼



四:結果分析:

     我們發現當插的位置越來越後的時候,Linklist越來越差,當時候就這樣給面試官說,當插入的數據在容量靠前面的時候.linkedList牛逼(牛逼這個詞到時候不說,我們談效率,顯的高雅),1/5,兩個貨都一樣,插入位置後面的時候,ArrayList牛逼,我們在平常使用的時候,用ArrayList多一點(這個看具體的情況)








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