赞
踩
递归是一个函数自己调用自己的过程。那么为什么要自己调用自己呢?当遇到一个复杂,且可以分成多个与原问题相似的问题时,我们不想用大量的代码去实现,就可以使用递归,也就是自己调用自己,每次调用自己都会比原问题更加简单,也可以说成把大事化小的过程。
下面让我们看看什么是自己调用自己吧:
像图片中main函数中又调用了一个main函数就是递归的使用,当然,这段代码如果运行,会使程序陷入死循环,无限打印printf函数中要打印的内容,所以,这并不是递归的正确打开方式,递归的使用必须有使用递归无法使用得的限制条件,使程序不会陷入死循环,还必须让每次递归调用都
更接近这个限制条件,文字难以理解,接下来我们用代码实例来解释吧:
例如我们要用求一个数的阶乘,递归就可以很好的解决这个问题
- int Fact(int n)
- {
- if (n == 0)
- return 1;
- else
- return n * Fact(n - 1);
- }
- int main()
- {
- int n = 0;
- scanf("%d", &n);
- int r = Fact(n);
- printf("%d", r);
- return 0;
- }
我们试着输入5,让它求5的阶乘
输入5,输出120,没错,5的阶乘为120,怎么样,递归的代码是不是特别简洁呢?
那么它是如何实现的呢?下面我将对它的代码一一讲解:
我们进入main函数创建了一个数n,它就是我们输入的要求阶乘的数,而求n的阶乘的功能主要是由Fact函数实现的,Fact函数内部也很简单,只有寥寥几行代码,我们要解释这几行代码首先就要我们解释我们实现求阶乘的思路,假如我们要实现一个数的阶乘,我们把求阶乘看成:
5!=5×4!
4!=4×3!
3!=3×2×1
也就是我们要求n的阶乘,可以用n乘以n-1的阶乘,这样就可以使用递归大事化小的特性,把求n的阶乘变成n×n-1!,求n-1的阶乘变成n-1×n-2!.......
现在,我们再来看Fact内部的代码
假如我们传入一个5,这个5由n接收,每次进入函数都判断n是否等于0,等于0则返回1,不等于则执行后面的代码,返回n×n-1的阶乘,而这个n-1的阶乘又是由Fact函数实现的,但是这一次传入的是n-1,下次进入函数时,参数n接收的数也是n-1,也就是4,函数会被多次调用,直至n等于0时,函数返回1,就开始回归,我们还是看图吧:
这张图充分体现了递归的递推和回归的特性。
递归有着代码简洁高效的优点,是不是意味着它在任何地方都可以使用呢?并不是,在一些看似能
使用递归的场景实则使用递归会使程序的计算量变得非常巨大。例如:我们要求第n位的斐波那契数列的值,在设计程序之前,我们先简单的了解一下斐波那契数列
斐波那契数列就是第一位为1,第二位为1,往后的每一位都由前两个数字相加所得,例如第十位的55是由第8位的21与第9位的34相加所得。由此条件,我们很快就能用递归实现:
- #include<stdio.h>
- int Fact(int n)
- {
- if (n <= 2)
- return 1;
-
- return Fact(n - 1) + Fact(n - 2);
- }
- int main()
-
- {
- int n = 0;
- scanf("%d", &n);
- int r = Fact(n);
- printf("%d ", r);
- return 0;
-
- }
当我们输入10,求斐波那契数列的第10位数,果然得到了55,这样一看,还没有什么问题 ,但是当我们要求更大位数的值时:
它却没有得出结果,这是为什么呢,因为,函数在内部多次调用了自己,产生了大量的重复计算,导致计算量巨大,代码执行效率非常低,让计算机也无法快速得出结果,这个例子告诉我们,递归是有使用条件的 ,如果要设计一个需要重复计算的程序,不能无脑使用递归,而是首先要思考递归能不能用,是否能让代码简洁的同时,更加高效,那么此类例子我们如何解决呢?接下来我们要介绍另一种能多次重复相同计算的方法。
迭代是类似循环的方法,它包含了循环,本质是多次做相同的动作,使程序运行起来实现我们要实现的功能,上述例子使用迭代能高效地解决:
- #include<stdio.h>
- int Fact(int n)
- {
- int i = 0;
- int a = 1;
- int b = 1;
- int c = 0;
- int temp = 0;
- for (i = 1; i <= n - 2; i++)
- {
- c = a + b;
- temp = c;
- a = b;
- b = temp;
- }
- return c;
- }
- int main()
- {
- int n = 0;
- scanf("%d", &n);
- int r = Fact(n);
- printf("%d", r);
- return 0;
- }
这次我们试着求第50位的斐波那契数:
可以看到,很快就得到了结果,但是答案是错误的,因为要求的数太大,一个字节无法表示,但是我们可以很直观的看见两者的差别,在这这样一个例子中,使用迭代会优于使用递归。所以,使用递归还是迭代,需要分析二者的优点和缺点选择更适合的方法。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。