函数递归
1.递归的概念
递归其实是一种解决问题的方法,在C语言中,递归就是自己调用自己。如:
这是一个简单的递归程序,只不过上面的递归只是为了演示递归的基本形式,不是为了解决问题,代码最终也会陷入死循环,导致栈溢出。即我们经常出现的未经处理的异常
2.递归的思想
把一个大型复杂问题层层转化为一个与原问题想似,但规模较小的子问题求解;直到子问题不能再被拆分,递归就结束了。递就是递推,归就是回归。
3.递归的限制条件
- 递归存在限制条件,当满足这个条件的时候,递归便不再继续。
- 每次递归调用后越来越接近这个限制条件。
4.递归实践:求n的阶乘
一个正整数的阶乘是所有小于及等于该数的正整数的积,0的阶乘为1。
思路:我们知道n的阶乘的公式:n!=n*(n-1)!
那么我们写fact函数求n的阶乘
int fact(int n)
{
if(n == 0)
return 1;
else
return n*fact(n-1);
}
完整函数如下:
#include <stdio.h>
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);
return 0;
}
ps:.这里n太大,也会存在溢出
5.递归举例:顺序打印一个整数的每一位
如:1234先用1234%10得到4输出4,然后1234/10得到123,123继续%10得到3,依次类推,但是这样我们得到的数据顺序是反的。
我们可以把一个数字/10作为递归的函数,当这个数不小于9就除以10,一直求到第一位数字被打印,
6.递归函数调用的本质
在C语言中每一次函数调用,都要需要为本次函数调用在栈区申请一块内存空间来保证函数调用的期间各种局部变量的值,这块空间被称为运行时栈堆,或者函数栈帧。
函数不返回,函数对应的栈帧空间就一直占用,所以如果函数调用中存在递归调用的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采用这种函数递归的方式完成代码,递归的层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出的问题。
所以如果不想使用递归就得想其他办法,通常就是迭代的方法。
7.迭代举例:计算n的阶乘
可以产生1~n的数字累计乘在一起
int fact(int n)
{
int i = 0;
int ret = 1;
for(i = 1;i<=n;i++)
{
ret*=i;
}
return ret;
}
上述代码能完成任务,效果比递归方式更好。
递归的程序会不断展开,在展开的过程中,我们发现会有重复的计算,层次越深,冗余计算越多。