You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求逐行解析单链表删除函数的指针版实现(仅用单个指针变量)

单链表删除函数(单指针+指针的指针实现)逐行解释与可视化

首先明确链表节点的定义(和原书一致):

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);
    }
}

逐行解释

  1. void delete_from_list(struct node **list, int n) {

    • 函数接收指向链表头指针的指针和要删除的节点值n;因为直接通过指针的指针修改原链表的指针,所以不需要返回值。
  2. while (*list != NULL && (*list)->data != n) {

    • 循环条件:当前*list(即当前遍历到的节点指针)不为空,且当前节点的data不等于目标值n。初始时*list就是链表的头节点指针。
  3. list = &(*list)->next;

    • 核心逻辑:把list更新为当前节点的next指针的地址。这样下一次循环时,*list就会变成下一个节点的指针。这一步相当于用list跟踪"当前要检查的节点的指针所在的内存位置",替代了原版本中prev的作用——当找到目标节点时,list指向的要么是头指针的地址,要么是前驱节点next指针的地址。
  4. }

    • 循环结束时,要么*list为空(没找到目标节点),要么*list就是要删除的节点的指针。
  5. if (*list != NULL) {

    • 确认找到目标节点,才执行删除操作。
  6. struct node *temp = *list;

    • 保存要删除的节点指针到temp,因为接下来要修改*list,之后会丢失该节点的地址,需要先保存以便释放内存。
  7. *list = (*list)->next;

    • 关键操作:修改list指向的那个指针(可能是头指针,也可能是前驱节点的next指针),让它指向要删除节点的下一个节点。这就完成了链表的"跳过"操作,把要删除的节点从链表中移除。
  8. free(temp);

    • 释放被删除节点的内存,避免内存泄漏。
  9. }

  10. }

可视化说明

用文本结构展示不同场景下的执行过程:

场景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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 06:15:41