***由力扣某道题目引出的悲惨故逝***
此处贴上题目链接
https://leetcode.cn/problems/reverse-linked-list/
力扣206题
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表
(我能怎么办,你要不把我办了吧)
1.双指针写法(迭代法)
从前往后地把链表节点指针的指向反转。
代码思路:
-
初始化prev为NULL,表示反转后的链表头节点;
初始化cur为head,表示当前需要处理的节点;
-
进入循环,当cur不为NULL时执行以下操作:
- 保存cur的下一个节点到temp中,以便后续操作;
- 将cur的next指针指向prev,实现反转;
- 将prev更新为cur,表示当前节点已经处理完毕;
- 将cur更新为temp,继续处理下一个节点;
-
循环结束后,prev指向反转后的链表头节点,将其返回作为结果
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* prev = NULL; // 初始化prev为NULL
struct ListNode* cur = head; // 初始化cur为head
while (cur) {
struct ListNode* temp = cur->next;
// 保存cur的下一个节点到temp中
cur->next = prev;
// 将cur的next指针指向prev,实现反转
prev = cur;
// 将prev更新为cur
cur = temp;
// 将cur更新为temp,继续处理下一个节点
}
return prev; // 返回反转后的链表头节点
}
2.递归法
利用递归 实现链表的反转
递归跳出循环的条件,应该有两个
当 p.next == null表明是最后一个节点,
另一个是P == null,这个时候说明传入时一个空节点,也要返回Null;
两个条件同时满足即可结束递归。
递归思路:
只要让每次进来的节点反转他们的指向,即可完成反转链表
如 传入的节点时 4 -> 5,现在使得5 -> 4
代码思路:
- 如果链表为空(
head == null
)或者只有一个节点(head.next == null
),则直接返回头节点,因为这种情况下链表已经是反转的了。 - 否则,递归调用
reverseList3(head.next)
,将子链表进行反转,得到反转后的最后一个节点last
。 - 将当前节点
head
的下一个节点的next
指针指向当前节点head
,实现当前节点与下一个节点的反转。 - 将当前节点
head
的next
指针置为null
,避免形成环。 - 返回反转后的最后一个节点
last
。
struct ListNode reverseList(ListNode head) {
if (head == null || head.next == null){
return head;//返回最后一个节点
}
//等所有递结束,开始归的时候调整我们的指针
ListNode last = reverseList(head.next);
head.next.next = head;
head.next = null;
//接收最后一个节点
return last;
}
3.就地逆置法
首先需要两个指针
为什么需要两个指针呢?
因为在操作的过程中需要取出中间的一个,这样就会导致后面的数据丢失,当我们有两个指针的时候就可以避免这种情况发生。
注意:在这里我们统一让链表头的不存入数据。
形象的可以把这四步操作总结为“连”,“掉”,“接”,“移”。
连:我们将beg->next=end->next,这样就会避免后面的数据丢失。
掉:接下来将end放在所有数据的前面,就是end->next=head->next。
接:这个时候就要把连移动的数据放在头指针的后面,即head->next=end。
移:最后就是要把下一个需要定义的数据往下移动一位,便是end=beg->next。
代码思路:
首先检查输入的链表是否为空或只有一个节点,如果是,则直接返回头指针。否则,它将使用两个指针(beg和end)来遍历链表并进行反转操作。
在循环中,函数将节点从原位置移除,并将其添加到新的位置。具体步骤如下:
- 将beg指针指向当前节点的下一个节点(即原位置的下一个节点)。
- 将end指针指向当前节点的下一个节点(即原位置的下下个节点)。
- 将beg指针的next指针指向end指针所指向的节点(即将原位置的节点从链表中删除)。
- 将end指针的next指针指向head指针(即将节点添加到链表的头部)。
- 更新head指针为end指针(即将head指针移动到当前节点的位置)。
- 更新end指针为beg指针的next指针(即将end指针移动到原位置的下一个节点)。
- 重复以上步骤,直到end指针到达链表的末尾。
最后,函数返回反转后的链表头节点。
struct ListNode* ReverseList(struct ListNode* head ) {
struct ListNode* beg=NULL;
struct ListNode* end=NULL;
if (head == NULL || head->next == NULL) // 空链或只有一个结点,直接返回头指针
{
return head;
}
else
{
//beg和end指针指向相应的head和head->next
beg=head;
end=head->next;
while(end!=NULL){
//摘下节点
beg->next=end->next;
//将节点添加到表头
end->next=head;
head=end;
end=beg->next;
}
}
return head;
}
4.栈
大概思路:根据栈的后进先出原理,让链表结点先进栈后出栈,就能得到逆序组合。
①在第一个while中,计算栈所需要的空间size。
②在第二个while中,将原链表中的结点地址进栈,注意是结点地址。
③在第三个while中,出栈并按照出栈顺序链接起来,形成新的链表。
代码思路:
首先检查链表是否为空或只有一个节点,如果是,则直接返回原链表头节点。
接下来,函数通过遍历链表来计算链表的长度,并将每个节点存储在一个栈中。然后,从栈顶开始逐个弹出节点,并将其连接起来,形成反转后的链表。
最后,将最后一个节点的next指针设置为NULL,表示反转后的链表结束。
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL||head->next==NULL){
return head;
}
int size=0;struct ListNode* p=head;
while(p!=NULL){
size++;
p=p->next;
}
struct ListNode*stack[size];
int top=-1;p=head;
while(p!=NULL){
stack[++top]=p;
p=p->next;
}
struct ListNode* head2=stack[top];
p=head2;
while(top!=-1){
p->next=stack[top--];
p=p->next;
}
p->next=NULL;
return head2;
}