目录
目录
函数递归是什么?函数递归是一种解决问题的方法。函数递归是平常解决C语言问题令人眼前一亮的解决方法。
递归:一个函数在它的函数体内调用它的自身。执行递归函数将反复调用其自身,每调用一次就进入新的一层。递归函数必须有结束条件。
一.最简单的递归函数
首先,先写一个最简单的递归函数来体验一下:
#include <stdio.h>
int main()
{
printf("hehe\n");
main();//在这里main函数实现了自己调用自己。
return 0;
}
上述代码中,main函数实现了自己调用自己,代码会陷入死循环,导致栈溢出(Stack overflow)而结束 。
二.递归函数分析
2.1递归函数思想:
把一个大型复杂问题层层转化为一个与原问题相似,但规模较小的子问题来求解;直到子问题不能再被拆分,那么递归就结束了,所以递归的思考方式就是大事化小的过程。
递归中的递就是递推的意思,归就是回归的意思。
2.2递归函数限制条件
- 递归函数存在限制条件,当满足这个递归条件,递归函数便不再执行。
- 每次递归函数执行后就会接近这个递归函数的限制条件。
三.递归函数举例
例1:求n的阶乘(不考虑溢出)
分析:n的阶乘就是1~n的数字累计相乘。同时,我们知道阶乘公式 n!= n * n(n - 1)!
3.1递归解决阶乘问题
举例:
当 n==0的时候。我们知道阶乘为1,所以我们在这里分为两种情况:
所以,我们可以按照这个思路去写代码啦!
#include <stdio.h>
int Fact(int n)
{
if (0 == n)
{
return 1;
}
else
return n * Fact(n - 1);
}
int main()
{
int n = 0;
int ret = 0;
scanf("%d", &n);
ret = Fact(n);
printf("%d阶乘为%d\n", n, ret);
return 0;
}
测试结果如下图:
3.2递归解决顺序打印一个整数的每一位
我们这个例子的要求,输入一个整数,按照顺序将整数以此打印出来。
比如:
代码分析:这个题目的关键就是怎么得到它的每一位数?
代码实现:
#include <stdio.h>
void My_print(int a)
{
if (a > 9)
{
My_print(a / 10);
}
printf("%d ", a % 10);
}
int main()
{
int a = 0;
scanf("%d", &a);
My_print(a);
return 0;
}
我们拿图来表示一下:
四.递归与迭代
但是在递归函数调⽤的过程中涉及⼀些运⾏时的开销。
在这里们引进函数栈帧:在C语⾔中每⼀次函数调⽤,都要需要为本次函数调⽤在栈区申请⼀块内存空间来保存函数调⽤期间 的各种局部变量的值,这块空间被称为运⾏时堆栈,或者函数栈帧。 函数不返回,函数对应的栈帧空间就⼀直占⽤,所以如果函数调⽤中存在递归调⽤的话,每⼀次递归函数调⽤都会开辟属于⾃⼰的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。所以如果采⽤函数递归的⽅式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack overflow)的问题。在后面我们会分享到函数栈帧。所以如果不想使用递归就得想其他的办法,通常就是迭代的方式(通常就是循环的方式)。
#include <stdio.h>
int Fact(int n)
{
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++)
{
ret *= i;
}
return ret;
}
int main()
{
int n = 0;
int ret = 0;
scanf("%d", &n);
ret = Fact(n);
printf("%d阶乘为%d\n", n, ret);
return 0;
}
4.1求n个斐波那契数
我们很清楚的知道公式,那再写这个程序时,我们很轻松的就写出递归的方式来解决这一道题。。
#include <stdio.h>
int Fib(int n)
{
if (n <= 2)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d", n);
}
但是,当我们输入一个较大的数字时,他的运行速度是我们难以接受的,这就说明递归比较低效。那是为什么呢?我们写一个代码来测试一下:
#include <stdio.h>
int count = 0;//计数器
int Fib(int n)
{
if (n == 3)
count++;//统计第3个斐波那契数被计算的次数
if (n <= 2)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
printf("\ncount = %d\n", count);
return 0;
}
我们运行结果如下图:
当我们求第40个斐波那契数的时候,我们的第三个斐波那契数使用了39088169次。这是一个多么庞大的数字,这也证明了递归在解决斐波那契问题的效率低下。
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);
}