“这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战”
关注我,以下内容持续更新
有一位大师曾经说过:人理解迭代,神理解递归。相信很多人在做递归算法时全靠感觉,其实我开始接触时递归时也是云里雾里的感觉,但是后来做了一些算法的题目然后查阅了相关资料对递归有了更加深入的理解.
递归的原理
-
递归的核心思想是分治策略,也就是将一个规模大的问题分解成一些规模小的同类问题,然后通过这些小问题求得大问题的解。
-
递归的底层原理是栈结构,栈是后进先出的数据结构,所以"递"的次序是正序,"归"的次序是逆序。
-
递归算法和分治法的区别:递归是算法的实现方式,分治是算法的设计思想。例如解决某个问题可以是分治法的思想,但不一定使用递归算法来实现。
递归的应用
本文通过用阶乘、斐波那契数列和计算最大公约数(辗转相除法)来介绍递归的入门
- 计算阶乘
int fact(int n){
if (n == 0) return 1;
return n * fact(n - 1);
}
//调用递归
int res = fact(10);
printf("%d\n", res);
递归过程请看下面的图解,为了方便理解,把return n * fact(n - 1)分解成两步int tmp = fact(n - 1)和return n * tmp(以后大家如果拿到一份递归算法不理解时,也可以通过这种方式来分解,便于理解),例如图解中执行递归fact(2)时,当执行到int tmp = fact(n - 1)时,立马暂停去执行了fact(1),当fact(1)执行到int tmp = fact(n - 1)时,又立马暂停去执行了fact(0),执行到这里,也就找到了递归的出口,就是 n=0时,return 1,因为fact(0)方法找到了出口所以立即返回,返回值是0,逆序执行fact(1),从刚才暂停的位置开始执行,也就是return n * tmp,执行到这里又返回了,返回值是1,继续逆序执行fact(2),还是从刚才的暂停的位置开始执行,即执行return n * tmp;从这里可以看出递归中递是正序的,归是逆序的.
- 求斐波那契数列
int fib(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n - 2) + fib(n - 1);
}
int main() {
for (int i = 0; i < 10; i++) {
printf("%d ", fib(i));
}
printf("\n");
return 0;
}
递归过程如下,不做讲解
- 计算最大公约数(辗转相除法)
int gcd(int a, int b){
if (b == 0) return a;
return gcd(b, a % b);
}
//调用递归
int result = gcd(12, 32);
递归的理解
以下是从代码角度对递归的理解,希望对于不会写递归的朋友有所帮助
1.写递归算法时,首先确定递归三要素
① 递归函数的参数和返回值 ② 终止条件 ③ 功能逻辑2.从代码角度理解递归
每次递归调用时,都会把本次(假设为第n次)递归入栈并暂存下一行代码的位置和参数值;当n+1次递归返回(return或者执行完所有行代码)时第n+1次递归就出栈,继续执行第n次递归,从刚才保存的位置开始执行,参数值用刚才暂存的值。
3.注意三点
① 递归函数返回有两种情况:return操作和执行完所有行代码
② 当第n+1次递归返回时,n+1次递归立即出栈,然后执行第n次递归函数;
③ 一旦执行到递归函数,立即把当前(n)递归入栈同时暂存下一行代码的位置和参数值,当n+1次递归返回时,回溯到第n次递归,从暂存的位置继续往后执行。