请求逐行解析单链表删除函数的指针版实现(仅用单个指针变量)
单链表删除函数(单指针+指针的指针实现)逐行解释与可视化
首先明确链表节点的定义(和原书一致):
struct node { int data; struct node *next; };
原书双指针实现(对比用)
原书17.5章的delete_from_list用cur和prev两个指针遍历:
struct node *delete_from_list(struct node *list, int n) { struct node *cur, *prev; for (cur = list, prev = NULL; cur != NULL && cur->data != n; prev = cur, cur = cur->next) ; if (cur == NULL) return list; if (prev == NULL) list = list->next; else prev->next = cur->next; free(cur); return list; }
指针的指针版实现(单指针逻辑)
你找到的实现代码如下:
void delete_from_list(struct node **list, int n) { while (*list != NULL && (*list)->data != n) { list = &(*list)->next; } if (*list != NULL) { struct node *temp = *list; *list = (*list)->next; free(temp); } }
逐行解释
void delete_from_list(struct node **list, int n) {- 函数接收指向链表头指针的指针和要删除的节点值
n;因为直接通过指针的指针修改原链表的指针,所以不需要返回值。
- 函数接收指向链表头指针的指针和要删除的节点值
while (*list != NULL && (*list)->data != n) {- 循环条件:当前
*list(即当前遍历到的节点指针)不为空,且当前节点的data不等于目标值n。初始时*list就是链表的头节点指针。
- 循环条件:当前
list = &(*list)->next;- 核心逻辑:把
list更新为当前节点的next指针的地址。这样下一次循环时,*list就会变成下一个节点的指针。这一步相当于用list跟踪"当前要检查的节点的指针所在的内存位置",替代了原版本中prev的作用——当找到目标节点时,list指向的要么是头指针的地址,要么是前驱节点next指针的地址。
- 核心逻辑:把
}- 循环结束时,要么
*list为空(没找到目标节点),要么*list就是要删除的节点的指针。
- 循环结束时,要么
if (*list != NULL) {- 确认找到目标节点,才执行删除操作。
struct node *temp = *list;- 保存要删除的节点指针到
temp,因为接下来要修改*list,之后会丢失该节点的地址,需要先保存以便释放内存。
- 保存要删除的节点指针到
*list = (*list)->next;- 关键操作:修改
list指向的那个指针(可能是头指针,也可能是前驱节点的next指针),让它指向要删除节点的下一个节点。这就完成了链表的"跳过"操作,把要删除的节点从链表中移除。
- 关键操作:修改
free(temp);- 释放被删除节点的内存,避免内存泄漏。
}}
可视化说明
用文本结构展示不同场景下的执行过程:
场景1:删除头节点(目标值为1)
初始链表:
头指针 → [data=1, next→] → [data=2, next→] → [data=3, next=NULL]
- 初始
list指向头指针的地址,*list是头节点(data=1),循环条件不满足,直接进入删除逻辑。 temp指向[data=1,...],*list = (*list)->next将头指针改为指向[data=2,...]。- 释放
temp后,链表变为:
头指针 → [data=2, next→] → [data=3, next=NULL]
场景2:删除中间节点(目标值为2)
初始链表:
头指针 → [data=1, next→] → [data=2, next→] → [data=3, next=NULL]
- 第一次循环:
*list是[data=1,...],data≠2,list变为指向第一个节点的next指针地址,此时*list是[data=2,...]。 - 循环退出,执行删除:
temp指向[data=2,...],*list = (*list)->next将第一个节点的next改为指向[data=3,...]。 - 释放
temp后,链表变为:
头指针 → [data=1, next→] → [data=3, next=NULL]
场景3:删除尾节点(目标值为3)
初始链表:
头指针 → [data=1, next→] → [data=2, next→] → [data=3, next=NULL]
- 第一次循环:
*list是[data=1,...],data≠3,list指向第一个节点的next地址,*list变为[data=2,...]。 - 第二次循环:
*list的data≠3,list指向第二个节点的next地址,*list变为[data=3,...]。 - 循环退出,执行删除:
temp指向[data=3,...],*list = (*list)->next将第二个节点的next改为NULL。 - 释放
temp后,链表变为:
头指针 → [data=1, next→] → [data=2, next=NULL]
场景4:未找到目标节点
如果目标值为4,循环会一直执行到*list为NULL,此时跳过删除逻辑,链表保持原样。
内容的提问来源于stack exchange,提问作者Fary
相关产品推荐
相关产品推荐

