函数的递归
1.定义:函数调用己称为函数的递归。
2.作用:把一个复杂问题层层转化为一个原问题相似,但规模较小的子问题来求解,直到子问题不能再拆分,把大事化小的过程。( 递:递推,归:回归。)
3.递归的必要条件:
一、函数的递归必须要有限制条件,递归满足限制条件时,递归不会再继续。
二、每当递归调用之后,越来越接近限制条件。
4.递归的运用
一、求n的阶乘
n!=n*(n-1)!由这个公式想到函数的递归,因此我们可以写如下代码
int Fact(int n) {
if (n <= 0) {
return 1;
}
else
return n * Fact(n - 1);
}
int main() {
int n = 0;
scanf("%d", &n);
int ret = Fact(n);
printf("%d\n", ret);
}
这里我们输入n=5,得出来5的阶乘是120从而验证代码的正确。
二、输入一个数,要求将他每位整数按顺序打印
这里我们想的是如输入12345,则我们需要依次打印1 2 3 4 5,因此这里我们同样想到函数的递归,Print(12345)=>Print(1234)+5
Print(1234)=>Print(123)+4....
这里我们就要想到如何分别打印整数的末尾数字,这里我们就要运用%,/两个运算符
12345%10=5; 12345/10=1234;
我们先利递推打印出首位数字,在利用回归,依次打印后面的数字
代码如下
int sum = 0;
void Print(int n) {
if (n / 10 != 0)
Print(n / 10);
printf("%d ",n%10);
}
int main() {
int n = 0;
scanf("%d", &n);
Print(n);
}
同样我们这里输入整数12345,顺序打印出来我们整数每一位数字,验证代码正确。
5.递归的缺点:因为函数每一次调用,都会在栈区申请一块内存空间来保存函数调用期间各种局部变量的值,所以在函数递归中,函数调用后不返回,函数对应的栈帧空间一直被占用,这样随着函数的递归层次加深,会浪费大量的栈帧空间,导致栈溢出。
所以为了预防这种情况的发生,我们可以使用迭代的方式来处理代码。
比如计算n的阶乘
我们可以直接利用循环来处理
int main() {
int n = 0;
int ret = 1;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
ret = ret * i;
}
printf("%d", ret);
}
同样这样也可以计算出n的阶乘。
这里递归缺点体现最极端的就是斐波那契数
看到这个数学公式,我们是不是可以很快联想到之前的n的阶乘,同理我们可以用函数的递归来书写代码来判断第几位斐波那契数是多少?
具体代码如下
int Fid(int n) {
if (n <= 2) {
return 1;
}
else
return Fid(n - 1) + Fid(n - 2);
}
int main() {
int n = 0;
scanf("%d", &n);
int ret=Fid(n);
printf("%d", ret);
}
这里我们输入5是可以迅速计算出结果的,但是当我们输入50的时候我们会发现会等很长时间才会给我们结果,这里的原因是计算第五十位数字我们需要进行非常多次的函数的调用,即使是计算机,也需要漫长的时间。
所以遇到这种问题,我们不妨想想是不是可以用迭代的时代来解决这个问题,这里我们可以使用循环
int Fib(int n) {
int a = 1;
int b = 1;
int c = 1;
while (n - 2) {
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main() {
int n = 0;
scanf("%d",& n);
int ret = Fib(n);
printf("%d", ret);
}
这里我们同样输入5,50,我们会发现得到结果速度远快于之前的函数的递归,因为我们发现我们算第五十位斐波那契数,我们只需要进行48次循环,我们就可以得到第五十位的数字。
我们这里就需要对什么时候使用递归要有很好的了解。
6、总结:今天对函数的递归的介绍简单的介绍到这里,对于函数的递归我们需要通过书写代码来加深理解,我们日积月累,了解递归的使用场景,优缺点,与迭代的优先级深刻掌握函数的递归。
如果大家感觉博主写的还不错的,希望大家可以三连支持一下博主,谢谢大家