JDK 1.6 LinkedList 採用**循環雙向鏈表**(header 節點 prev 指向尾、next 指向頭),JDK 1.7+ 簡化為**非循環雙向鏈表**(first/last 直接指向頭尾節點,null 表示邊界)。本文基於 **JDK 1.7/8** 源碼分析,切勿混淆舊版博客資料。
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;
}
}
item 數據、next 後繼、prev 前驅。prev, element, next。
transient int size = 0; // 節點數
transient Node<E> first; // 頭節點引用
transient Node<E> last; // 尾節點引用
transient:序列化時自定義寫入(writeObject 手動序列化節點數據),不依賴默認字段序列化。
// 無參:空實現,first=last=null, size=0
public LinkedList() {}
// Collection 構造:轉數組 → 批量鏈接
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index); // index ∈ [0, size]
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0) return false;
Node<E> pred, succ;
if (index == size) { // 尾部插入
succ = null;
pred = last;
} else { // 中間插入
succ = node(index); // 獲取 index 處節點
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null) first = newNode;
else pred.next = newNode;
pred = newNode;
}
if (succ == null) last = pred;
else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
關鍵點:單向遍歷數組,雙向鏈接節點,O(numNew) 時間,避免重複查找插入點。
Node<E> node(int index) {
// assert isElementIndex(index); // index ∈ [0, size-1]
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;
}
}
get/set/add/remove 所有索引操作。
// 頭插
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++;
}
// 指定節點前插入
void linkBefore(E e, Node<E> succ) {
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++;
}
private E unlinkFirst(Node<E> f) {
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;
}
private E unlinkLast(Node<E> l) {
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null; l.prev = null;
last = prev;
if (prev == null) first = null;
else prev.next = null;
size--; modCount++;
return element;
}
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; x.prev = null; }
if (next == null) last = prev;
else { next.prev = prev; x.next = null; }
x.item = null; // help GC
size--; modCount++;
return element;
}
pop()/remove() 等語義。| 方法 | 實現核心 | 時間複雜度 |
|---|---|---|
| addFirst(e) | linkFirst(e) | O(1) |
| addLast(e) | linkLast(e) | O(1) |
| getFirst() | first.item (空檢查) | O(1) |
| getLast() | last.item (空檢查) | O(1) |
| removeFirst() | unlinkFirst(first) | O(1) |
| removeLast() | unlinkLast(last) | O(1) |
| add(index, e) | index==size ? linkLast : linkBefore(e, node(index)) | O(min(index, n-index)) |
| get(index) | node(index).item | O(min(index, n-index)) |
| set(index, e) | node(index).item = e | O(min(index, n-index)) |
| remove(index) | unlink(node(index)) | O(min(index, n-index)) |
| add(e) | linkLast(e) | O(1) |
| remove(Object o) | 遍歷 first→last,equals 匹配 → unlink | O(n) |
| indexOf(o) | 從 first 正向遍歷比較 | O(n) |
| lastIndexOf(o) | 從 last 反向遍歷比較 | O(n) |
實現 Deque<E> 接口,提供豐富別名方法:
| 語義 | 方法 | 等效實現 |
|---|---|---|
| 棧 (LIFO) | push(e) | addFirst(e) |
| pop() | removeFirst() | |
| peek() | peekFirst() / getFirst() | |
| empty() | isEmpty() | |
| search(o) | 從頂向下 1-based 索引 | |
| 隊列 (FIFO) | add(e) / offer(e) | addLast(e) |
| remove() / poll() | removeFirst() / pollFirst() | |
| element() / peek() | getFirst() / peekFirst() | |
| 雙端隊列 | addFirst/offerFirst | linkFirst |
| addLast/offerLast | linkLast | |
| removeFirst/pollFirst | unlinkFirst | |
| removeLast/pollLast | unlinkLast | |
| peekFirst/peekLast | first/last.item |
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned = null; // 上次返回節點
private Node<E> next; // 下一個待返回節點
private int nextIndex; // 下一個索引
private int expectedModCount = modCount; // 快速失效檢查
// next():向後
public E next() {
checkForComodification();
if (!hasNext()) throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
// previous():向前
public E previous() {
checkForComodification();
if (!hasPrevious()) throw new NoSuchElementException();
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
// add():在 lastReturned 之前插入(next 之前)
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null) linkLast(e);
else linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
// remove():刪除 lastReturned
public void remove() {
checkForComodification();
if (lastReturned == null) throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned) next = lastNext;
else nextIndex--;
lastReturned = null;
expectedModCount++;
}
}
nextIndex 指向下一個元素索引。add(e) 插入到游標前(即 next 之前),不影響後續 next()。remove() 刪除最近一次 next()/previous() 返回的元素(lastReturned)。modCount 機制:結構性修改(add/remove)+1,迭代器操作同步更新 expectedModCount,檢測併發修改拋 ConcurrentModificationException。
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject(); // 寫入非 transient 字段(此處無)
s.writeInt(size); // 寫入 size
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item); // 逐節點寫入元素
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
int size = s.readInt();
for (int i = 0; i < size; i++)
linkLast((E) s.readObject()); // 重建鏈表
}
first/last 引用(transient),避免反序列化後引用失效。size 和**元素順序**,反序列化時重新 linkLast 重建結構。
public Object clone() {
LinkedList<E> clone = superClone(); // 父類 Object.clone() 淺拷貝字段
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item); // 逐元素 add,共享元素對象
return clone;
}
| 操作類別 | 複雜度 | 說明 |
|---|---|---|
| 頭尾增刪 | O(1) | 直接操作 first/last,無遍歷 |
| 索引訪問 | O(min(i, n-i)) | 雙向查找優化,但本質 O(n) |
| 中間增刪 | O(min(i, n-i)) | 定位 O(n),鏈接 O(1) |
| 搜索/遍歷 | O(n) | 順序訪問 |
| 內存開銷 | 高 | 每個元素額外 2 引用 + Node 對象頭 |