python递归逆置一条单链表详解

递归逆置的做法真的很巧妙,最好画图自己想一下
我们的目标是:实现一个递归函数,给定一条单链表的首结点,逆置这条单链表,并返回逆置后的首结点

这种比较复杂的递归往往都有步骤可循,我常用的思路就是先写伪代码,按照边界条件,执行操作,返回操作的步骤来思考。
当然,第一步就是假设我们有这么一个递归函数reverse,它的功能就是给定一条单链表的首结点,逆置这条单链表,并返回逆置后的首结点
然后我们就可以写边界条件了,注意下面是类python的伪代码

  1. 边界条件

    if node==null or node.next==null:
    	return node
    

    很显然,结点为空或者结点只有一个的情况我们就直接返回node就好

  2. 关键操作+处理特殊条件
    这一步是最关键的,我们之前已经假设了拥有reverse函数,那么我们可以这样做
    对于当前的node,我们先逆置node.next

    tnode=reverse(node.next)	
    

    此时我们会获得以node.next为首结点逆置后的单链表
    ok,然后我们画图,分析一下当前的状况
    你有没有发现,reverse(node.next)之后,node.next就是逆置后的链表尾结点
    在这里插入图片描述
    现在我们需要,把node连接上这条逆置的单链表,你先想一下怎么做。
    答案就是这一行代码

    node.next.next=node
    

    如果到这里没看懂,或者觉得很抽象不好理解,建议自己多画图分析一下,弄懂了再往下看,经过这一步操作之后,链表会变成这个样子
    在这里插入图片描述
    看起来还不错,但是我们发现,node和node.next之间的链接没有断开 于是我们执行这一条语句

    node.next=null
    

    但是有的同学可能会问,这一步是必要的吗?因为我返回递归的时候,node.next.next=node不是会更改这个node指针吗?
    这条语句的确会更改node指针,但是如果是递归到首结点呢?
    在这里插入图片描述
    很显然我们如果没有node.next=null这条语句的话,那么这条逆置单链表最后一个结点的指针(node)是错的!,它本来应该指向null的!
    因此,下面这条语句是必须的

    node.next=null
    

    很完美,现在我们得到一条以node为首结点,逆置后的单链表了

  3. 返回条件
    别忘了我们的目标,返回逆置链表的首结点
    我们如何才能得到首结点呢?
    我们应该想到,对一条链表来说,逆置后的首结点就是逆置之前的尾结点。但是如何在这个递归函数里面返回这个尾结点呢?先回顾一下之前的代码
    到这里,我们已经有了如下的代码

def reverse(node):
	if node==null or node.next==null:
		return node
	tnode=reverse(node.next)	
	node.next.next=node
	node.next=null

我们先在草稿纸上面运行一下代码,发现,无论如何,在reverse(node.next)这行代码里面,node会一直传入node.next进去,循环往复,我们会得到什么? 没错,if node==null or node.next==null 这个返回条件里面,我们最终会得到 当前链表的尾结点
在这里插入图片描述
到最后一个结点的时候,此时tnode就是当前链表的尾结点了而node就是tnode的前一个结点

那我们应该返回tnode了

	return tnode

到此为止,完成的代码如下:

def reverse(node):
	if node==null or node.next==null:
		return node
	tnode=reverse(node.next)	
	node.next.next=node
	node.next=null
	return tnode

接下来我们看看执行代码会发生什么
我们执行

	node.next.next=node
	node.next=null

此时会发生什么?
在这里插入图片描述
看出来了吗?此时tnode=>node 已经被逆置了,这个时候会返回上一层,继续操作
在这里插入图片描述
以此类推,最终我们会得到
在这里插入图片描述
然后函数最终会返回tnode,而tnode始终都是最后一个结点,是没有改变的!!不信你可以在纸上模拟一下递归

最终代码如下

def reverse(node):
	if node==null or node.next==null:
		return node
	tnode=reverse(node.next)	
	node.next.next=node
	node.next=null
	return tnode

分析到现在,你可能发现,我们并没有一开始就去涉及递归函数怎么做,而是假设已经存在了这么一个递归函数,然后按照以下顺序分析我们需要进行的操作

  1. 递归边界 一般考虑边界条件,例如传入空结点 or 只有一个结点的情况
  2. 关键操作 如果有多个结点,那么我应该做什么一般(common)操作使得算法能达到我想要的效果
    1. 通过特殊情况来分析一般情况(例如上面的尾结点node.next指针问题)
    2. 通过画图来模拟递归,考虑最后一层递归时应该做的操作
  3. 返回条件,明白自己的返回条件,例如这一题就是取得逆置链表的最后一个结点

leetcode上面有原题,可以自己试着做一下
https://leetcode-cn.com/problems/reverse-linked-list/submissions/


class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if(head==None or head.next==None):
            return head
        first=self.reverseList(head.next)
        head.next.next=head
        head.next=None
        return first
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值