線性表:元素間一對一關係,除首尾節點外各有唯一前驅後繼。邏輯結構簡單,常以棧、佇列、字串等受限形式應用。
鏈表:物理存儲不連續,透過指標串聯邏輯順序。優勢在於頭部插入刪除 O(1),劣勢在於隨機訪問 O(N)。
新節點總是插在頭節點後,首個插入的節點成為尾節點。適合實現棧。
public class SingleLinkedList<T> {
private Node<T> first;
public void insertFirst(T data) {
Node<T> newNode = new Node<>(data);
newNode.next = first;
first = newNode;
}
public Node<T> deleteFirst() {
if (first == null) return null;
Node<T> temp = first;
first = first.next;
return temp;
}
// ... find, delete, display, reverse
static class Node<T> { T data; Node<T> next; Node(T d){data=d;} }
}
維護尾指標 rear,新節點接在尾部。適合實現佇列。
public class SingleLinkedList2<T> {
private Node<T> head, rear;
public void insertLast(T data) {
Node<T> newNode = new Node<>(data);
if (head == null) { head = rear = newNode; }
else { rear.next = newNode; rear = newNode; }
}
// ... deleteLast, find, delete, display, reverse
}
public void reverse() {
Node<T> prev = null, curr = first, next;
while (curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
first = prev;
}
在單鏈表基礎上增加 rear 指向尾節點,使尾部插入也能 O(1)。刪除尾部仍需 O(N)(需找前驅),除非改為雙向鏈表。
public class TwoEndpointList<T> {
private Node<T> head, rear;
public void insertFirst(T data) { /* 同單鏈表頭插 */ }
public void insertLast(T data) { /* 利用 rear 直接尾插 O(1) */ }
public T deleteHead() { /* 刪頭 O(1) */ }
// 刪尾需遍歷找倒數第二個,O(N)
}
棧只需單端操作,直接複用 insertFirst/deleteHead。
public class LinkStack<T> {
private TwoEndpointList<T> list = new TwoEndpointList<>();
public void push(T data) { list.insertFirst(data); }
public T pop() { return list.deleteHead(); }
public T peek() { return list.peekHead(); }
public boolean isEmpty() { return list.isEmpty(); }
}
佇列頭刪尾增,完美映射 deleteHead/insertLast。
public class LinkQueue<T> {
private TwoEndpointList<T> list = new TwoEndpointList<>();
public void insert(T data) { list.insertLast(data); } // 入隊
public T remove() { return list.deleteHead(); } // 出隊
public T peek() { return list.peekHead(); }
public boolean isEmpty() { return list.isEmpty(); }
}
維持節點按關鍵字有序。插入需查找位置 O(N),刪除最小值(頭節點)O(1)。適用於優先權佇列、頻繁存取極值場景。
public class SortedLinkedList<T extends Comparable<T>> {
public void insert(T data) {
Node<T> newNode = new Node<>(data), curr = first, prev = null;
while (curr != null && data.compareTo(curr.data) > 0) {
prev = curr; curr = curr.next;
}
if (prev == null) first = newNode;
else prev.next = newNode;
newNode.next = curr;
}
// 可用於鏈表插入排序:遍歷陣列插入有序鏈表,再遍歷輸出
}
| 結構 | 頭插 | 尾插 | 頭刪 | 尾刪 | 查找 | 適用場景 |
|---|---|---|---|---|---|---|
| 單鏈表(頭插) | O(1) | O(N) | O(1) | O(N) | O(N) | 棧、前綴匹配 |
| 單鏈表(尾插) | O(N) | O(1)* | O(1) | O(N) | O(N) | 佇列、順序構建 |
| 雙端鏈表 | O(1) | O(1) | O(1) | O(N) | O(N) | 棧/佇列雙模、雙端操作 |
| 有序鏈表 | O(N) | O(N) | O(1) | O(N) | O(N) | 優先權佇列、極值維護 |
* 需維護 rear 指標
first == nullfirst = rear = nullnext 必須置 nullT extends Comparable<T>手寫鏈表是理解指標、記憶體模型、遞迴的最佳練習。建議在紙上畫圖推演每個操作的指標變化,再敲代碼驗證。