翻转单链表细节讲解
Posted 流楚丶格念
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了翻转单链表细节讲解相关的知识,希望对你有一定的参考价值。
文章目录
问题导入
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
完整代码如下
class Solution
// 迭代
public ListNode reverseList1(ListNode head)
ListNode pre=null;
ListNode cur=head;
while(cur!=null)
ListNode tmpNext = cur.next;
cur.next=pre;
pre=cur;
cur = next;
return pre;
// 递归
/*
看了半个小时可算是把这个递归看懂了!不妨假设链表为1,2,3,4,5。按照递归,当执行reverseList(5)的时候返回了5这个节点,reverseList(4)中的p就是5这个节点,我们看看reverseList(4)接下来执行完之后,5->next = 4, 4->next = null。这时候返回了p这个节点,也就是链表5->4->null,接下来执行reverseList(3),代码解析为4->next = 3,3->next = null,这个时候p就变成了,5->4->3->null, reverseList(2), reverseList(1)依次类推,p就是:5->4->3->2->1->null
*/
public ListNode reverseList(ListNode head)
// 递归终止条件
if(head==null||head.next==null)
return head;
ListNode p = reverseList(head.next);
// 它下一个的下一个改为本身
// 也就是 原来是4->5 改为 5->4 head.next=5 5.next=4 再让4.next=null p是5 再返回5 依次递归
head.next.next = head;
head.next = null;
return p;
我们可以使用两个方法,下面我们对这两个方法进行讲解
原理剖析
迭代
首先给你一个链表,我们给定一个pre
pre=null;
当前的curr结点就是头结点
curr = head;
如果是翻转第一个,我们只需要
curr.next = pre;
就可以了
然后让pre和curr都向后移动一位
pre = 之前的curr;
curr = 之前的curr的next;
之后再不断执行上面循环就行了
curr.next = pre;
pre = 之前的curr;
curr = 之前的curr的next;
…
直到最后一个翻转
最后的状态是这样的
有一个问题:怎么往后移动?
这是理想的逻辑,但是我们在写代码的时候就会有一个问题:让pre与curr往后移动一位的时候,pre还好说,让pre = curr;
就好了,但是已经执行了curr.next = pre;
,curr怎么获取之前的curr的next
呢?
相信很多小伙伴们写代码的时候就困惑住了,就觉得这样行不通,然后就…放弃了
别激动,既然没有,我们提前存一下就好了,设置一个临时结点去存储之前的curr的next
ListNode tmpNext = cur.next;
然后之前的代码
pre = 之前的curr;
curr = 之前的curr的next;
就可以替换为:
// 存储之前的curr的next
ListNode tmpNext = cur.next;
// 翻转当前结点指向
cur.next=pre;
// 向下移动 pre与cur
pre=cur;
cur = next;
然后我们需要不断执行这几个操作,所以他们要套在循环里:
while(cur!=null)
ListNode tmpNext = cur.next;
cur.next=pre;
pre=cur;
cur = next;
再开头我们需要定义pre与curr:
ListNode pre=null;
ListNode cur=head;
最后我们只需要返回pre就可以了
OK,完整代码就如下所示:
// 迭代
public ListNode reverseList1(ListNode head)
ListNode pre=null;
ListNode cur=head;
while(cur!=null)
ListNode tmpNext = cur.next;
cur.next=pre;
pre=cur;
cur = next;
return pre;
递归
说完了上面的迭代法,下面我们说说递归,可能很多小伙伴会疑惑?这也能用递归???
那是肯定的,我们先回顾一下递归的思想
其实很简单,把递归两个字拆开就可以了:
- 递:有相同的执行逻辑,能一层层的往下递推下去
- 归:有终止逻辑,最终有相同的归操作,能一层层的向上返回来
那么对于这一个链表的翻转,我们其实可以分解成两个子问题:
- 翻转头结点
- 翻转除了头结点之外的结点
那么我们可不可以往下递呢?当然是可以的,我们可以把剩下的结点继续拆分
- 翻转剩下链表的头结点
- 翻转除了剩下链表的头结点之外的结点
那么他能不能归回来呢?当然是可以的,要归的话首先我们要有终止条件,终止条件我们往往看最后一个递归调用最为明显(也就是这个问题的最小拆分):
最后是这样的:
我们可以发现当如下条件的时候就可以进行递归终止了
head==null||head.next==null
有了终止条件,我们就需要完成递归中的归操作,我们进行翻转也是在归操作中进行的
翻转操作如下,让当前头结点的next的next指向当前头结点,头结点的next指向null
// 它下一个的下一个改为本身
head.next.next = head;
head.next = null;
最终代码如下:
public ListNode reverseList(ListNode head)
// 递归终止条件
if(head==null||head.next==null)
return head;
ListNode p = reverseList(head.next);
// 它下一个的下一个改为本身
head.next.next = head;
head.next = null;
return p;
以上是关于翻转单链表细节讲解的主要内容,如果未能解决你的问题,请参考以下文章
Java算法 -- 单链表的反转单链表实现栈和队列以及双端队列K 个一组翻转链表