题目:
接口:
原链表
这里我用了两种来解决。
方法一.迭代法
思路:
既然要使链表反转,那么原本n1->next=n2,n1指向n2(即n1存储n2的地址),就反转成n2指向n1(即n2存储n1的地址),这样两个节点就可以反转了。
但这样会出现一个问题,n2->next存储的是n1的地址,却丢失了原本下一个节点的地址(即原来指向该节点的指针丢失了),会造成内存泄漏导致该节点无法访问,所以需要一个n3来保存下一个节点地址。
错误以及逆转如图
解决方法:再用一个指针n3在进行逆转前存储下一个节点的地址,n3=n2->next将下一个节点地址存储防止丢失,n3做到的就是帮助n2找到下一个节点,并且还能通过n3遍历逆转。
如图:
遍历迭代过程,根据我自己的习惯,喜欢画图进行分析,如下方GIF可以清晰得看出递归逆转的过程,就需要将n2的地址赋给n1,n3的地址赋给n2,n3存储下一个节点则n3=n2->next,当n2下一个节点地址存储好后,这时再进行逆转,
以上应该能够知道如何递归逆转,那何时结束呢?
是当n2==NULL的时候,return n1,当n2==NULL的时候n1才到最后一个节点的位置,n1才存储下最后一个位置。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
if(head == NULL || head->next == NULL){
return head;
}
struct ListNode* n1 = NULL;
struct ListNode* n2 = head;
struct ListNode* n3 = n2->next;
while(n2){
//存储下一个节点的地址
n3 = n2->next;
//逆转
n2->next = n1;
//迭代
n1 = n2;
n2 = n3;
}
return n1;
}
方法二.头插法
思路:
在单链表初步学习中学习到了头插,将这思路运用到逆转中,从头节点开始向新链表中依次头插,就能够达到反转的效果
将原链表从head开始头插进新链表中,但也就意味着原本存储原链表下一个节点地址的指针指向了新链表,那么意味着下一个节点内存泄露,丢失其地址。
所以需要next来存储下一个节点的地址。
由此我们可知我们需要三个指针,cur记录当前需要头插的节点,next记录下一个节点,newNode为新链表的尾指针所以为NULL 。
struct ListNode* cur = head;
struct ListNode* newNode = NULL;
将cur头插到newNode中,需要连接newNode与cur(对头插还有疑惑的,多看下,多画下单链表头插的过程)。头插完成,根据题目最后要输出反转后的链表的头指针,所以newNode也要前进,进行遍历,先将newNode移至已经头插完毕的节点处,通过next将cur移至下一个节点,next再存储下一个节点的位置。
图像化展示
while(cur){
cur->next = newNode;
newNode = cur;
cur = next;
next = next->next;
}
▲注意▲,遍历反转循环结束的条件时cur==NULL(不以next=NULL为条件判断,当next==NULL时,还没头插最后一个)就要注意,next一直都是cur下一个节点,那么当cur==NULL时,next再继续访问,会出现段错误,尝试访问NULL指针所指向的内存是非法的。
所以需要加一个判断这段循环应该是这样
while(cur){
cur->next = newNode;
newNode = cur;
cur = next;
if(next){
next = next->next;
}
}
▲没有节点和只有一个节点也不会有问题,如果head==NULL那么循环就不会开始,返回的newNode也是NULL,只有一个节点进入循环,也就是头插一个节点,返回也没问题。
这就对了吗 no ! No! ! NO! ! !
这里由于个人习惯,我将next的声明在循环外,也就是
struct ListNode* cur = head;
struct ListNode* newNode = NULL;
struct ListNode* next =cur->next;
这里就会出现一个错误,如果链表为空呢,或者只有一个节点呢,会出现空指针错误,那么next就是访问NULL指针所指向的内存。
所以应该定义在循环之内,综上就可以得出完整的代码如下
完整代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* cur = head;
struct ListNode* newNode = NULL;
while(cur){
struct ListNode* next = cur->next;
cur->next = newNode;
newNode = cur;
cur = next;
if(next){
next = next->next;
}
}
return newNode;
}