記一次LinkedList的源碼閱讀

                                  編碼如夢,望歸來還是老友。

 

LinkedList 是一個可能會經常被問到的集合類型,大多數都是和ArrayList進行對比,有什麼不同?啥啥啥的,但是真的和ArrayList相比的那些優勢有徹底或者更深入一步的瞭解嗎?主要弄明白鏈表和動態數組(數組)之前對保存數據和刪除數據和獲取數據之間的區別的時候,就會對這種問題的回答比較清晰。

  來一張 LinkedList 的上層類的結構圖

這個圖主要是對上層比較清晰。

好啦,開始記錄一下看源碼的代碼心得了啦。


 

1  : 參數的說明

// 長度的變量
transient int size = 0;

// 第一個節點

transient Node<E> first;

// 最後一個節點

transient Node<E> last;

 

 2 : 構造方法說明

// 無參構造方法,也就是什麼都沒有特別的做。
public LinkedList() {
}

 // 傳入集合的構造方法; 先調用上面的無參構造方法;然後調用addAll()方法

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

 

 3 : 方法的介紹

// 檢查是否越界
private boolean isPositionIndex(int index) {
    return index >= 0 && index <= size;
}
// 調用上面的方法進行判斷是否越界
private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 在鏈表的末尾插上元素
void linkLast(E e) {
   // 尾部的拿出來,用一個新的節點變量來進行存儲
    final Node<E> l = last;
    // 用尾節點值 傳入進來的e值  用內部類來生成新對象Node
    final Node<E> newNode = new Node<>(l, e, null);
    // 新對象賦值給最後尾節點
    last = newNode;
    // 如果之前尾節點是null的話,first節點給賦值上新的節點
    if (l == null)
        first = newNode;
    else
       // 否則就指向下一個節點
        l.next = newNode;
    // 長度 ++
    size++;
    modCount++;
}
// 傳入 E 值  和 一個節點
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節點指向新的節點
    succ.prev = newNode;
    // succ 最初的prev判斷是否是null;如果是null的話,就賦值給first;否則的話,就用pred.next指向給新的節點
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    // 長度 ++
    size++;
    modCount++;
}

// 添加前判斷 checkPositionIndex 傳入進來的索引是否越界;然後根據index的大小判斷是否等於長度的大小,然後來調用不同的方法
public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}
// node方法
Node<E> node(int index) {
    // assert isElementIndex(index);
    // size 右移1;然後判斷是否大於index
    if (index < (size >> 1)) {
        // 大於index 使用x 來儲存first節點信息
        Node<E> x = first;
        // 遍歷,x -> x.next  讓自身的下一個節點賦值給自己
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        // 用 x 存儲最後一個節點
        Node<E> x = last;
       // 倒敘遍歷,返回prev節點的信息
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}
// set 方法相對於add 方法;就沒那麼複雜了
public E set(int index, E element) {
   // 先檢查index是否越界和符合要求
    checkElementIndex(index);
    // 調用node方法來獲取Node信息
    Node<E> x = node(index);
    // 獲取節點的值 oldVal
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

//  根據index 獲取值;先檢查index是否越界等;然後調用node()方法  這裏主要 node()是遍歷的;時間複雜度是O(n);而數組的話是直接根據下標獲取;時間複雜度是O(1)也就是常數
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}


public boolean remove(Object o) {
    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;
}
// 獲取第一個節點的值;先將第一個節點值給 f ;然後判斷f 是不是null ; 如果是null 就拋出異常,如果不是的話;就調用iten屬性
public E getFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}
// 獲取最後一個節點的值 ; 操作思路是和 獲取首節點的值是一樣的
public E getLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return l.item;
}
 

4: 內部類說明

類 Node 就是存儲數據的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;
    }
}

 還有其他的三個內部類;感興趣的話;可以自己研究下。

 

 

 

 

 

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