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

C語言鏈表刪除節點的兩種核心方法詳解與代碼對比

     編輯:關於C語言

鏈表刪除節點核心邏輯

單向鏈表刪除節點本質是:**修改前驅節點的 `next` 指針跳過被刪節點,然後釋放被刪節點記憶體**。

關鍵難點:單向鏈表無法直接訪問前驅,需在遍歷時**同時維護前驅指針 `prev` 與當前指針 `curr`**。

方法一:雙指針遍歷法(教科書標準寫法)

// 根據姓名刪除學生記錄
void delete_by_name(Student *head) {
    if (!head) { printf("鏈表為空\n"); return; }

    char name[20];
    printf("輸入要刪除的姓名: "); scanf("%19s", name);

    Student *prev = head;
    Student *curr = head->next;

    while (curr) {
        if (strcmp(curr->name, name) == 0) {
            prev->next = curr->next;  // 1. 旁路被刪節點
            free(curr);               // 2. 釋放記憶體
            printf("刪除成功\n");
            return;
        }
        prev = curr;
        curr = curr->next;
    }
    printf("未找到該學生\n");
}

關鍵點圖解

刪除前:  head → [A] → [B] → [C] → NULL
                    ↑     ↑
                  prev  curr (目標 B)

刪除後:  head → [A] → [C] → NULL
                    ↑
            prev->next = curr->next
            free(curr)

方法二:臨時變量法(邏輯等價,寫法不同)

// 從文件讀取鏈表並刪除指定學號
Student *delete_by_id(Student *head) {
    FILE *fp = fopen("student.txt", "wb+");
    Student *prev = head;
    Student *curr = head->next;
    char target_id[12];
    printf("輸入要刪除的學號: "); scanf("%11s", target_id);

    while (curr) {
        if (strcmp(curr->id, target_id) == 0) {
            Student *temp = curr;      // 1. 保存被刪節點
            curr = curr->next;         // 2. 當前指針後移
            prev->next = curr;         // 3. 旁路
            free(temp);                // 4. 釋放
            // 將剩餘鏈表寫回文件...
            break;
        }
        // 寫入當前節點到文件
        fwrite(curr, sizeof(Student), 1, fp);
        prev = curr;
        curr = curr->next;
    }
    fclose(fp);
    return head;
}

兩種方法本質對比

| 維度 | 方法一(雙指針) | 方法二(臨時變量) | |------|------------------|-------------------| | 核心思想 | `prev->next = curr->next; free(curr);` | `temp = curr; curr = curr->next; prev->next = curr; free(temp);` | | 指針移動順序 | 先旁路,後釋放 `curr` | 先保存 `curr` 到 `temp`,`curr` 後移,再旁路,釋放 `temp` | | 適用場景 | 純記憶體操作 | 需同步持久化(如寫文件)時 | | 可讀性 | ⭐⭐⭐⭐⭐ 標準教學寫法 | ⭐⭐⭐ 多一個 `temp` 變量 |

完整可運行示例(含建立、刪除、打印)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Student {
    char id[12];
    char name[20];
    struct Student *next;
} Student;

Student *create_list() {
    Student *head = calloc(1, sizeof(Student));  // 頭節點無數據
    Student *tail = head;
    char id[12], name[20];
    while (1) {
        printf("輸入學號(空行結束): "); 
        if (!fgets(id, sizeof(id), stdin) || id[0] == '\n') break;
        id[strcspn(id, "\n")] = 0;
        printf("輸入姓名: "); fgets(name, sizeof(name), stdin);
        name[strcspn(name, "\n")] = 0;

        Student *node = malloc(sizeof(Student));
        strcpy(node->id, id); strcpy(node->name, name);
        node->next = NULL;
        tail->next = node;
        tail = node;
    }
    return head;
}

void print_list(Student *head) {
    for (Student *p = head->next; p; p = p->next)
        printf("[%s] %s\n", p->id, p->name);
}

void delete_student(Student *head) {
    char target[12];
    printf("輸入要刪除的學號: "); fgets(target, sizeof(target), stdin);
    target[strcspn(target, "\n")] = 0;

    Student *prev = head, *curr = head->next;
    while (curr) {
        if (strcmp(curr->id, target) == 0) {
            prev->next = curr->next;
            free(curr);
            printf("刪除成功\n");
            return;
        }
        prev = curr;
        curr = curr->next;
    }
    printf("未找到\n");
}

int main() {
    Student *head = create_list();
    print_list(head);
    delete_student(head);
    print_list(head);
    // 釋放剩餘節點...
    return 0;
}

常見錯誤與修正

| 錯誤代碼 | 問題 | 修正 | |----------|------|------| | `free(curr); prev->next = curr->next;` | 釋放後訪問野指針 | 先旁路 `prev->next = curr->next;` 再 `free(curr);` | | 刪除頭節點(無哨兵頭) | `head` 本身被刪,呼叫者指針未更新 | 使用**哨兵頭節點**(如上例),或傳遞 `Student **head` | | 忘記 `free` | 記憶體洩漏 | 刪除邏輯中必須配對 `free` | | 刪除後繼續用 `curr` | `curr` 已釋放 | 刪除後 `return` 或 `curr = prev->next;` |

總結

鏈表刪除節點的**標準模式**是:

  1. 維護 `prev`、`curr` 雙指針遍歷
  2. 找到目標:`prev->next = curr->next`
  3. 釋放:`free(curr)`
  4. 結束:`return` 或 `curr = prev->next` 繼續遍歷(刪除多個匹配項)

方法二只是將 `curr` 先存入 `temp` 再移動 `curr`,本質完全一致。掌握雙指針模式,即可應對所有單向鏈表刪除場景。

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