Jdk1.8 Collections Framework源碼解析(2)-LinkedList

ArrayList的插入和刪除元素的操做會花費線性時間,那麼有沒有插入和刪除元素比較省時的集合呢,看下LinkedList這個實現。 老樣子,先看看它實現了那些接口。java

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

以前看過的接口不看了。先看下java.util.Deque。算法

public interface Deque<E> extends Queue<E>

這個接口擴展了java.util.Queue,Queue也是Java Collections Framework中一個重要的接口,它表示了隊列。固然隊列自己也屬於集合(java.util.Collection是更高層次的抽象)。數組

public interface Queue<E> extends Collection<E>{  
    boolean add(E e);  
    boolean offer(E e);  
    E remove();  
    E poll();  
    E element();  
    E peek();  
}

Queue提供了添加、刪除和獲取元素的方法,每種方法提供2個版本。如添加元素,add和offer均可以完成這個操做,區別在於add方法若是添加失敗會拋出異常,而offer方法則會返回false。Queue接口只提供隊列的抽象概念,但並無定義元素的操做順序。其實現能夠提供先入先出或者先入後出(棧)這樣的性質。數據結構

大概瞭解了java.util.Queue後繼續看java.util.Deque。this

public interface Deque<E> extends Queue<E> {  
    void addFirst(E e);  
    void addLast(E e);  
    boolean offerFirst(E e);  
    boolean offerLast(E e);  
    E removeFirst();  
    E removeLast();  
    E pollFirst();  
    E pollLast();  
    E getFirst();  
    E getLast();  
    E peekFirst();  
    E peekLast();  
    boolean removeFirstOccurrence(Object o);  
    boolean removeLastOccurrence(Object o);  
    void push(E e);  
    E pop();  
    Iterator<E> descendingIterator();  
}

像Queue接口同樣,Deque也對這些操做方法提供了2個版本。.net

接下來看一下java.util.AbstractSequentialList這個抽象類,這個類的做用和java.util.AbstractList做用同樣,提供一些「骨架」實現。區別在於這個類提供了「按次序訪問」的基礎,而AbstractList提供了「自由訪問」的基礎。也就是說,若是咱們要實現一個基於鏈表的集合的話,能夠繼承這個類;要實現基於數組的集合的話,就繼承AbstractList類。指針

在看LinkedList的源代碼以前,仍是先思考一下,若是本身實現LinkedList要怎麼作?code

思考中......orm

既然是鏈表,那麼內部必定會有一個「鏈」,而「鏈」是由「環」組成,說明內部會有「環」這樣的概念。每一個環都和下一個環相扣,有兩個特殊的環,首環和尾環。首先,沒有任意一環的下一環是首環,尾環沒有下一環;而後,首環和尾環上是不攜帶數據的(固然普通環也是能夠保存null元素滴)。若是再從代碼上考慮一下,每個環都有下一個環的引用,這樣能夠構成一個鏈。但每一個環也能夠即有上一個環的引用,又有下一個環的引用,也能夠構成鏈。它們有什麼區別呢?其實這就是所謂的單向鏈表和雙向鏈表,java.util.LinkedList內部使用雙向鏈表實現。那可使用單向鏈表實現嗎?那就試試吧。 這個不放參考一些以前《算法4》的一個實現。 經過查看OpenJDK的源碼咱們但是能夠,對比不一樣JDK版本,的實現。繼承

看來一下,LinkedList 類開頭的註釋,大概是這樣說的, LinkedList 是基於 List 的一個雙向鏈表實現的一個數據結構。

Doubly-linked list implementation of the {@code List} and {@code Deque} interfaces. Implements all optional list operations, and permits all elements (including {@code null}).

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;

    transient Node<E> first;

    transient Node<E> last;

經過上面的源碼,咱們看到,作爲雙向鏈表實現,必然會有一個 頭指針 first 和 尾指針last , 經過用雙向鏈表,整個鏈表的數據結構在遍歷的時候就會有所選擇的,從頭遍歷仍是從尾部遍歷,這樣就會加快效率,可是它是如何知道是何時該是從頭遍歷,何時該從尾部遍歷呢?

看看,鏈表的數據結構,很是簡單。

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

咱們在看看LikedList 的 的添加操做:

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

    /**
     * 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++;
    }

    /**
     * Inserts element e before non-null Node succ.
     */
    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 = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }

元素數據的查詢,主要是經過下面的2個方法來實現的:

/**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index {@code i} such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     *
     * @param o element to search for
     * @return the index of the first occurrence of the specified element in
     *         this list, or -1 if this list does not contain the element
     */
    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;
    }

    /**
     * Returns the index of the last occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the highest index {@code i} such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     *
     * @param o element to search for
     * @return the index of the last occurrence of the specified element in
     *         this list, or -1 if this list does not contain the element
     */
    public int lastIndexOf(Object o) {
        int index = size;
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (x.item == null)
                    return index;
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (o.equals(x.item))
                    return index;
            }
        }
        return -1;
    }

LikedList 默認是從頭部開始查詢,同時也提供了從尾部查詢的方法。

相關文章
相關標籤/搜索