【一起学数据结构与算法分析】第三篇:递归的4条设计原则

递归相信大家都很熟悉,简单来说,就是把一个很大的东西按照相同的模式回归到一个确定的点上。

比如说爬楼梯,如果一个人一步能跨2个台阶,现在问:他第100步能跨到第几个台阶上?
在这里插入图片描述

有人说200,很明显不对,因为老朽没说他最开始在哪个台阶上,如果最开始就在第200个台阶上,那答案就是200 + 200 = 400了。

我们可以简单的列个等式:H(n) = H(n - 1) + 2, H(0) = C(n >= 1,C为常量),这样才能求解H(100) = 400。

所以说,没指定初始值的递归都是耍流氓!

由此我们不禁要问:正确的递归应该满足哪些原则呢?

其实书本已经写得很清楚了:
在这里插入图片描述
其中第1条和第2条就是指我上面说的,很好理解,需要注意的是”朝向基准“这个关键词,朝向基准更多地是强调收敛,而不是单调,如F(n) = (-1)^n * F(n - 1),F(0) = 1, (n为不小于1的正整数)不单调,但同样可以求。

第3条就是说你每个递归都是可执行的,再举上面爬台阶的例子,你必须能保证一步跨出后就是”增加“2层,这样我们才能”准确“地计算出下一层是多少。不能说搞不好哪步跨不上去,这样预估的结果肯定不具有唯一性。

最难理解的可能是第4条:合成效益法则,因为这条与程序的正确性无关,但同时也是程序员最容易损失性能的地方!

就拿斐波那契数列F(n) = F(n - 2) + F(n - 1)来说,我们很容易写出如下的递归算法:

/**
     * Retrieve Fibonacci result by recursion.
     * F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
     */
    private fun fibonacci(n: Int): Int {
        // Ignore parameter checking!!!
        // Decide the basic point.
        return when(n) {
            0 -> 0
            1 -> 1
            else -> fibonacci(n - 1) + fibonacci(n - 2)
        }
    }

代码确实很简洁,但是有没有发现n-1以下均被执行了double。
在这里插入图片描述
也就是说在不同的递归里做了重复的动作,如上图求F(n)计算了F(n - 2),但是求F(n - 1)同样计算了F(n - 2),这就违背了第4条的合成效益法则。
那么正确地做法是什么样的呢?就不用递归呗,直接上代码吧。

/**
     * Retrieve Fibonacci result by eliminating repeated works in recursion.
     * F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
     */
    private fun fibonacciPlus(n: Int): Int {
        // Ignore parameter checking to ensure n >= 2.
        // Declare an array to store Fibonacci numbers.
        val storeArray = Array<Int>(n + 2) { it }
        storeArray[0] = 0
        storeArray[1] = 1
        for(i in 2 .. n) {
            //Add the previous 2 numbers in the series and store it.
            storeArray[i] = storeArray[i - 1] + storeArray[i - 2]
        }
        return storeArray[n]
    }

最后,大家跟老夫一起默念一下递归的四个原则。

git: https://github.com/codersth/dsa-study.git
文件:Recursion4Principles.kt

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Meta章磊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值