1、什么是“递归”
程序调用自身的编程技巧称为递归(recursion),通俗的来讲,就是自己调用自己。
递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量提高开发效率。
递归的主要思考方式在于:把大事化小!一个个拆分解决!
2、递归的两个必要条件
- 设定一个让递归停止的条件,避免无条件的自己调自己,这样可以避免死递归,从而导致栈空间溢出。
- 每次递归调用之后要越来越接近这个让递归停止的条件。
3、递归的实现
这里以一道题来讲解什么是递归,以及如何实现。
题目:接受一个整型值(无符号),按照顺序打印它的每一位。
例如:
输入:123,输出1 2 3。
#include <stdio.h>
void print(int n)
{
//设定一个让递归停止的条件,避免无条件的自己调自己,导致栈空间溢出
if(n > 9)
{
//调用自己
print(n / 10);
}
printf("%d " ,n%10); //当不在满足继续递归下去的条件时,则开始往回执行printf!!!
}
int main()
{
unsigned int num = 0;
scanf("%d",&num); //输入123
print(num);
return 0;
}
3.1、递归的调用过程
画图讲解:
总结:
递归,可以用少量的代码解决复杂的问题。但是要避免出现“死递归”的情况,其实并不是满足两个必要条件就不会出现栈溢出的情况,就不会有问题。
在实际开发中,递归虽然好用,但是同时如果写出来的效果影响效率,那就可以考虑用循环来解决。
- 那什么时候用递归,什么时候用循环?
在实际开发中,递归虽然好用,但是同时如果写出来的效果影响效率,那就可以考虑用循环来解决。 - 关于递归与迭代
“迭代”它展现出来的不一定是循环!!!
但它的思路还是在重复的在做一件事情。比如go to语句也可以实现循环,它叫迭代,不能叫做循环。
练习:
1、求第n个的阶乘
//方法一:用for
int Fun(int n)
{
int ret = 1;
//相当于1*1*2*3*4*5*6*7*8
for (int i = 1; i <= n; i++)
{
ret = ret*i;
}
return ret;
}
//方法二:用while
// int Fun(int n)
// {
// int ret = 1;
// while (n > 1)
// {
// ret = ret * n;
// n = n - 1;
// }
// return ret;
// }
//方法二:用递归实现
// int Fun1(int n)
// {
// int ret = 1;
// //如果n <= 1那么n的阶乘就是1,如果n >= 1,n的阶乘等于(n-1)*n
// if (n <= 1)
// return 1;
// else
// return n*Fun1(n - 1);
// }
int main()
{
int x = 0;
scanf("%d",&x);
printf("%d\n", Fun(x)); //方法一
// printf("%d\n", Fun1(x)); //方法二:用递归实现
return 0;
}
2、求第n个斐波那契数(不考虑溢出)
斐波那契数: 1 1 2 3 5 8 13 21 34 55
实际上可以理解为前面两个数是1,后面一个数总是前面两个数相加的和。
//用递归的方法实现(用递归去解,其实不合适!!!)
// int Fib(int n)
// {
// if (n <= 2)
// return 1;
// else
// return Fib(n-1) + Fib(n-2);
// }
//用循环的方式解决
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
while (n > 2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d",&n);
printf("%d\n", Fib(n));
return 0;
}