1.这种是我学习了一些其它三指针法链表逆置方法后,结合本人的强迫症最后得到的优美且健全的实现方案。循环条件是p3不为空,也就是最后一次进入循环条件时候p3的指向是原链表最后一个元素,完成最后一次循环后p2在原链表的末尾位置,也就是新链表的表头位置。所以,在改变p2指向后,返回的头指针是p2而不是p1。
//分两段逻辑处理节点:第1到n-1个节点,第n个节点
ListNode* reverse(ListNode* head) {
if(head==NULL) return NULL;
ListNode *p1 = NULL, *p2 = head, *p3=p2->next;
while (p3) {//处理第1到n-1个节点
p2->next = p1; //p2的指向反转
p1 = p2; //p1后移
p2 = p3; //p2后移,
p3=p2->next; //p3后移,
}//此时p2在最原链表最末端的节点位置,此时p2指向最后的NULL
p2->next=p1;//反转p2指向
return p2;
}
2.这是标准写法(我将变量名换成了我自己容易理解的p1\p2\p3),省去了对空链表的单独逻辑判断,但是声明p3的时候没有初始化以及p3后移的顺序在反转指针前面,让我感觉到“不美”,这种方法我大概率今天记了明天就忘了,所以我还是更加中意自己的第一种写法。还有区别是这个方法是利用p2不为NULL进入循环条件,故最后一次进入循环的时候p2指向的是原链表的最后一个节点,当执行完最后一次循环的时候,p1会后移到原链表的最后一个节点,所以最后链表反转后链头在p1上。
ListNode* reverse_standard(ListNode* head) {
ListNode *p1 = NULL, *p2 = head, *p3;
while (p2) {
p3 = p2->next; // 保存下一个节点
p2->next = p1; // 反转指针
p1 = p2; // p1前移
p2 = p3; // p2前移
}
return p1;
}
但是这种标准写法的好处在于保证了指针操作的“先保存、再操作、后移动”,所以自己应该要逐步适应这种规则。
3.还有一种写法
//分两段逻辑处理节点:第1到n-1个节点,第n个节点
ListNode* reverse(ListNode* head) {
if(head==NULL) return NULL;
ListNode *p1 = NULL, *p2 = head, *p3=p2->next;
while (p2) {
p2->next = p1; //p2的指向反转
p1 = p2; //p1后移
p2 = p3; //p2后移,
if(p2!=NULL) p3=p2->next; //p3后移,
}
return p1;
}
6571

被折叠的 条评论
为什么被折叠?



