一、概述
LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。
AbstractSequentialList
AbstractSequentialList 实现了“链表中,根据index索引值操作链表的全部函数”。
实现了与index相关接口
- get(int): E
- set(int, E): E
- add(int, E): void
- remove(int, E): E
- addAll(int, Collection<? extends E>):boolean
限定只返回ListIterator
AbstractSequentialList使用Iterator实现了这些随机访问接口,减少随机访问对于具体数据结构的依赖。如果想要自定义随机访问方式,可以继承AbstractList。
二、数据结构
链表
Node - 双向链表节点类,一般来说包括previous引用、next引用、element
size - 节点个数
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
与之前版本修改点:header拆分成两个first+last,之前只有一个header使用index判断是否是边界,使用first+last只需要判断prev==null||next==null就可以了。
三、特点
- 顺序访问效率高、随机访问效率低
- 随机添加/随机删除元素效率高
- 无限容量
四、实现要点
1. 双向链表的索引值实现
随机访问
遍历寻找,根据size选择比较近的一端开始遍历。复杂度为O(N/2)
LinkedList中所有随机访问都是先通过node(int)得到Node,然后再对Node进行操作。
/**
* Returns the (non-null) Node at the specified element index.
*/
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;
}
}
定位(indexOf(E))
遍历实现
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;
}
2. 基本功能的实现
AbstractSequentialList已实现方法add()、remove()、get() ,依然保留,使用Iterator实现AbstractSequentialList未实现方法,Node元素操作直接修改next、prev引用对象来实现,索引操作先找到Node元素,再进行操作。
抛弃元素时需要设置各项为null,保证对象可以被gc掉
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;
}
3. Iterator/DescendingIterator实现
自定义了ListItr<E>继承自ListIterator<E>
成员变量:
private Node<E> lastReturned = null;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
使用方式:类同ArrayList
fast-fail机制:类同ArrayList
DescendingIterator:从size开始向前调用
4. Deque双端队列
由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。
方法总结
第一个元素(头部) | 最后一个元素(尾部) | |||
---|---|---|---|---|
抛出异常 | 特殊值 | 抛出异常 | 特殊值 | |
插入 | addFirst(e) | offerFirst(e) | addLast(e) | offerLast(e) |
移除 | removeFirst() | pollFirst() | removeLast() | pollLast() |
检查 | getFirst() | peekFirst() | getLast() | peekLast() |