C语言如何原地修改链表并返回头节点?LeetCode19题代码排查
问题描述
正在LeetCode平台完成19. 删除链表的倒数第N个结点题目,最初认为该题实现逻辑较为简单,编写的实现代码如下:
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){ int count = 1; struct ListNode* curr_node = head; while (curr_node->next) { curr_node = curr_node->next; count++; } int forward = count-n; count = 0; curr_node = head; while (count < forward) { curr_node = curr_node->next; count++; } struct ListNode * next_node = curr_node->next; struct ListNode final_before = *curr_node; final_before.next = next_node->next; return head; }
但实际运行时上述代码完全没有修改传入的head节点关联的链表内容,核心疑问为:在C语言中应当如何对链表进行原地修改?
问题原因
代码完全不生效的核心错误是操作了临时副本,没有触碰原链表:
- 代码中
struct ListNode final_before = *curr_node;会把curr_node指向的原节点的全部内容,拷贝一份存储在栈上的临时变量final_before中,后续修改final_before.next仅仅是改动了这个临时拷贝的成员,原链表对应节点的next指针没有发生任何变化。函数执行结束后临时变量被系统回收,原链表自然不会有任何改动。 - 原有逻辑还存在边界漏洞:当传入的n等于链表总长度时,需要删除的就是头节点本身,现有逻辑会访问空指针触发运行错误。
C语言链表原地修改方法
链表原地修改的核心原则非常明确:直接通过指针操作原节点的成员,不要对节点结构体做值拷贝后修改副本。如果需要修改某个节点的next指向,必须拿到该节点在内存中的真实地址(即指向该节点的指针),直接对指针指向的原结构体成员赋值。
针对这道题的正确实现步骤:
- 第一次遍历链表统计总节点数,计算待删除节点从头开始的位置
- 单独处理待删除节点为头节点的边界场景,直接返回头节点的next作为新链表头
- 遍历定位到待删除节点的前驱节点,直接修改前驱节点的next指针,使其指向待删除节点的next,完成节点摘除
参考修正代码:
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){ int count = 0; struct ListNode* curr = head; // 统计链表总长度 while (curr != NULL) { count++; curr = curr->next; } int remove_idx = count - n; // 处理删除头节点的边界情况 if (remove_idx == 0) { return head->next; } // 定位到待删除节点的前驱节点 curr = head; for (int i = 0; i < remove_idx - 1; i++) { curr = curr->next; } // 直接修改原节点的next指针,完成原地删除 curr->next = curr->next->next; return head; }
拓展:该题也可以用快慢指针实现单次遍历,不需要提前统计链表长度,本质逻辑完全一致,都是通过指针直接操作原节点成员,不存在节点结构体的拷贝。
内容的提问来源于stack exchange,提问作者zeroclaim
相关产品推荐
相关产品推荐

