Java集合--LinkedList

LinkedList 的本质是双向链表。实现 List 接口,能对它进行队列操作。实现 Deque 接口,能将LinkedList当作双端队列使用。
LinkedList 是非同步的。

LinkedList的继承关系

java.lang.Object
   ↳     java.util.AbstractCollection<E>
         ↳     java.util.AbstractList<E>
               ↳     java.util.AbstractSequentialList<E>
                     ↳     java.util.LinkedList<E>

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

LinkedList构造函数

// 默认构造函数
LinkedList()
// 创建一个LinkedList,保护Collection中的全部元素。
LinkedList(Collection<? extends E> collection)

LinkedList的API 

boolean       add(E object)
void          add(int location, E object)
boolean       addAll(Collection<? extends E> collection)
boolean       addAll(int location, Collection<? extends E> collection)
void          addFirst(E object)
void          addLast(E object)
void          clear()
Object        clone()
boolean       contains(Object object)
Iterator<E>   descendingIterator()
E             element()
E             get(int location)
E             getFirst()
E             getLast()
int           indexOf(Object object)
int           lastIndexOf(Object object)
ListIterator<E>     listIterator(int location)
boolean       offer(E o)
boolean       offerFirst(E e)
boolean       offerLast(E e)
E             peek()
E             peekFirst()
E             peekLast()
E             poll()
E             pollFirst()
E             pollLast()
E             pop()
void          push(E e)
E             remove()
E             remove(int location)
boolean       remove(Object object)
E             removeFirst()
boolean       removeFirstOccurrence(Object o)
E             removeLast()
boolean       removeLastOccurrence(Object o)
E             set(int location, E object)
int           size()
<T> T[]       toArray(T[] contents)
Object[]     toArray()

 

源码分析

List接口的实现类之一ArrayList的内部实现是一个数组,而另外一个实现LinkedList内部实现是使用双向链表。

LinkedList在内部定义了一个叫做Node类型的内部类,这个Node就是一个节点,链表中的节点,这个节点有3个属性,分别是元素item(当前节点要表示的值), 前节点prev(当前节点之前位置上的一个节点),后节点next(当前节点后面位置的一个节点)。

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

LinkedList的3个属性:

transient int size = 0; // 集合链表内节点数量
transient Node<E> first; // 集合链表的首节点
transient Node<E> last; // 集合链表的尾节点

add(E e)

添加元素到链表的最后一个位置

public boolean add(E e) {
    linkLast(e);
    return true;
}
void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null); // 由于是添加元素的链表尾部,所以也就是这个新的节点是最后1个节点,它的前节点肯定是目前链表的尾节点,它的后节点为null
    last = newNode; // 尾节点变成新的节点
    if (l == null) // 如果一开始尾节点还没设置,那么说明这个新的节点是第一个节点,那么首节点也就是这个第一个节点
        first = newNode;
    else // 否则,说明新节点不是第一个节点,处理节点前后关系
        l.next = newNode;
    size++; // 节点数量+1
    modCount++;
}

add(int index, E element)

添加元素到列表中的指定位置

public void add(int index, E element) {
    checkPositionIndex(index); // 检查索引的合法性,不能超过链表个数,不能小于0

    if (index == size) // 如果是在链表尾部插入节点,那么直接调用linkLast方法,上面已经分析过
        linkLast(element);
    else // 不在链表尾部插入节点的话,调用linkBefore方法,参数为要插入的元素值和节点对象
        linkBefore(element, node(index));
}

根据索引找到对应的节点

Node<E> node(int index) {
    // 用了一个小算法,如果索引比链表数量的一半还要小,从前往后找,这样只需要花O(n/2)的时间获取节点
    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;
    }
}

void linkBefore(E e, Node<E> succ) { // succ节点表示要新插入节点应该在的位置
    final Node<E> pred = succ.prev;
    final Node<E> newNode = new Node<>(pred, e, succ); // 1:新节点的前节点就是succ节点的前节点,新节点的后节点是succ节点
    succ.prev = newNode; // 2:succ的前节点就是新节点
    if (pred == null)    // prev=null表示succ节点就是head首节点,这样的话只需要重新set一下首节点即可,首节点的后节点在步骤1以及设置过了
        first = newNode;
    else // succ不是首节点的话执行步骤3
        pred.next = newNode; // 3:succ节点的前节点的后节点就是新节点
    size++; // 节点数量+1
    modCount++;
} 

上面代码中注释的1,2,3点就在下图中表示

LinkedList还提供了2种特殊的add方法,分别是addFirst和addLast方法,处理添加首节点和尾节点。

 

remove(int index)

移除指定位置上的节点

public E remove(int index) {
    checkElementIndex(index); // 检查索引的合法性,不能超过链表个数,不能小于0 
    return unlink(node(index));
}

E unlink(Node<E> x) {
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    if (prev == null) { // 特殊情况,删除的是头节点
        first = next;
    } else {
        prev.next = next; // 1
        x.prev = null; // 1
    }

    if (next == null) { // 特殊情况,删除的是尾节点
        last = prev;
    } else {
        next.prev = prev; // 2
        x.next = null; // 2
    }

    x.item = null; // 3
    size--; // 链表数量减一
    modCount++;
    return element;
}

上面代码中注释的1,2,3点就在下图中表示

 

get(int index)

得到索引位置上的元素

public E get(int index) {
    checkElementIndex(index); // 检查索引的合法性,不能超过链表个数,不能小于0 
    return node(index).item; // 直接找到节点,返回节点的元素值即可
}

 

posted @ 2016-08-24 12:01  Hesier  阅读(936)  评论(0编辑  收藏  举报