1、递归相关概念
我们先来看一个耳熟能详的故事:
从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事,故事的内容是:从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事,故事的内容是:从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事,故事的内容是:…
我们发现,这个故事有个特点:不断地循环自身。这就是递归。递归式编程世界中一个非常重要,也特别难的概念,同时它也是算法的基础。很多复杂的问题,如果去使用递归的思想去思考,会发现简化了很多。
举例:
阶乘计算
n! = 1 * 2 * 3 * 4 * ...... * (n-1) * n
我们可以使用一个循环来实现:
public static int factorial(int n) {
int num = 1;
for (int i = 1; i <= n; i++) {
factorial *= i;
}
return factorial;
}
也可以实现递归来实现:
将上面的公式简化,如果用数学公式来表示,可以简单理解为:
f(1) = 1
f(n) = f(n-1) * n
当 f(n) = f(n-1) * n
,这其实就是一种递归的概念,我们为了求 f(n)
,不需要关心其他的,只需要知道它是在 f(n-1)
的基础上乘以 n 就可以得到
即:在求
f(n)
的时候,我们假设已经搞定f(n-1)
了,我们只需要考虑在f(n-1)
的基础上需要增加什么操作就可以了
代码如下:
public static int factorial(int n) {
// 当 n = 1 时,递归结束
if (n == 1) {
return 1;
}
// 把 factorial(n - 1) 的结果和 n 相乘,剩下的交给 factorial(n - 1) 来解决
return n * factorial(n - 1);
}
2、递归的实现
根据上面的示例,可以总结一下递归的特点:
-
基准条件
基准条件也可以理解为递归的结束条件
如果没有结束条件,就会出现死循环,这点很重要
如阶乘中的代码,如果去掉这部分:
if (n == 1) { return 1; }
最终代码如下:
public static int factorial(int n) { return n * factorial(n - 1); }
阶乘的结果将是:
n! = n * (n - 1) * ... * 1 * 0 * -1 * -2 * ...
这将是一个死循环
所以上面的
if (n == 1)
这个结束条件,或者叫作基准条件非常重要 -
递归公式
解决了递归的基准条件后,就需要考虑接下来该如何执行,也就是考虑递归公式
对于递归公式很容易找到
f ( n ) = n ∗ f ( n − 1 ) f(n) = n * f(n-1) f(n)=n∗f(n−1)
递归公式总是描述自己和下一个递归函数直接的递进关系
总结一下,在之后遇到递归的类似问题时,我们可以按照如下步骤思考:
- 找出基准条件
- 思考在基准条件下,会出现什么情况
- 思考基准条件的前一步的情况,或者函数执行情况
- 配合递归公式,继续往前推进
- 最后实现完善的代码
最后再用一个经典的斐波那契数列的例子来加深理解:
public static int fibonacci(int n) {
if (n == 0 || n == 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
希望本文能够得到您的认可~~~如果觉得本文有用的话记得来个 点赞 + 关注,或者分享给身边的朋友们,我们一起加油!