一.递归相关内容
递归是指在函数中调用函数自身的方法。这一方法通常就是将一个复杂的问题逐渐拆解成一个个小问题,然后再对其进行总和,从难到易,再通过回溯,由此得出答案。
递归模板(这里以求斐波那契数列为例)
int fi(int x) // 参数
{
if(x==1) return 1; // 判断条件 何时返回函数调用
if(x==2) return 1;
return fi(x-1)+fi(x-2); // 返回值 (函数需要执行的功能)
}
通过上述模板,可以了解到递归函数分为三个部分
1.调用函数时的参数:递归函数需要通过相关参数不断调用函数自身求得答案。
2. 判断条件(结束条件):递归函数不断调用自身(如果一直调用,则陷入死循环中)因此需要找出终止条件,退出对函数的自身调用,达到递归的目的。
3.函数执行的功能(找出等价关系式):每个问题不一样,对应的递归函数也不一样,需要找出其关系式,通过递归的形式写出。
二.递归相关的典型例题
1.求 n 的阶乘的问题
阶乘式: F(n)=n! 递归的关系式(拆成小问题的形式):F(n)=n*F(n-1)
注:这里 F(n) 仅与 F(n-1) 构成关系,若写成 F(n)=n*(n-1)*F(n-2) 则包括了前面的关系式。
结束条件: F(1)=1 当 n 为 1 时 返回 1
以图画的形式展开递归的内容
核心代码
int fi(int x)
{
if(x==1) return 1;
return n*fi(x-1);
}
2.求斐波那契数列
例如 1 1 2 3 5 8 13 21 34 55 89 144 的这一类数,规定前两个数是 1 ,从第三个数开始每个数是前两个数的和。
关系式: F(n)=F(n-1)+F(n-2) 这里则是将F(n) 分成了两个子问题,分别对F(n-1) 和 F(n-2) 求解
结束条件:规定 F(1)=1,F(2)=1
图示
核心代码
int fi(int x)
{
if(x==1) return 1;
if(x==2) return 2;
return fi(x-1)+fi(x-2);
}
一个关于递归的思考:在上图中,可以看到F(1) F(2) 反复被递归调用,如果当n取得非常大,F(1) F(2)被重复调用的次数将会更多,从而使效率大大降低,有没有什么方法可以避免重复调用?(将在后文解答)
3.跳台阶问题
小明一次可以跳1~3个台阶,问他跳 n 个台阶时,有几种方法?
当调至n个台阶的前一个阶段有三种情况:在 n-1 个台阶处 跳 1 格
在 n-2 个台阶处 跳 2 格
在 n-3 的台阶处 跳 3 格
得出关系式 F(n)=F(n-1)+F(n-2)+F(n-3)
结束条件: F(1)=1 F(2)=2 F(3)=4
大致过程与题2相同,不再论述
三.关于递归的思考
递归是通过不断调用自身函数求得结果的过程,在这其中总是会出现重复调用的情况,从而使代码超时,怎样才可以避免这种情况,达到高效的目的呢?
方法:只需要将计算过的值记录下来,当再次遇到相同的情况时,可以直接输出相应的数,从而减去了不必要的重复递归操作。
这里以T2为例:
int fi(int x)
{
if(x==1) return 1;
if(x==2) return 1;
if(f[x]) return f[x]; // 如果 f[x]被记录过,则可直接输出,从而将递归操作变为线性的结构
f[x]=fi(x-1)+fi(x-2);
return f[x];
}
四.总结
1.递归的难度不在于代码的复杂程度,递归总是通过简单的代码解决复杂的问题,针对于解决递归的问题,核心为寻找递归的关系式以及结束条件,就可以解决问题。
2.对于递归的内涵,可以通过调试的方法(单步进入),探寻递归的本质2.