private static class Node<E> {
Node<E> prev;
E item;
Node<E> next;
Node(Node<E> prev, E element, Node<E> next) {
this.prev = prev; this.item = element; this.next = next;
}
}
public class LinkedList<E> {
private Node<E> head;
// 头插 O(1)
public LinkedList<E> addFirst(E e) {
head = new Node<>(null, e, head);
if (head.next != null) head.next.prev = head;
return this;
}
// 尾插 O(n) — 需遍歷到尾部
public LinkedList<E> addNode(E e) {
if (head == null) { head = new Node<>(null, e, null); return this; }
Node<E> last = head;
while (last.next != null) last = last.next;
last.next = new Node<>(last, e, null);
return this;
}
// 刪除 O(n) — 需查找節點
public LinkedList<E> remove(E e) {
Node<E> cur = head;
while (cur != null) {
if (e.equals(cur.item)) {
if (cur.prev != null) cur.prev.next = cur.next;
if (cur.next != null) cur.next.prev = cur.prev;
if (cur == head) head = cur.next;
break;
}
cur = cur.next;
}
return this;
}
// ... getFirst(), toString() 等
}
public class LinkedList<E> {
private Node<E> head;
private Node<E> last; // 尾指針
public LinkedList<E> addNode(E e) {
if (last == null) { // 空鏈表
head = last = new Node<>(null, e, null);
} else {
last.next = new Node<>(last, e, null);
last = last.next;
}
return this;
}
public E getLast() { return last == null ? null : last.item; }
// 刪除邏輯需同步維護 last 指針(刪除尾節點時 last = last.prev)
// ... 其他方法同版本一
}
| 操作 | 無尾指針 | 帶尾指針 |
|---|---|---|
| 頭插/頭刪 | O(1) | O(1) |
| 尾插 | O(n) | O(1) |
| 尾刪 | O(n) | O(1)* |
| 按值查找/刪除 | O(n) | O(n) |
| 空間開銷 | 1 指針 | 2 指針 |
* 尾刪需維護 last = last.prev,仍為 O(1)。
Node<E>,外部類用 LinkedList<E>Collections.synchronizedList 或 ConcurrentLinkedDequesize、first/last、modCount(Fail-Fast)ListIterator 支持雙向游標操作Deque、Queue、List 多介面手寫雙向鏈表是理解數據結構、指針操作、邊界處理的**必修課**。帶尾指針版本在尾部高頻操作場景下優勢明顯,代價僅多一個引用。**生產代碼直接用 JDK LinkedList**,但面試、教學、嵌入式受限環境手寫能力不可或缺。