Linklist *reverse(Linklist *head) { // 假設帶頭結點
Linklist *p, *t;
p = head->next; // p 指向第一個資料結點
t = p->next; // t 指向第二個結點
p->next = NULL; // 斷開第一個結點,使其成為新鏈表尾部
while (t != NULL) {
p = t->next; // 暫存 t 的下一個
t->next = head->next; // 將 t 插入頭結點之後 (頭插法)
head->next = t;
t = p; // 移動 t 到下一個待處理結點
}
return head;
}
此演算法將原鏈表視為兩部分:
每次迴圈從待處理部分取出第一個結點 `t`,插入到已反轉部分的頭部(即 `head->next` 之後),實現就地反轉。
原始: HEAD -> 1 -> 2 -> 3 -> 4 -> NULL
p=1, t=2
步驟1: p->next=NULL => HEAD -> 1 -> NULL (t=2->3->4)
步驟2: 取 t=2, 插入頭部 => HEAD -> 2 -> 1 -> NULL (t=3->4)
步驟3: 取 t=3, 插入頭部 => HEAD -> 3 -> 2 -> 1 -> NULL (t=4)
步驟4: 取 t=4, 插入頭部 => HEAD -> 4 -> 3 -> 2 -> 1 -> NULL (t=NULL)
結束: 返回 HEAD,新鏈表 4->3->2->1
| 語句 | 角色 | 說明 |
|---|---|---|
p = t->next; | 暫存後繼 | 保存 `t` 原本的下一個結點,防止斷鏈後找不到後續節點。此時 `p` 指向待處理部分的新頭部。 |
t->next = head->next; | 接入已反轉鏈表 | 將 `t` 的 `next` 指向當前已反轉鏈表的第一個資料結點 (即舊的 `head->next`)。此處 `head->next` 等同於迴圈開始時的 `p` (第一次迴圈),但隨著迴圈進行,`head->next` 已更新為最新插入的結點。 |
本質區別:前者是「向後看」保存未來;後者是「向前連」接入過去。兩者指向完全不同的記憶體位置。
Node* reverse(Node* head) {
Node *prev = NULL, *curr = head, *next = NULL;
while (curr) {
next = curr->next; // 1. 暫存
curr->next = prev; // 2. 反轉指針
prev = curr; // 3. 移動 prev
curr = next; // 4. 移動 curr
}
return prev; // 新頭結點
}
此版本雙指針 `prev`/`curr` 更直觀,無需虛擬頭結點,適用於所有單向鏈表反轉場景。