1.何为递归?
在函数的嵌套调用中,如果函数嵌套调用的是自己,那么我们称之为函数的递归调用。
简单来说就是自己调用自己
#include<stdio.h>
int main()
{
printf("Hello my friend!\n");
main(); //函数调用本身,一直打印 Hello my friend!
return 0;
}
以上就是最简单粗暴的一个递归例子,虽然程序回打印 Hello my friend!,但是这是一个死递归的状态,最终导致栈溢出。
出现了死递归的情况,自然要加限制条件解决这个问题。
2.递归的限制条件
如果让你计算 1~5 的和,首先想到的肯定是循环,而这里我们就试试递归的方法来试试。
#include<stdio.h>
int add(int x)
{
int y = 0;
if (x == 1)
{
return 1;
}
y = x + add(x - 1); //递归
return y;
}
int main()
{
int a = 5;
int num = add(a); //调用 add 函数
printf("%d",num); //最后结果为15
return 0;
}
图解:
递归分为两个过程,一个是递推,一个是回归。
上图为例,想要知道 add(5) 的值,我们又已经知道了 add 的值有 x+add(x-1) 公式,所以 add(5)=5+add(4); 要求 add(5) 的值又要求 add(4) 的值,以此类推······最终我们要求到 add(1) 的值才能求出 add(5) 的值。
如果这样还不能理解,就再换一个更容易理解的例子:
有 A、B、C、D 四个人,
D说:我的年龄比 C 小 2 岁。
C说:我的年龄比 B 小 1 岁。
B说:我的年龄比 A 小 3 岁。
A说:我的年龄是 30 岁。
问 :D的年龄是多少?
解析:首先想要知道 D 的年龄,就要知道 C 的年龄,而想要知道 C 的年龄,就要知道 B 的年龄,B 的年龄又比 A 的年龄小3岁,所以我们只要知道 A 的年龄就能够求出每个人的年龄了。
答案:D 的年龄是24岁。
分析: D 向前面 询问 每个人的年龄是一个 递推 的过程,最后向后 返回 每个人的年龄是一个回归的过程。
3.示例
求 n 的阶乘
#include<stdio.h>
int fact(int x)
{
int y;
if (x == 1)
return 1;
y = x * fact(x - 1); //递归
return y;
}
int main()
{
int n = 0;
printf("请输入n的值:");
scanf("%d",&n); //输入6
int m = fact(n); //调用 fact 函数
printf("结果为:%d",m);
return 0;
}
运行结果:
请输入n的值:6
结果为: 720
4.迭代
迭代是重复反馈过程的活动,每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
这里我们引入一个函数栈帧的概念,每个栈帧对应着一个未运行完的函数,栈帧中保存了该函数的返回地址和局部变量。
递归的时候,每调用一次就会开辟一个属于自己的栈帧空间,直到停止递归。如果递归地太深,就会浪费栈帧空间,最后可能导致栈溢出的情况。
还是计算 n 的阶乘,如果不用递归,用迭代的方法会好些。
#include<stdio.h>
int main()
{
int n = 0;
int m = 1;
printf("请输入n的值:");
scanf("%d",&n); //输入6
for(int i=1;i<=n;i++)
{
m = m * n; //每一次迭代的结果会作为下一次迭代的初始值
}
printf("结果为:%d",m);
return 0;
}
最后:有时候递归的层次会很深,或者又多余的计算,切记不可盲目使用递归。