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 默认是从头部开始查询,同时也提供了从尾部查询的方法。