得益於頭結點的存在,單鏈表在指定位置插入節點時,首節點、中間節點、尾節點後插入均可用同一套邏輯處理,無需像無頭結點版本那樣單獨判斷 pos==0 或 head==NULL。本文給出最精簡、健壯的實現。
InsertNodeNode* InsertNode(Node *head, int pos, int x) {
// pos: 插入位置 (0-based,頭結點後為第0個位置)
// 即 pos=0 插在第一個數據節點前,pos=length 插在尾部
Node *pre = head;
// 1. 移動 pre 到第 pos 個節點 (即新節點的前驅)
for (int i = 0; pre && i < pos; i++) {
pre = pre->next;
}
// 2. 合法性檢查:pre 不能為 NULL (pos 超出長度)
if (!pre) {
printf("插入位置 %d 非法 (長度: %d)\n", pos, SizeList(head));
return head;
}
// 3. 創建新節點
Node *newNode = (Node*)malloc(sizeof(Node));
if (!newNode) { perror("malloc"); return head; }
newNode->element = x;
// 4. 標準雙鏈接 (單向版:先連後斷)
newNode->next = pre->next;
pre->next = newNode;
printf("在位置 %d 插入值 %d 成功\n", pos, x);
return head;
}
插入前 (pos=2, 插入 99):
head -> [10] -> [20] -> [30] -> NULL
pre ↑
(i=0) (i=1 循環結束)
插入後:
head -> [10] -> [20] -> [99] -> [30] -> NULL
pre->next = newNode
newNode->next = 原 pre->next
| pos 值 | 插入位置 | 示例 (長度=3) |
|---|---|---|
| 0 | 第一個數據節點前 (新首節點) | 插入後序列: [新] [10] [20] [30] |
| 1 | 第 1、2 個數據節點之間 | 插入後序列: [10] [新] [20] [30] |
| 2 | 第 2、3 個數據節點之間 | 插入後序列: [10] [20] [新] [30] |
| 3 | 尾部 (最後一個數據節點後) | 插入後序列: [10] [20] [30] [新] |
| >=4 | 非法 (超出長度) | 報錯,不插入 |
// 無頭結點版本需處理:
if (head == NULL) { ... } // 空表
if (pos == 0) { newNode->next=head; head=newNode; } // 插首
else { 遍歷到 pos-1 ... } // 插中/尾
帶頭結點版本零特殊判斷,代碼行數減少 40%,Bug 率大幅降低。
int main() {
Node *list; InitialList(&list);
CreateList(list); // 輸入 10 20 30 0
InsertNode(list, 0, 5); // 頭插: 5 10 20 30
InsertNode(list, 2, 99); // 中插: 5 10 99 20 30
InsertNode(list, 4, 40); // 尾插: 5 10 99 20 30 40
InsertNode(list, 10, 1); // 非法: 報錯
PrintList(list);
return 0;
}
帶頭結點單鏈表插入操作的精髓在於:統一前驅查找、統一鏈接邏輯、統一邊界處理。只需記住「找前驅 pre,newNode->next = pre->next; pre->next = newNode」這一標準模式,即可應對所有插入場景。這正是「哨兵節點」設計模式在數據結構中的經典體現。