LinkedList源碼分析

1.概述

高效插入和刪除的有序序列
線程不安全,非同步
數據結構:鏈表(雙向鏈表)
繼承了AbstractSequentialList,可以作爲棧和隊列使用
實現了Deque,可以做雙向鏈表
遍歷時推薦使用iterater

關係圖:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

2.源碼

常用屬性:
// 元素個數
transient int size = 0;
// 頭節點
transient Node<E> first;
//尾節點
transient Node<E> last;


// 記錄修改次數,與線程有關的屬性(平時使用並不多)
protected transient int modCount = 0;
常用構造方法:
// 默認構造方法
public LinkedList() {}

// 指定添加元素,並不常用
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}
核心內部類:
/**
 * 鏈表的數據結構
 */
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;
    }
}
/**
 * 主要與LinkedList的迭代有關
 * 而且在迭代的過程中能對元素進行操作
 */
private class ListItr implements ListIterator<E> {
    private Node<E> lastReturned = null;
    private Node<E> next;
    private int nextIndex;
    private int expectedModCount = modCount;
    
    // methods()....
}
核心方法:
/**
 * 添加元素到鏈表尾部
 */
public boolean add(E e) {
    // 實際添加到末尾
    linkLast(e);
    return true;
}

/**
 * Links e as last element.
 */
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++;
}
// ---------

重點看一下刪除元素的過程

/**
 * Removes the first occurrence of the specified element from this list
 * 移除鏈表第一個匹配的元素
 */
public boolean remove(Object o) {
    // 遍歷鏈表,找到符合的結點,再使用unlink真正移除該結點
    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;
            }
        }
    }
    // 沒找到則返回 false
    return false;
}

/**
 * Unlinks non-null node x.
 */
E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    // 移除頭結點,頭結點改變成頭結點的next
    if (prev == null) {
        first = next;
    } else {
        // 移除中間結點的一半引用(指針)操作(這個操作自己畫一張圖看起來更加直觀)
        prev.next = next;
        x.prev = null;
    }

    // 移除尾結點,尾結點改變爲尾結點的pre
    if (next == null) {
        last = prev;
    } else {
        // 移除中間結點的另一半引用(指針)操作
        next.prev = prev;
        x.next = null;
    }

    // 前面的prev和next的引用都清除了,現在清楚數據域的引用
    x.item = null;
    size--;
    modCount++;
    return element;
}

上面這些方法中,重點學習unlinck(),在指定位置插入也是相似的。

參考

Java集合源碼分析(二)Linkedlist
原文:LinkedList源碼分析

可以看一下我用Java寫的線性表的鏈式實現

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