1. 递归是什么?
递归是学习C语⾔函数绕不开的⼀个话题,那什么是递归呢? 递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。 写⼀个史上最简单的C语⾔递归代码 #include <stdio.h> int main() { printf("hehe\n"); main(); //main函数中⼜调⽤了main函数 return 0; } 上述就是⼀个简单的递归程序,只不过上⾯的递归只是为了演⽰递归的基本形式,不是为了解决问题,代码最终也会陷⼊死递归,导致栈溢出(Stack overflow)。1.1 递归的思想:
把⼀个⼤型复杂问题层层转化为⼀个与原问题相似,但规模较⼩的⼦问题来求解;直到⼦问题不能再 被拆分,递归就结束了。所以递归的思考⽅式就是把⼤事化⼩的过程。 递归中的递就是递推的意思,归就是回归的意思,接下来慢慢来体会。1.2 递归的限制条件
递归在书写的时候,有2个必要条件: • 递归存在限制条件,当满⾜这个限制条件的时候,递归便不再继续。 • 每次递归调⽤之后越来越接近这个限制条件。 在下⾯的例⼦中,我们逐步体会这2个限制条件2. 递归举例
递归代码及一定要包含递推部分跟回归部分。少了回归会导致栈溢出,而缺了递推部分则无法解决实际问题。
2.1 举例1:求n的阶乘
⼀个正整数的阶乘(factorial)是所有⼩于及等于该数的正整数的积,并且0的阶乘为1。 ⾃然数n的阶乘写作n!。 题⽬:计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘。2.1.1 分析和代码实现
我们知道n的阶乘的公式: n! = n ∗ ( n − 1)! 举例: 5! = 5*4*3*2*1 4! = 4*3*2*1 所以:5! = 5*4! 这样的思路就是把⼀个较⼤的问题,转换为⼀个与原问题相似,但规模较⼩的问题来求解的 当 n==0 的时候,n的阶乘是1, 其余n的阶乘都是可以通过公式计算。 n的阶乘的递归公式如下 那我们就可以写出函数Fact求n的阶乘,假设Fact(n)就是求n的阶乘,那么Fact(n-1)就是求n-1的阶乘,函数如下: 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; } 运⾏结果(这⾥不考虑n太⼤的情况,n太⼤存在溢出):2.1.2 画图推演
每一次,递推都n--,越来越接近递推结束条件n=1。当n=1的时候开始回归从而算出结果。2.2 举例2:顺序打印⼀个整数的每⼀位
输⼊⼀个整数m,打印这个按照顺序打印整数的每⼀位。 ⽐如: 输⼊:1234 输出:1 2 3 4 输⼊:520 输出:5 2 02.2.1 分析和代码实现
这个题⽬,放在我们⾯前,⾸先想到的是,怎么得到这个数的每⼀位呢? 如果n是⼀位数,n的每⼀位就是n⾃⼰ n是超过1位数的话,就得拆分每⼀位 1234%10就能得到4,然后1234/10得到123,这就相当于去掉了4 然后继续对123%10,就得到了3,再除10去掉3,以此类推 不断的 %10 和 /10 操作,直到1234的每⼀位都得到; 但是这⾥有个问题就是得到的数字顺序是倒着的 但是我们有了灵感,我们发现其实⼀个数字的最低位是最容易得到的,通过%10就能得到 那我们假设想写⼀个函数Print来打印n的每⼀位,如下表⽰: 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) 以此类推下去,就有 Print(1234) ==>Print(123) + printf(4) ==>Print(12) + printf(3) ==>Print(1) + printf(2) ==>printf(1) 直到被打印的数字变成⼀位数的时候,就不需要再拆分,递归结束。 那么代码完成也就⽐较清楚: void Print(int n) { if(n>9) //回归 { Print(n/10); //递推 } printf("%d ", n%10); } int main() { int m = 0; scanf("%d", &m); Print(m); return 0; } 在这个解题的过程中,我们就是使⽤了⼤事化⼩的思路 把Print(1234) 打印1234每⼀位,拆解为⾸先Print(123)打印123的每⼀位,再打印得到的4 把Print(123) 打印123每⼀位,拆解为⾸先Print(12)打印12的每⼀位,再打印得到的3直到Print打印的是⼀位数,直接打印就⾏。2.2.2 画图推演
以1234每⼀位的打印来