递归是什么?
递归是学习C语言函数绕不开的一个话题,那么什么是递归呢
递归就是解决问题的一种方法
写一个最简单的C语言递归代码
#include<stdio.h>
int main() {
printf("hahahaha\n");
//调用main()函数
main();
return 0;
}
上述代码就是一个简单的递归代码,只不过上述代码只不过是未来演示递归的基本形式,不是为了解决问题,代码最终也会陷入死循环,导致栈溢出(Stack overflow)。
递归的思想:
把一个大型复杂的问题层层转化为一个原问题相似,但规模较小的子问题来求解;直到子问题不能在被拆分了,递归就结束了,所以递归的思考方式就是想大事化小的过程。
递归中递就是递推的意思,归就是回归的意思。
递归的限制条件
递归在书写的时候,有2个必要条件:
- 递归存在条件,但满足这个限制条件的时候,递归便不再继续。
- 每次递归调用之前越来越接近这个限制条件。
在下面的例子来进一步了解递归
递归举例
举例一:求n的阶乘
计算n的阶乘(暂时不考虑溢出),n的阶乘就是1~n的数字积累相乘。
分析和代码实现
我们知道n的阶乘的公式:n! = n * (n - 1)!
这样的思路就是将一个较大的问题转换为一个与原问题相似,但是用规模较小的问题来解决的。
n!--->n*(n - 1)!
(n - 1)! --->(n - 1)* (n - 2)!
.............以此类推
直到n是1或者0时,不在拆解
再往下分析就是,当 n <= 0时n的阶乘就是为1,n > 0 时就是按照公式来向下推
n的阶乘的递归公式如下:
代码如下:
Fact(int n); //函数声明
int main() {
int n = 0;
printf("请输入n的值:\n");
scanf("%d",&n);
int r = Fact(n);
printf("%d\n",r);
return 0;
}
//调用Fact函数
Fact(int n) {
if (n <= 0) {
return 1;
}
else {
return n * Fact(n - 1);
}
}
我们来测试一下
这里不考虑n太大溢出的情况
画图推演
举例二:顺序打印一个整数的每一位
输入一个整数m,打印这个按照顺序打印整数的每一位。
比如:
输入:1234 输出:1 2 3 4
输入:520 输出:5 2 0
分析和代码实现
看到这个题目我们会想该怎么去得到每个数的第一位呢
n如果是一位数,那么就输出他本身
n如果大于一位数的,就得拆分每一位
1234 % 10我们就能得到4,再1234 / 10 = 123,得到123 相当于就去除了4
然后在对123 % 10 = 3,得到3,再123 / 10 = 12,去除掉3,以此类推。
不断的 %10、/10操作,直到1234得到每一位,但是这里的数字得到的都是倒着的,
Print(n)
如果n是1234,那表⽰为
Print(1234) //打印1234的每⼀位
其中1234中的4可以通过%10得到,那么
Print(1234)就可以拆分为两步:
1. Print(1234/10) //打印123的每⼀位
2. printf(1234%10) //打印4
完成上述2步,那就完成了1234每⼀位的打印
那么Print(123)⼜可以拆分为Print(123/10) + printf(123%10)
以此类推
printf(1234)
printf(123) + printf(4)
printf(12) + printf(3)
printf(1) + printf(2)
printf(1)
直到只剩一位数组时,不再进行拆分,递归结束。
代码如下:
void Print(int m);
void digit(int m);
int main() {
int m = 0;
printf("请输入一个数字:\n");
scanf("%d", &m);
Print(m);
return 0;
}
void Print(int m) {
if (m < 9) {
printf("%d\n", m);
}
else {
digit(m);
}
}
void digit(int m) {
if (m > 9) {
Print(m / 10);
}
printf("%d\n", m % 10);
}
我们来测试一下
结果和上面叙述一样(代码仅供参考,还需要自己去写遍)
画图推演
以1234的每一位来演算、推演