递归(二)

  • 之前很少接触递归,最近在学习《算法4》一书。该书课后习题要求使用递归和迭代方式解决问题,本人觉得迭代方式更加符合正常的逻辑思维。应要求不得不编写递归方式,不过在专研递归时,让我产生新的思路,让我对递归产生一种又爱又恨的感觉。
  • 本书的104页练习题1.3.30

编写一个函数,接受一条链表的首节点作为参数,将链表反转并返回结果链表的首结点

  • 首先来看迭代版本的思路,将原链表看做两个链表,一个是正序链表一个是反序链表。首先搞清楚怎样的顺序才算作反转。请看下图迭代版
  • 由于使用的链表为单向链表没有pre,所以不能从尾部开始,依次将second.next = first;,无法保存前一个结点的信息。所以出现如图所示的思路,将整个链表分作两部分。reverse始终指向指向反序链表的首部,firstsecond分别指向正序链表的尾部。正序的first结点指向reversereverse结点向前移动(reverse始终指向反序链表的首结点),正序部分的first,second结点后移一位。代码如下
public Node reverse(Node x){
        Node first = x;
        Node reverse = null;
        while(first != null){
            //记录等待反转操作链表首节点的下一个结点
            Node second = first.next;
            //reverse为反转链表的首节点
            //将要插入反转链表的结点指向当前反转链表首结点
            first.next = reverse;
            //首节点插入之后reverse结点向前移动
            reverse = first;
            //等待反转操作的链表首节点
            first = second;
        }
        return reverse;
    }
  • 回到主题—递归。受到迭代版思路的影响,还是第一个想到将整个链表分成两部分(正序和反序),花费了一天时间,想破脑袋也没想通代码的写法。首先考虑我们要返回的是下一个结点还是返回second.next = first的关系。如果要返回下一个结点,那我们没有必要使用递归,直接使用first.next返回即可。如果返回两个结点之间的关系,就我目前水平不能实现。给出课本自带的实现代码
public Node reverse_recursive(Node first){
        if(first == null) return null;
        if(first.next == null) return first;
        Node second = first.next;
        Node rest = reverse_recursive(second);
        second.next = first;
        first.next = null;
        return rest;
    }
  • 如果是按照迭代版思路,那么一定会卡在寻找反序首节点和前两个结点与第三个结点之间没有关联等问题,这也有由于本人对递归根本不熟悉的原因。
  • 在使用IDEA进行调试递归代码时,发现每个迭代过程都有自己的递归栈。如下图递归栈
  • 上图栈**[6]**中保存最后一个结点,我们可能会产生一个思路[6].next = [5],[5].next = [4] ...。这是一个不错的思路,但是如何编写代码。结合上面给出的课本参考代码,发现rest始终作为反序链表首节点。真正的子问题是 second.next = first; first.next = null;可以很容易明白原本结点first指向结点second,现在改为结点second指向结点first。但是第二个结点如何与第三个结点建立关系的?观察递归栈,递归栈中保存着first,second等局部变量。举个例子,第5层栈中保存的second变量就是第6层first变量。那么层与层之间的关联不就建立起来了嘛。下面是示意图递归实现链表反转
  • 细细品味上面那段代码,越发的觉得其实现算法的精妙。它巧妙地运用了递归栈保存变量信息,并且每层的变量之间不会产生影响。迭代的思路也很清奇,它进行递归并不会产生一个新的结果(rest始终为反序的首节点),只是为了让firstsecond结点之间的指向反转,并利用递归栈性质建立两个结点与第三个结点之间的关系。
  • 哈哈,刚刚接触到算法,可能是本人少见多怪吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值