前言
链表反转是一个很重要的内容,因为它不仅涉及到链表的增加,删除,对思维的能力考察也要求严格。在各类热门面试题中,处于居高不下的地位。
本次我们探讨的是LeetCode206题:给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
建立虚拟头节点辅助反转
如上图,我们先建立应该新节点ans,使ans->next=head,在这里,我们让虚拟节点为
ans->next=node(1),之后只需要将后面的节点插入到中间对应位置即可,在这里要注意cur的移动,cur=next。即在第一步中,应为:cur->next=ans->next;ans->next=cur;cur=next;最后,我们只需要返回ans->next
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* ans=(struct ListNode*)malloc(sizeof(struct ListNode));
ans->next=NULL;
struct ListNode* cur=head;
while(cur->next!=NULL){
struct ListNode* next=cur->next;
cur->next=ans->next;
ans->next=cur;
cur=next;
}
return ans->next;
}
直接操作链表实现反转
虽然利用虚拟节点操作链表反转会比较简单,但正是因为比较简单,在面试中可能不会被面试官认可,那我们怎样不利用虚拟节点进行操作呢?还是什么那一道题,我们首先根据中间过程进行分析。
从图中我们可以看出,只需要将cur->next=pre;pre=cur;cur=next;既可以完成,下面上代码:
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* pre=NULL;
struct ListNode* cur=head;
while(cur!=NULL){
struct ListNode* next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
return pre;
}
这个地方,我们从中间部分的变化更好理解。
除了这两种方法,还有便是递归,下面我们一起来看看。
利用递归实现链表反转
我们直接先上代码:
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL||head->next==NULL){
return head;
}
struct ListNode* new_head=reverseList(head->next);
head->next->next=head;
head->next=NULL;
return new_head;
}
现在我们通过画图来理解一下这串代码的意思:由于一号节点不为空,所以new_head为2,二号节点也不为空,所以new_head为3......同理,直到五号节点的next为NULL,因此,执行 head->next->next=head;
head->next=NULL;
return new_head;此时new_head为5,而head为4,因此head->next为5,即5->next=4,之后为 4->next=NULL,这样便实现了一次反转。
下面以3->4->5为例
可以看出head与new_head的变化,下面是整个链表的变化: