程序调⽤⾃身的编程技巧称为递归(recursion)。
递归做为⼀种算法在程序设计语⾔中⼴泛应⽤。⼀个过程或函数在其定义或说明中有直接或间接调⽤⾃身的⼀种⽅法。
它通常把⼀个⼤型复杂的问题层层转化为⼀个与原问题相似的规模较⼩的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,⼤⼤地减少了程序的代码量。
递归的主要思考⽅式在于:把⼤事化⼩。
递归的两个条件:
(a)存在限制条件,当满⾜这个限制条件的时候,递归便不再继续。
(b)每次递归调⽤之后越来越接近这个限制条件。
就递归来举几个例子
例1:接受一个整型数值,把他转换为单个字符并进行打印。例如,输入 1234, 输出 1 2 3 4。
#include <stdio.h>
#include <stdlib.h>
// 接受一个整型数值,把他转换为单个字符并进行打印
// 例如,输入 1234, 输出 1 2 3 4
void print(int num) {
if (num > 9) {
print(num / 10);
}
printf("%d ", num % 10);
}
int main() {
int n = 1234;
print(n);
system("pause");
return 0;
}
运行结果:
例2:编写函数不允许创建临时变量,求字符串的⻓度。
#include <stdio.h>
#include <stdlib.h>
// 编写函数不允许创建临时变量,求字符串的⻓度
size_t my_strlen(const char* str) {
// 非法输入
if (*str == '\0') {
return 0;
}
return 1 + my_strlen(str + 1);
}
int main() {
char* str = "hello world";
printf("len is %d\n", my_strlen(str));
system("pause");
return 0;
}
运行结果:
例3:求n的阶乘。(不考虑溢出)
#include <stdio.h>
#include <stdlib.h>
// 求n的阶乘。(不考虑溢出)
int factorial(int num) {
if (num == 1) {
return 1;
}
return num*factorial(num - 1);
}
int main() {
int num = 10;
printf("%d! = %d\n", num, factorial(num));
system("pause");
return 0;
}
运行结果:
例4:求第n个斐波那契数
#include <stdio.h>
#include <stdlib.h>
// 求第n个斐波那契数
int fib(int num) {
if (num <= 2) {
return 1;
}
return fib(num-1)+fib(num-2);
}
int main() {
int num = 10;
printf("第 %d 个斐波那契数为 %d\n", num, fib(num));
system("pause");
return 0;
}
运行结果:
看到这里,是不是感觉递归无所不能,但是,别高兴得太早,使用递归也是有缺点的。
- 在使⽤ fib 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。
- 使⽤ factorial 函数求10000的阶乘(不考虑结果的正确性),程序会崩溃。
因为递归调⽤的过程中很多计算其实在⼀直重复,所以有的时候效率极其低下,所以会导致运行变慢和程序崩溃(其实是栈溢出)等结果。
改进
为了解决上述的问题,应该进行如下改进。
- 例3 的情况,应该将递归改写为非递归,提高效率。
- 例4 栈溢出的情况,可以使用 static静态变量 代替 局部变量。这不仅可以减少每次递归调⽤和返回时产⽣和释放局部变量的开销,⽽且static变量还可以保存递归调⽤的中间状态,并且可为各个调⽤层所访问。
#include <stdio.h>
#include <stdlib.h>
// 求n的阶乘。(不考虑溢出)
int factorial(int num) {
int result = 1;
while (num > 1) {
result *= num--;
}
return result;
}
// 求第n个斐波那契数
int fib(int num) {
int pre = 1;
int cur = 1;
int result = 1;
while (num-- >= 2) {
result = pre + cur;
pre = cur;
cur = result;
}
return result;
}
int main() {
int num1 = 10;
int num2 = 1000;
printf("%d! = %d\n", num1, factorial(num1));
printf("第 %d 个斐波那契数为 %d\n", num2, fib(num2));
system("pause");
return 0;
}
运行结果: