递归——很常见的一种编程技巧

什么是递归?(what)

  • 递归时一种应用广泛的算法(或者编程技巧),很多算法的编码实现都要用到递归,比如DFS深度优先搜索、前中后序二叉树遍历等;
  • 所有的递归问题都可以用递推公式来表达:f(n)=f(n-1)+a,f(1)=b;
    -递归就是函数调用函数本身,函数有返回值,并在一定条件下终止调用一层层返回。
  • 递归,函数调用自身:递 ,函数有返回值:归;

为什么用递归?(why)

优点:代码表达力强,简洁;
缺点:空间复杂度高,有堆栈溢出风险,存在重复计算可能,以及过多的函数调用会比较耗时;

什么样的问题用递归?(when)

  1. 一个问题的解可以分解为几个子问题的解;
    例如 f(n)=f(n-1)+f(n-2);
  2. 这个问题与分解的子问题,除数据规模不同,求解思路完全一样;
    例如 f(n)=f(n-1)+f(n-2); n 、n-1 、 n-2只是数据不同但求解函数一样都是f
  3. 存在递归终止条件;
    例如 f(1)=1;

怎样编写递归代码?

理解

写出递推公式,找到终止条件

递归其实就是一个方程式:f(n) = f(n-1) + a;也就是说在设计递归的时候应该考虑下面三个方面:

  1. 求解f(n)的时候,假设f(n-1)已经求解出来了。我们不要去考虑f(n-1)是如何求解出来的。
  2. 关键点在于找到递归的终止条件。
  3. 递归往往和分治法是分不开的。对于复杂的递归,往往将递归拆分,然后再合并。
步骤

写一个递归方法。

  1. 先写判断递归结束时候的操作;
  2. 再写递归分解操作
栗子

汉诺塔问题就是使用典型的递归思想。
先推导最简单的f(2),从而推f(n)的解可以分为:

  1. 将 n-1 个圆盘从 from -> buffer
  2. 将 1 个圆盘从 from -> to
  3. 将 n-1 个圆盘从 buffer -> to
  4. 以上三步都是为了求解f(n),最后我们给出递归结束的条件。只有一个圆盘的时候,只需一次移动操作即可from -> to。
/**
     * 汉诺塔问题
     */
    public static void move(int n,String from,String buffer,String to){
        if(n==1){
            System.out.println(from+"—>"+to);
            //必须有return
            return;
        }
        move(n-1,from,to,buffer);
        move(1,from,buffer,to);
        move(n-1,buffer,from,to);
    }

电影院问座位第几排问题,f(n)=f(n-1)+1,f(1)=1,

	/**
     * 电影院座位排数问题
     * @param n 前面一排
     * @return
     */
    public static int ask(int n){
        if(n==1){
            return 1;
        }
        return ask(n-1)+1;
    }

注意点

1.警惕堆栈溢出:

递归用的是系统栈或者虚拟机函数调用栈,栈空间一般都不大,
如果递归求解的数据规模很大,调用层次很深,一直压入栈,就会有堆栈溢出的风险。
可以声明一个全局变量来控制递归的深度,从而避免堆栈溢出。

2.警惕重复计算:

例如 f(n)=f(n-1)+f(n-2) , f(5)=(f4)+f(3),f(4)=f(3)+f(2),这里f(3)重复计算
通过散列表来保存已经求解过的值,从而避免重复计算。

熄灯

  • 递归必须有函数调用函数自身;
  • 递归必须有return;
  • 写递归代码的关键就是找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,然后再推敲终止条件,最后将递推公式和终止条件翻译成代码。
  • 编写递归代码的关键是,只要遇到递归,我们就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解递归的每个步骤。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小技工丨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值