LinkedList中查詢(contains)和刪除(remove)源碼分析

1、contains源碼分析

本文分析雙向鏈表LinkedList的查詢操做源碼實現。jdk中源程序中,LinkedList的查詢操做,經過contains(Object o)函數實現。具體見下面兩部分程序:
java

public boolean contains(Object o) {
    return indexOf(o) != -1;
}

node

public int indexOf(Object o) {
    int index = 0;
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            index++;
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
    }
    return -1;
}

indexOf函數查詢對象o在鏈表中的索引位置。編程

源碼首先將元素爲null的情形單獨判讀剝離,我的分析,應該是若是不單獨分析,null元素在下邊的for循環中,不能執行o.equals操做(編譯器輸入null.,會自動將已有輸入替換爲NullPointerException.,提示空指針異常)。數組

因爲鏈表不一樣於數組,在內存中並不是連續存儲,所以訪問某個元素須要遍歷。源程序中使用for循環進行遍歷。index表示鏈表元素索引,初值爲0。函數

一、針對空元素(null)的狀況,用for循環遍歷,查找元素爲null的節點,並返回索引index。for循環初始條件爲頭指針(無元素),判斷條件爲節點不爲null,自增表達式爲x重賦值爲下個節點(利用節點x的next指針實現,在java中next爲node對象的屬性成員)。每次自增,index+1。
二、針對非空元素,遍歷操做同上。函數結束的判斷條件變爲o.equals(x.item),這裏equals方法爲Object超類的方法,程序中元素類型非Object也可調用。源碼分析

兩種情形下,鏈表遍歷完畢(仍爲return),代表該元素o在鏈表中不存在,所以返回-1。學習

2、remove源碼對比

經過查閱,發現remove方法和contains方法的源碼實現很是類似,列出以下:this

/**
 * Removes the first occurrence of the specified element from this list, 
 * if it is present.  If this list does not contain the element, it is
 * unchanged. 
 * @param o element to be removed from this list, if present
 * @return {@code true} if this list contained the specified element
 */

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

對比發現,和contains相似,remove操做首先也是查找Object o是否存在與表中。空節點元素和非空節點的循環判斷基本相同,在找到Object o後,區別與contains的返回索引,remove須要刪除節點link(LinkedList的刪除須要對next鏈進行重配置引用)。spa

刪除節點的方法unlink的源碼以下:指針

//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;

    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;  //注:已從結構上修改此列表的次數。AbstractList屬性
    return element;
}

分析:
刪除節點程序中,須要考慮節點在鏈表中的不一樣位置,進行不一樣的操做。

一、節點於鏈表首端

clipboard.png

此時,特殊操做是須要將first指針(引用)指向其後的節點。

first = next;

二、節點於鏈表尾端

clipboard.png

此時,須要將上一個節點的next指針指向null,即上個節點稱爲尾節點。

last = prev;

三、節點於鏈表中間狀況

clipboard.png

若是不仔細思考,咱們在寫程序時,會直接在兩個if判斷後,將剩餘的相關操做寫在一塊兒。而源碼並無這麼作,稍做分析,就能看出,若是前一個if中,條件是prev,所以可對該節點的prev進行相關操做。然後續的if語句,還需判斷該節點的next引用,所以在第一個if-else語句體中,不對next進行操做,不然更改後,後學的next已經不是該節點的原next值。

所以,第一個if-else中:

prev.next = next;
x.prev = null;

第二個if-else中:

next.prev = prev;
x.next = null;

3、總結

從LinkedList的源碼能夠看到,源程序中相應方法代碼簡潔,邏輯清晰正確,在學習java的過程當中,除了學習知識爲我所用,也要避免閉門造車,多查看源碼和其餘優秀的項目程序,參考優秀的編程習慣和思想,從而積累經驗,提升本身的水平。

相關文章
相關標籤/搜索