LinkedList插入數據效率不一定比ArrayList高,源碼分析+實驗對比


(一)結論

  1. 在尾部插入數據,數據量較小時LinkedList比較快,因為ArrayList要頻繁擴容,當數據量大時ArrayList比較快,因為ArrayList擴容是當前容量*1.5,大容量擴容一次就能提供很多空間,當ArrayList不需擴容時效率明顯比LinkedList高,因為直接數組元素賦值不需new Node

  2. 在首部插入數據,LinkedList較快,因為LinkedList遍歷插入位置花費時間很小,而ArrayList需要將原數組所有元素進行一次System.arraycopy

  3. 插入位置越往中間,LinkedList效率越低,因為它遍歷獲取插入位置是從兩頭往中間搜,index越往中間遍歷越久,因此ArrayList的插入效率可能會比LinkedList高

  4. 插入位置越往后,ArrayList效率越高,因為數組需要復制后移的數據少了,那么System.arraycopy就快了,因此在首部插入數據LinkedList效率比ArrayList高,尾部插入數據ArrayList效率比LinkedList高

  5. LinkedList可以實現隊列,棧等數據結構,這是它的優勢

 

 

(二)在尾部插入數據

結論:當數據量越來越大時,ArrayList比LinkedList快

原因:當數據量大時,ArrayList每次擴容都能得到很大的新空間,解決了前期頻繁擴容的劣勢,而LinkedList雖然有尾指針,但是每次add都要將對象new成一個Node(而ArrayList直接數組對應位置元素賦值)

末尾插入源碼

ArrayList:如果超出容量需要擴容,不需擴容時直接數組元素賦值

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

LinkedList:用傳入的值new一個Node對象,然后尾指針指向該新的Node

    public void addLast(E e) {
        linkLast(e);
    }
    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

實驗對比

    public static void main(String[] argv) {
        LinkedList<Integer> linkedList = new LinkedList<Integer>();
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        Long start = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            linkedList.addLast(i);

        }
        Long end = System.nanoTime();
        System.out.println("LinkedList消耗時間:" + (end - start));

        start = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            arrayList.add(i);
        }
        end = System.nanoTime();
        System.out.println("ArrayList消耗時間:" + (end - start));
    }

 

(三)指定位置插入數據

(1)源碼對比

ArrayList:性能主要在於擴容和數組復制,而當size很大時擴容影響就會減少

  1. 判斷index是否合法
  2. 判斷是否需要擴容
  3. 數組復制,從index開始把后面的數組元素全部復制到相對后一位的位置,該方法是native方法而且是連續內存復制問題,因此性能影響也沒想象中的大
  4. 將element賦值給數組index元素
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

 

LinkedList:性能主要在於遍歷鏈表查找index

  1. 判斷是否超過鏈表長度,超過則拋錯誤
  2. 如果是插入最后的位置直接使用linkLast方法而不必去遍歷查詢對應位置
  3. node方法尋找index所指向的Node,首先判斷index是否大於size/2,大於則從末尾往前找,小於則從0開始往后找
  4. 找到之后就是new一個node對象,設置指針的問題
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

    Node<E> node(int index) {
        // assert isElementIndex(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;
        }
    }

    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++;
    }

(2)首部插入實驗對比

 

 結論:開頭插入,LinkedList比ArrayList快

(2)中間插入實驗對比

結論:中間插入LinkedList比ArrayList慢

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM