1. 程式人生 > >LinkedList的原始碼分析(基於jdk1.8)

LinkedList的原始碼分析(基於jdk1.8)

1.初始化

public LinkedList() {
}

並未開闢任何類似於陣列一樣的儲存空間,那麼連結串列是如何儲存元素的呢?

 

2.Node型別

儲存到連結串列中的元素會被封裝為一個Node型別的結點。並且連結串列只需記錄第一個結點的位置和最後一個結點的位置。然後每一個結點,前後連線,就可以串起來變成一整個連結串列。

transient Node<E> first;//指向連結串列的第一個結點

transient Node<E> last;//指向連結串列的最後一個結點
   
//LinkedList中有一個內部類Node型別
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; } }

 

3.新增元素

public boolean add(E e) {
    //預設連結到連結串列末尾
linkLast(e); return true; } void linkLast(E e) { //用l記錄當前連結串列的最後一個結點物件 final Node<E> l = last; //建立一個新結點物件,並且指定當前新結點的前一個結點為l final Node<E> newNode = new Node<>(l, e, null); //當前新結點就變成了連結串列的最後一個結點 last = newNode; if (l == null)      //如果當前連結串列是空的,那麼新結點物件,同時也是連結串列的第一個結點
first = newNode; else //如果當前連結串列不是空的,那麼最後一個結點的next就指向當前新結點 l.next = newNode; //元素個數增加 size++; //修改次數增加 modCount++; }

 

 

4.刪除元素

public boolean remove(Object o) {
   //分o是否是null討論,從頭到尾找到要刪除的元素o對應的Node結點物件,然後刪除
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}
E unlink(Node
<E> x) { final E element = x.item; //用next記錄被刪除結點的後一個結點 final Node<E> next = x.next; //用prev記錄被刪除結點的前一個結點 final Node<E> prev = x.prev; if (prev == null) { //如果刪除的是第一個結點,那麼被刪除的結點的後一個結點將成為第一個結點 first = next; } else { //否則被刪除結點的前一個結點的next應該指向被刪除結點的後一個結點 prev.next = next; //斷開被刪除結點與前一個結點的關係 x.prev = null; } if (next == null) { //如果刪除的是最後一個結點,那麼被刪除結點的前一個結點將變成最後一個結點 last = prev; } else { //否則被刪除結點的後一個結點的prev應該指向被刪除結點的額前一個結點 next.prev = prev; //斷開被刪除結點與後一個結點的關係 x.next = null; } //徹底把被刪除結點變成垃圾物件 x.item = null; //元素個數減少 size--; //修改次數增加 modCount++; return element; }

 

 5.指定位置插入元素

public void add(int index, E element) {
    //檢查索引位置的合理性
    checkPositionIndex(index);

    if (index == size)
        //如果位置是在最後,那麼連結到連結串列的最後
        linkLast(element);
    else
        //否則在連結串列中間插入
        //node(index)表示找到index位置的Node物件
        linkBefore(element, node(index));
}
void linkBefore(E e, Node<E> succ) { // pred記錄被插入位置的前一個結點 final Node<E> pred = succ.prev; //構建一個新結點 final Node<E> newNode = new Node<>(pred, e, succ); //把新結點插入到succ的前面 succ.prev = newNode; //如果被插入點是連結串列的開頭,那麼新結點變成了連結串列頭 if (pred == null) first = newNode; else //否則pred的next就變成了新結點 pred.next = newNode;
//元素個數增加 size++; //修改次數增加 modCount++; }

 

 6.總結

對於頻繁的插入或刪除元素的操作,建議使用LinkedList類,效率較高。因為不涉及到移動元素,只需要修改前後結點的關係。也不需要涉及到擴容

此類雖然提供按照索引查詢與操作的方法,但是效率不高,如果需要按索引操作,那麼建議使用動態陣列