链表回文判断C语言代码输入1,2,1,1时失效的错误排查
问题描述
现有C语言实现的链表回文判断功能,多数测试用例运行正常,但输入节点序列为1、2、1、1时会返回错误判断结果。
相关代码
- 反转链表函数前置声明 + 链表节点计数函数
ListNode *reverseLL(ListNode*); int nodeCounter(struct ListNode* head){ struct ListNode* ptr=head; int counter=0; while(ptr!=NULL){ counter++; printf("%d ",ptr->val); ptr=ptr->next; } return counter; }
- 回文判断主逻辑
bool isPalindrome(struct ListNode* head){ struct ListNode *revhead=reverseLL(head); int length=nodeCounter(head),mid=length/2,count=0; struct ListNode *ptr=head; struct ListNode *ptr1=revhead; while(length!=mid){ printf("\n %d == %d",ptr->val,ptr1->val); if(ptr->val!=ptr1->val){ printf("in"); return 0; } ptr=ptr->next; ptr1=ptr1->next; length--; } return true; }
错误根因定位
核心问题出在对原链表做原地全反转后,仍用原头节点指针遍历原链表:
- 代码中调用的
reverseLL是原地反转实现,执行时会直接修改原链表所有节点的next指针指向,反转完成后,传入的原head指针不再是原链表的头节点,而是反转后链表的尾节点,其next指针最终会指向NULL。 - 代码执行顺序存在逻辑漏洞:先执行全链表反转,再调用
nodeCounter(head)统计长度。此时从原head(反转后的尾节点)出发遍历,根本无法遍历到所有节点,统计出的长度完全错误。
以输入1->2->1->1为例复现错误流程:
- 反转前链表结构:
节点A(1) -> 节点B(2) -> 节点C(1) -> 节点D(1) -> NULL,原head指向节点A - 原地反转后链表结构:
节点D(1) -> 节点C(1) -> 节点B(2) -> 节点A(1) -> NULL,revhead指向D,原head仍指向A,而A的next已经被修改为NULL - 调用
nodeCounter(head)时从A出发遍历,仅能统计到1个节点,计算得到length=1、mid=0 - 循环仅执行1次:比对A的值1和D的值1,判定相等后
length减为0,直接退出循环返回true,完全没检测到后续节点值不匹配的问题,最终判断错误。
修复方向
- 不要直接对整个原链表做原地全反转后再遍历原头指针,这种写法会彻底破坏原链表结构,导致遍历逻辑完全失效。
- 常规O(1)空间的正确实现逻辑:
- 先遍历原链表统计总长度,定位到链表中间节点
- 仅原地反转链表的后半段,不修改前半段的指针指向
- 用两个指针分别从原链表头、后半段反转后的新头出发,逐节点比对值,全部匹配则为回文
- 比对完成后可再次反转后半段,恢复原链表结构
- 如果不需要严格限制空间复杂度,更简单的写法是先遍历链表把所有节点值存入顺序数组,再用双指针从数组头尾向中间逐位比对,代码逻辑更简单,不容易出现指针操作错误。
内容的提问来源于stack exchange,提问作者flanker99
相关产品推荐
相关产品推荐

