LinkedList分析

AndyandJennifer發表於2018-04-12

模仿遊戲.jpeg

上次我們分析了ArrayList,大家都已經瞭解了分析一個集合的步驟。那接下來,我們繼續分析LinkedList。廢話不不多說,直接整。

檢視LinkedLis成員

	/**
     * 指標指向第一個節點
     * 初始化: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * 指標指向最後一個節點
     * 初始化: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;
複製程式碼

從LinkedList成員中,可以看出Lined內部有兩個指標,first(指向第一個節點)與Last(指向最後一個節點)。檢視相關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;
        }
    }
複製程式碼

Node類中,儲存了當前資料元素,上一個節點,及下一個節點。從這裡,我們大概瞭解到了LinkedList的內部結構是連結串列。

一、新增元素

add(e)方法

 public boolean add(E e) {
        linkLast(e);
        return true;
    }

複製程式碼

add方法內部呼叫了linkLast(e),繼續走linkLast(e)。

檢視linkLast(e)方法

void linkLast(E e) {
        final Node<E> l = last;//last指向最後一個節點。
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;//frist指向第一個新增元素
        else
            l.next = newNode;//不是第一次新增,上一個節點的next指向當前節點
        size++;
        modCount++;
    }
複製程式碼

當該方法執行是,會初始化一個Node節點儲存當前新增元素及上一個節點。如果是第一次執行,該方法,first與Last都會指向該節點。如果不是第一次執行。上個節點的next會指向新新增的節點,且last指向新新增的節點。

addFist(e)方法

addFist(e)中方法直接呼叫了linkFrist(e)方法,我們直接檢視LinkFirst方法:

  private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }
複製程式碼

linkFirst方法內部建立了一個新的節點。如果是第一次新增。新節點上個節點為null。如果不是,則新的節點的上個的節點為first原來指向的節點,first指向新新增的節點。

addLast(e)方法原理與addFirst(e)原理差不多,這裡就直接跳過了

二、獲取元素

get(Index)方法

public E get(int index) {
        checkElementIndex(index);//判斷是否操作儲存的長度
        return node(index).item;
    }
複製程式碼

get方法先判斷時候在有效範圍類,如果呼叫了node(index)方法返回相應元素,繼續走node方法。

Node<E> node(int index) {
        // assert isElementIndex(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;
        }
    }

複製程式碼

該方法內部先判斷index的位置是否小於總長度的一半,如果是,則從連結串列前方遍歷,如果不是,則從連結串列最末尾進行遍歷。

三、刪除元素

removeFirst()方法

        final Node<E> f = first;
        if (f == null)//如果first沒有指向元素,丟擲異常
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }
複製程式碼

removeFirst()方法,先判斷當前frist時候為null,如果不是,將first作為引數傳入unLinkFirst()方法,檢視unLinkFirst方法。

 private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }
複製程式碼

unLinkFirst方法將器node中資料置為null,且將frist節點,指向f的下一個節點。並將f的下一個節點的上個節點(也就是f)至為null。

removeLast()方法

public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }
複製程式碼

removeLast方法內把Last指向的節點,傳入unLikeLast()方法,繼續走unLinkLast方法。

 private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;
        final E element = l.item;
        final Node<E> prev = l.prev;
        l.item = null;
        l.prev = null; // help GC
        last = prev;
        if (prev == null)
            first = null;
        else
            prev.next = null;
        size--;
        modCount++;
        return element;
    }
複製程式碼

unLinkLast方法內部獲取last重寫指向Last原節點的上一個節點,同時將Last原節點至為null.

總結

  • LinkedList方法內部實現是連結串列,且內部有fist與last指標控制資料的增加與刪除等操作
  • LinkedList內部元素是可以重複,且有序的。因為是按照連結串列進行儲存元素的。
  • LinkedList執行緒是非執行緒安全的,因為其內部新增、刪除、等操作,沒有進行同步操作。
  • LinkedList增刪元素速度較快。

最後,附上我寫的一個基於Kotlin 仿開眼的專案SimpleEyes(ps: 其實在我之前,已經有很多小朋友開始仿這款應用了,但是我覺得要做就做好。所以我的專案和其他的人應該不同,不僅僅是簡單的一個應用。但是,但是。但是。重要的話說三遍。還在開發階段,不要打我),歡迎大家follow和start

相關文章