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

相关文章
相关标签/搜索