一,递归是什么?
递归其实是一种解决问题的方法,在C语言中,递归就是函数自己调用自己。
例:
始终重复打印的原因是无限调用原本的函数。
调试结果:
其中有显示“Stack overflow”意义为~~栈溢出。
1.1递归的思想
把一个大型复杂问题层层转化为一个与原问题相似,但规模较小的子问题来求解;直到子问题不能再被拆分,递归就结束了。(大事化小)
1.2递归限制条件
两个必要条件(其中两者必须有但不一定对):
1>递归存在限制条件,当满足这个限制条件的时候,递归便不再继续。(有些情况继续,有些情况要停止)
2>每次递归调用之后越来越接近这个限制条件。(渐渐的停下来)
二,递归举例
2.1 例1:求n的阶乘
一个正整数的阶乘是所有小于及等于该数的正整数的积。
理解:5! == 5*4*3*2*1 == 5*fact(4)
4! == 4*3*2*1 == 4*fact(3)
3! == 3*2*1 == 3*fact(2)......
2.1.2思维导图
eg:以3!为例
先递推:
fact(3)==3*fact(2)--->fact(2)==2*fact(1)--->fact(1)==1*fact(0)--->
再回归:
fact(0)==1--->fact(1)==1--->fact(2)==2--->fact(3)==6
2.2 例2:顺序打印一个整数的每一位
输入一个整数m,按照顺序打印整数的每一位。
每一次函数调用,都会向内存栈区上申请一块空间
这块空间主要是用来存放函数的中局部变量,和函数调用过程中的上下文的信息
这个空间一般叫:函数的运行时堆栈,也叫函数栈帧空间。
三,递归与迭代
#include<stdio.h>
int fact(int n)
{
if (n == 0)
return 1;
else
return n * fact(n - 1);//函数递归
}
int main()
{
int n = 0;
scanf_s("%d", &n);//输入
int ret = fact(n);//函数调用
printf("%d", ret);
return 0;
}
fact函数是可以产生正确的结果,但是在递归函数调用的过程中涉及一些运行时的开销。
在C语言中每一次函数调用,都要需要为本次函数调用在栈区申请一块内存空间来保存函数调用期间的各种局部变量的值,这快空间被称为运行时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就一直占用,所以如果函数调用中存在递归调用的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack overflow)的问题。
迭代
用“迭代”的方式实现的
int f (int n)
{
循环产生1~n的数字
int i = 0;
int a = 1;
for (i = 1; i <= n; i++)
{
a *= i;
}
return a;
}
int main()
{
int n = 0;
int ret = 0;
scanf_s("%d", &n);
ret = f(n);
printf("%d ", ret);
return 0;
}
3.1例:斐波那契数列
“递归”斐波那契数列
#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_s("%d", &n);
printf("%d",Fib(n));
return 0;
}
“迭代”
#include<stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
while (n >= 3)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf_s("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
两者同时可以完成斐波那契数列的计算但对于“迭代”来说“递归”所计算的量过大,如计算第50个数的时候,“递归”的计算时间远超于“迭代”且CPU所占比例增高。
3.2递归与循环的选择
3.2.1如果使用递归写代码,非常容易,写出的代码没问题,那就直接使用递归。
3.2.2如果使用递归写出的问题,是存在明显缺陷,那就不能使用递归,就得使用迭代的方式处理。
3.3 例:青蛙跳台问题
有一只青蛙一次可以跳一个台阶,也可以一次跳两个台阶问,跳到第n个台阶有多少种跳法
解析:
当只跳跃一个台阶时,只有一种跳法
当一次跳两个台阶时,有1+1或2,两种跳法
当一次跳三个台阶时,有1+1+1或1+2或2+1,三种跳法
当一次跳四个台阶时,有1+1+1+1或2+1+1或1+1+2或2+2或1+2+1,五种跳法