LinkedList是一个双端链表,他继承了AbstractSequentaiList顺序列表,实现了List,Deque,Cloneable,和Serializable接口。Deque是双端队列的接口,LinkedList有记录头的 first 和 尾的 last,所以我们可以对队列的两端进行操作。它还实现了Cloneable和Serializeble接口,它们分别是实现队列进行拷贝和序列化的接口。
LinkedList的节点的结构是:
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; } }
其中lLinkedList除了含有first和last两个基本属性外,还有:
transient int size = 0; //记录集合中元素数量 //Fields inherited from class java.util.AbstractList protected transient int modCount = 0; //修了几个的次数 //当利用Iterator进行操作时会用上
它记录了下一个节点和后一个节点。LinkedList的很多操作是调用以下函数来完成的:
/* * 将一个元素作为头结点插入集合中 * */ 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++; } /* * 将一个元素作为队尾插入集合中 * */ 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++; } /** *将一个元素插入在指定结点之前,其中指定结点不能为null */ 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++; } /** * 删除指定结点值,指定结点后的结点将作为头结点,f不能为null */ private E unlinkFirst(Node<E> f) { // assert f == first && f != null; final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; if (next == null) last = null; else next.prev = null; size--; modCount++; return element; } /** * 删除指定结点值,指定结点前的结点将作为尾结点,f不能为null */ private E unlinkLast(Node<E> l) { // assert l == last && l != null; final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; } /** * 删除指定结点 ,x值不能为null */ E unlink(Node<E> x) { // assert x != null; 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; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
需要注意的是LinkedList没法在O(n)的时间复杂度内,根据index值来指定位置的节点进行操作,我们先来看看随机访问,修改,增加,修改的源码:
public E get(int index) { checkElementIndex(index); return node(index).item; } public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; } public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); } public E remove(int index) { checkElementIndex(index); return unlink(node(index)); }
checkXXXXIndex(index)函数是用来检测index是否能用的,我们可以看到每次调用方法时,它都是在底层调用了node()方法,那它又是怎样的呢
Node<E> node(int index) { // assert isElementIndex(index); 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; } }
首先会先确定index离对头还是队尾更近,在确定从哪开始遍历。所以,LinkedList的随机访问效率为O(n)。因此我们不会通过调用
while(index < list.size()){ get(index++); }
来遍历LinkedList,当需要遍历LinkedList时怎么办呢,需要调用listIterator();或者descendingIterator();或者调用继承自Deque的iterator();
无论是listIterator()还是descendingIterator()都是对LinkedList的内部类ListItr进行操作,它实现了ListIterator<E>.
private class ListItr implements ListIterator<E> { private Node<E> lastReturned; <span style="white-space:pre"> </span>//最后一次返回的节点 private Node<E> next;<span style="white-space:pre"> </span>//下一个操作的节点 private int nextIndex;<span style="white-space:pre"> </span>//next的索引 private int expectedModCount = modCount; <span style="white-space:pre"> </span>//iterator的修改次数 当modCount != expectedModCount时会抛出ConcurrentModficationException //方法 ...... }
我们可以看到,它记录了指向最后一次返回的节点信息和下一次操作节点的信息,所以我们对LinkedList遍历时使用如下代码:
ListIterator<String> iterator = list.listIterator(); while (iterator.hasNext()){ iterator.next() }
因为实现了ListIterator接口,所以它相对Iterator而言,还能够add,set,previous,hasPrevious和previousIndex。还有一点需要提醒一下,ListItr有个属性expectedModCount属性是被赋值为LinkedList的modCount的,并且,调用ListItr的方法时,除了hasXXX或者XXXindex方法外,都会检测expectedModCount 是否等于 modCount, 不等会被抛出异常,所以在调用LInkedList的XXXXIterator()方法后,都不应该在直接通过LinkedList的方法对List进行操作而应该直接利用XXXXIterator的方法进行操作。