什么是递归
递归就是直接或者间接地调用自身,把一个大型复杂的程序简化为规模较小的程序,将大量的程序用简单的程序来代替。
递归的主旨是将大事化小。
函数递归
在调用一个函数的过程中又出现直接或间接地调用该函数本身
C语言的特点之一就是允许函数的递归。
函数的限制条件
递归的实现需要2个必要条件:
- 递归存在限制条件,当满足这个限制条件,递归就不再继续。
- 每次递归之后要越来越接近这个限制条件。
举例讲解函数递归的实现
题目
有5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第4个学生岁数,他说比第3个学生大2岁。问第3个学生,又说比第2个学生大2岁。问第2个学生,说比第1个学生大2岁。最后问第1个学生,他说是10岁。请问第5个学生多大。
题目分析
一共有5个学生,序号分别为1,2,3,4,5,第一个学生10岁,往后的每个学生都比前一个学生大两岁。
思路分析
非递归:
想要算出第五个学生的岁数,就是
第二个学生:10+2=12
第三个学生:12+2=14
第四个学生:12+2=16
第五个学生:16+2=18
递归:
我们要创建的函数:int age(int n), n就是我们要求的第五个学生的序号,到时候n=5即可。
age(5)=age(4)+2
age(4)=age(3)+2
age(3)=age(2)+2
age(2)=age(1)+2
效果等同于:age(n) = age(n-1)+2,输入:n=5
实现代码:
第一次以 n=5 进去,c=age(5-1)+2 -> c=age(4)+2,再次调用age函数,参数是4,
age(4)的返回值为c,c=age(4-1)+2-> c=age(3)+2,再次调用age函数,参数是3,
直到运行到age(1),age(1)=10,递推结束。
int age(int n)//5作为参数进来,n=5 { int c = 0; if(n==1) c = 10; else c=age(n-1)+2;//c=age(4)+2 这里age(4)参数为4,再次进入到 age 函数。 //函数age(4)又会走到这里,n=4,这里c=age(3)+2. //c是函数的返回值, return (c); }
限制条件:
n=1
age(n) = age(n-1)+2
我们的函数递归如果没有限制条件,就会陷入死循环。
所以当n=1的时候,age(1)=10,就不会再执行递归c=age(n-1)+2
题目
用递归的方法求n!
题目分析
一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。
思路分析
5!=5x4x3x2x1
4!=4x3x2x1
3!=3x2x1
……
我们发现5!=5x4!
4!=4x3!
因此得出n!=nx(n-1)!
实现代码:
#include <stdio.h> int fact(int n) { if(n==1) return 1; else return n*fact(n-1); } int main() { int n = 0; scanf("%d",&n); int c = fact(n); printf("%d",c); return 0; }
函数递归所引发的栈溢出问题
每一次函数的调用,都会向内存栈区申请空间,直到函数返回值,开始释放空间。
这块空间主要是用来存放函数中的局部变量,和函数调用过程中上下文的信息
我们把这块空间叫做函数栈帧空间。
我们留给函数栈帧的空间是有限的,所以函数递归有要求:
1.限制条件
2.越来越接近我们的限制条件
不然,无限地开辟函数栈帧空间,导致的栈溢出问题
刚才我们的n的阶乘的题目,我将限制条件改为n=6,随之函数的运行,会离限制条件越来越远,在msvc编译器底下,好像并没有报错,最后以无结果的形式结束运行,应该是有优化。
总结
1.递归是什么?
2.递归的限制条件的要求
3.对题目运用递归的方式进行求解
4.栈溢出问题(为什么要有限制条件)