單向鏈表刪除節點本質是:**修改前驅節點的 `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;
}
#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;
}
鏈表刪除節點的**標準模式**是:
方法二只是將 `curr` 先存入 `temp` 再移動 `curr`,本質完全一致。掌握雙指針模式,即可應對所有單向鏈表刪除場景。