当前位置:   article > 正文

c语言:递归与迭代

c语言:递归与迭代

递归

      递归是一个函数自己调用自己的过程。那么为什么要自己调用自己呢?当遇到一个复杂,且可以分成多个与原问题相似的问题时,我们不想用大量的代码去实现,就可以使用递归,也就是自己调用自己,每次调用自己都会比原问题更加简单,也可以说成把大事化小的过程。

    递归的本意是实现两个动作,递是递归的意思,归是回归的意思。

下面让我们看看什么是自己调用自己吧:

像图片中main函数中又调用了一个main函数就是递归的使用,当然,这段代码如果运行,会使程序陷入死循环,无限打印printf函数中要打印的内容,所以,这并不是递归的正确打开方式,递归的使用必须有使用递归无法使用得的限制条件,使程序不会陷入死循环,还必须让每次递归调用都

更接近这个限制条件,文字难以理解,接下来我们用代码实例来解释吧:

例如我们要用求一个数的阶乘,递归就可以很好的解决这个问题

  1. int Fact(int n)
  2. {
  3. if (n == 0)
  4. return 1;
  5. else
  6. return n * Fact(n - 1);
  7. }
  8. int main()
  9. {
  10. int n = 0;
  11. scanf("%d", &n);
  12. int r = Fact(n);
  13. printf("%d", r);
  14. return 0;
  15. }

我们试着输入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相加所得。由此条件,我们很快就能用递归实现:

  1. #include<stdio.h>
  2. int Fact(int n)
  3. {
  4. if (n <= 2)
  5. return 1;
  6. return Fact(n - 1) + Fact(n - 2);
  7. }
  8. int main()
  9. {
  10. int n = 0;
  11. scanf("%d", &n);
  12. int r = Fact(n);
  13. printf("%d ", r);
  14. return 0;
  15. }

当我们输入10,求斐波那契数列的第10位数,果然得到了55,这样一看,还没有什么问题 ,但是当我们要求更大位数的值时:

它却没有得出结果,这是为什么呢,因为,函数在内部多次调用了自己,产生了大量的重复计算,导致计算量巨大,代码执行效率非常低,让计算机也无法快速得出结果,这个例子告诉我们,递归是有使用条件的 ,如果要设计一个需要重复计算的程序,不能无脑使用递归,而是首先要思考递归能不能用,是否能让代码简洁的同时,更加高效,那么此类例子我们如何解决呢?接下来我们要介绍另一种能多次重复相同计算的方法。

迭代

   迭代是类似循环的方法,它包含了循环,本质是多次做相同的动作,使程序运行起来实现我们要实现的功能,上述例子使用迭代能高效地解决:

  1. #include<stdio.h>
  2. int Fact(int n)
  3. {
  4. int i = 0;
  5. int a = 1;
  6. int b = 1;
  7. int c = 0;
  8. int temp = 0;
  9. for (i = 1; i <= n - 2; i++)
  10. {
  11. c = a + b;
  12. temp = c;
  13. a = b;
  14. b = temp;
  15. }
  16. return c;
  17. }
  18. int main()
  19. {
  20. int n = 0;
  21. scanf("%d", &n);
  22. int r = Fact(n);
  23. printf("%d", r);
  24. return 0;
  25. }

这次我们试着求第50位的斐波那契数:

可以看到,很快就得到了结果,但是答案是错误的,因为要求的数太大,一个字节无法表示,但是我们可以很直观的看见两者的差别,在这这样一个例子中,使用迭代会优于使用递归。所以,使用递归还是迭代,需要分析二者的优点和缺点选择更适合的方法。 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/607240
推荐阅读
相关标签
  

闽ICP备14008679号