public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{}
LinkedList
是一个继承于 AbstractSequentialList
的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。 LinkedList
实现了 List
接口,能对它进行列表操作。 LinkedList
实现了 Deque
接口,即能将 LinkedList
当作双端队列使用。 LinkedList
实现了 Cloneable
接口,即覆盖了函数Object.clone()
,能被克隆。 LinkedList
实现了 java.io.Serializable
接口,这意味着 LinkedList
支持序列化,能通过序列化去传输。 LinkedList
是非同步的。
LinkedList 除了第一个结点没有头指针、最有一个结点没有尾指针,每一个结点都有一个唯一的头指针和尾指针。
属性
// 链表元素的个数
transient int size = 0;
// 链表头结点
transient Node<E> first;
// 链表尾结点
transient Node<E> last;
其中 Node 是一个静态内部类,代表了双向链表的每一个结点。
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;
}
}
方法
构造函数
// 构造空链表
public LinkedList() {
}
// 构造一个包含指定 collection 中的元素的列表
// 这些元素按其 collection 的迭代器返回的顺序排列
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
头插结点
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 = new![这里写图片描述](http://img.blog.csdn.net/20180119124827945?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveF9peWE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)Node;
else
f.prev = newNode;
size++;
modCount++;
}
第一次插入元素的时候
接下来插入元素
linkLast 是使用尾插法插入元素,与上边的插入情况类似就不做介绍了。 linkBefore(E e, Node<E> succ)
是在结点 succ 前插入结点。
删除结点
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; // 1
x.prev = null; // 2
}
if (next == null) { // 删除尾结点
last = prev;
} else {
next.prev = prev; // 3
x.next = null; // 4
}
x.item = null;
size--;
modCount++;
return element;
}
在 Java 中一般删除结点包括两部分内容:
- 将与所删除的结点相关联的链删除,也就是删除结点间的引用关系
- 将所删除的结点的相关引用置为null,进行GC操作
unlinkFirst 是删除头结点
unlinkLast 是删除尾结点
以上两个操作和删除结点类似,不再介绍。
克隆
@SuppressWarnings("unchecked")
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
可以看到克隆操作先执行一个对 LinkedList 的克隆,然后对其进行尾插入法操作。
“随机访问”
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;
}
}
因为是双向链表结构,所以是没有随机访问的,即使存在随机访问的接口。而这些接口的实现也只是遵循顺序访问。此处有一个小的优化:
当索引小于元素个数的一半时,从现象后遍历;否则从后往前遍历。(第一个元素的索引为0)
LinkedList 作为 Stack
public void push(E e) {
addFirst(e);
}
public E pop() {
return removeFirst();
}
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public boolean isEmpty() {
return size() == 0;
}
LinkedList 作为 Queue
public interface Queue<E> extends Collection<E> {
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
}
LinkedList 作为 Deque
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);
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
void push(E e);
E pop();
boolean remove(Object o);
boolean contains(Object o);
public int size();
Iterator<E> iterator();
Iterator<E> descendingIterator();
}