LinkedList詳解及源碼分析

1.LinkedList概述:

LinkedList相較於ArrayList而言,ArrayList底層是維護了一個數組,而LinkedList是維護了一個雙向鏈表。所以在增刪元素時,LinkedList效率要略高,而隨機訪問時ArrayList效率則會略高。
在LinkedList中,所有對內部元素的操作都是基於雙向鏈表的需要來進行的,這裏會判斷操作元素的位置是靠近開頭還是結尾,之後我會解釋Node()方法 。同樣的,LinkedList也是不同步的。

2.LinkedList繼承實現體系:

在這裏插入圖片描述

這裏由於LinkedList實現了Queue接口,提供更豐富的操作方法,比如:offer()、peek()、poll()

3.LinkedList主要屬性介紹:

    //儲存元素的長度
    transient int size = 0;

    //第一個元素
    transient Node<E> first;

    //最後一個元素
    transient Node<E> last;

這裏的Node是LinkedList的靜態內部類,它就是實際維護的實體

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

Node類主要包括當前元素、前一個元素、後一個元素三個屬性,這就是雙向鏈表的體現形式

4.LinkedList的構造方法:

    public LinkedList() {
    
     }

    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

這裏我們主要說一下addALL()方法:

 public boolean addAll(int index, Collection<? extends E> c) {
 	//首先,檢查插入位置是否合法
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;
	
	//獲取插入位置的前一個node跟後一個node
        Node<E> pred, succ;
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }

	//循環依次插入到指定位置
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

	//最後判斷插入的最後一個node是否爲鏈表中最後一個node
        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

	//長度增加
        size += numNew;
       //操作數增加1
        modCount++;
        return true;
    }

這裏主要就是通過對插入位置的前一個node與後一個node的修改來完成的,這裏指的注意的是Node(index)方法,它的作用就是得到指定位置的node

 Node<E> node(int 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;
        }
    }

size>>1=size/2,查找時,通過判斷查找索引與size/2的大小來決定是從頭開始查找還是從尾開始查找。通過解析這個方法,我們可以看出當查找元素時,爲什麼LinkedList效率要略低於ArrayList了。

5.LinkedList的操作方法:

add(E e): 將指定node添加到此鏈表的結尾。

public boolean add(E e) {
    addBefore(e, header);
        return true;
    }

這裏調用了addBefore方法,它是LinkedList的私有方法。

private Entry<E> addBefore(E e, Entry<E> entry) {
        //利用Entry構造函數構建一個新節點 newEntry,
        Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
        //修改newEntry的前後節點的引用,確保其鏈表的引用關係是正確的
        newEntry.previous.next = newEntry;
        newEntry.next.previous = newEntry;
        //容量+1
        size++;
        //修改次數+1
        modCount++;
        return newEntry;

}

add(E e)無非就是做了2件事:構建一個新節點newEntry,然後修改其前後的引用。

其他的操作元素的方法也是大同小異,並不複雜,大家可以自行閱讀,我就不一一例舉了。

對於LinkedList來說,最重要的就是理解它的數據結構是一個雙向鏈表,所有對該鏈表的操作都是對於裏面Node的修改前後引用來完成的,對於有數據結構基礎的同學來說,這應該不難理解。

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