首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言實現帶頭結點單鏈表節點刪除:按位置與按值雙模式

     編輯:關於C語言

帶頭結點刪除:前驅指針統一化,邏輯極致簡潔

帶頭結點單鏈表刪除節點時,無需區分首節點、中間節點、尾節點。通過維護 pre (前驅) 和 cur (當前) 兩個指針,從頭結點開始遍歷,統一執行 pre->next = cur->next; free(cur); 即可完成所有位置的刪除。本文提供按位置刪除與按值刪除兩種模式的標準實現。

核心代碼:按位置刪除 DeletePosNode

Node* DeletePosNode(Node *head, int pos) {
    // pos: 1-based 位置 (第一個數據節點為 1)
    if (pos < 1) { printf("位置非法: %d\n", pos); return head; }
    
    Node *pre = head;
    Node *cur = head->next;
    int i = 1;
    
    // 1. 遍歷找到第 pos 個節點及其前驅
    while (cur && i < pos) {
        pre = cur;
        cur = cur->next;
        i++;
    }
    
    // 2. 合法性檢查
    if (!cur) {
        printf("位置 %d 超出鏈表長度 (%d)\n", pos, i-1);
        return head;
    }
    
    // 3. 統一刪除邏輯:斷開鏈接 + 釋放內存
    pre->next = cur->next;
    free(cur);
    cur = NULL; // 防野指針
    
    printf("刪除位置 %d 節點成功\n", pos);
    return head;
}

核心代碼:按值刪除 DeleteValueNode (刪除首個匹配值)

Node* DeleteValueNode(Node *head, int x) {
    Node *pre = head;
    Node *cur = head->next;
    
    // 1. 遍歷查找值為 x 的節點
    while (cur && cur->element != x) {
        pre = cur;
        cur = cur->next;
    }
    
    // 2. 未找到
    if (!cur) {
        printf("值 %d 不存在於鏈表中\n", x);
        return head;
    }
    
    // 3. 統一刪除邏輯 (同按位置刪除)
    pre->next = cur->next;
    free(cur);
    cur = NULL;
    
    printf("刪除值 %d 節點成功\n", x);
    return head;
}

刪除邏輯統一性圖解

刪除位置 2 (值 20) / 刪除值 20:
head -> [10] -> [20] -> [30] -> NULL
         pre     cur

執行 pre->next = cur->next; free(cur);
head -> [10] ----------> [30] -> NULL
         pre     (cur已釋放)

刪除位置 1 (首節點) / 刪除首節點值:
head -> [10] -> [20] -> NULL
         pre   cur
執行 pre->next = cur->next;  // head->next 直接指向 20
head ----------> [20] -> NULL

刪除尾節點:
head -> [10] -> [20] -> NULL
               pre   cur
執行 pre->next = cur->next;  // cur->next 為 NULL
head -> [10] -> NULL

對比:無頭結點版本的分支地獄

// 無頭結點刪除首節點
if (pos == 1) { 
    Node *tmp = head; 
    head = head->next; 
    free(tmp); 
    return head; // 必須返回新 head!
}
// 無頭結點刪除尾節點
if (cur->next == NULL) { pre->next = NULL; free(cur); }
// 無頭結點刪除中間
pre->next = cur->next; free(cur);

帶頭結點版本:零 if-else 分支,統一邏輯覆蓋所有情況。

完整測試驗證

int main() {
    Node *list; InitialList(&list);
    CreateList(list); // 輸入: 10 20 30 40 0
    
    PrintList(list);        // 10 20 30 40
    DeletePosNode(list, 2); // 刪除 20
    PrintList(list);        // 10 30 40
    DeleteValueNode(list, 40); // 刪除尾部 40
    PrintList(list);        // 10 30
    DeleteValueNode(list, 10); // 刪除首部 10
    PrintList(list);        // 30
    DeletePosNode(list, 1);   // 刪除唯一節點 30
    PrintList(list);        // (空)
    DeletePosNode(list, 1);   // 空表刪除,報錯
    return 0;
}

最佳實踐提醒

  • 雙指針同步移動:pre = cur; cur = cur->next; 保證 pre 永遠是 cur 的前驅。
  • free 後置 NULL:防止後續誤用野指針 (雖然此處 cur 即將銷毀,但屬於好習慣)。
  • 位置語義統一:建議項目中統一規定「查找/刪除用 1-based,插入用 0-based」或全用 0-based,文檔化說明。
  • 返回 head:雖帶頭結點刪除不改變 head,但保持返回 head 的習慣,便於鏈式調用與接口統一。

總結

帶頭結點單鏈表刪除操作,通過「哨兵節點 + 雙指針遍歷」模式,將原本需要 3-4 個分支處理的邊界情況,壓縮為單一統一邏輯。這不僅減少代碼量,更從根本上消除了邊界條件遺漏導致的 Bug,是「用空間換取邏輯簡潔性」的教科書級範例。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved