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 ? get(i)==null : 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 ? get(i)==null : 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 默認是從頭部開始查詢,同時也提供了從尾部查詢的方法。