关于递归循环的总结(包含题目解析与思路)

C语言函数————递归(曾经困扰我很久的问题)
相信大家在一开始学习函数这一章节的时候,像我这样的白痴脑袋曾经被递归这一算法思想困扰了很久。
所以这样一篇博客早已是大一上学期刚学完递归后的我想总结的小节,这不刚放寒假嘛,赶紧抓住这一时机,写下了这样一篇博客~
希望大家看完发现错误后能即使留言批评与纠正。

首先先介绍一下递归
递归,顾名思义,就是套娃(doge)。所以刚开始作为刚接触语言学习的我来说,我就纯把递归理解为循环了,因为都是对代码的反复使用。虽说这样理解好像没啥很大的毛病,因为可以使用循环的地方通常都可以使用递归,但是深入了解过后还是能发现它们的区别:
1(个人觉得最大):递归的规模小,很大程度上受到栈上的限制
循环规模大,基本上不会受限制
2 :递归总是将问题从大到小放缩,所以限制条件也即(1==n)
循环则不然,既可以从大到小,也可以从小到大放缩,条件都是我们自己设定
还有一些比较深入的问题由于博主能力有限也总结不出来~…
总之它们两者的不同也就顺然的引出它们两者的优缺点:
递归:代码简单易懂,但是效率低下(例子的话,可以看下面“斐波那契数列的”的解决)
循环:效率高,但是不好懂!
所以基本上,有时循环解决的问题号,又是则是递归,这就要看场合了。
下面举一些例子来介绍递归,顺带引出上面提到的“场合”,进一步区分它们俩
eg1 :这里引用大名鼎鼎的《C Primer Plus》书上的最初例子(稍微该简短了些,详细见第六版P221)

#include void up_and_down(int a){ printf("Level %d\n",a); if(a < 4) up_and_down(a + 1); //递归 printf("LEVEL %d\n",a); //大小写利于区分 } int main(void){ up_and_down(1); //最初给n赋值1 return 0; }

最终结果是:
关于递归循环的总结(包含题目解析与思路)
文章图片

这里用我自己的大白话+画图来解释一下啦~
我们先来看看递归过程中的“去“
关于递归循环的总结(包含题目解析与思路)
文章图片

再来看看”回“
【关于递归循环的总结(包含题目解析与思路)】关于递归循环的总结(包含题目解析与思路)
文章图片

*这里为啥要故意每个箭头拐一下呢?是因为要先回到上一级调用结束,才能跳出花括号进入下一条语句~
这里小白博主刚开始脑袋秀逗,以为花括号外即是else,所以导致想了很久才想明白。。。
这样一画图一理解,相信应该很好理解————吧?
相同的,这样利用递归思路的解题还有很多
譬如”利用递归来写一个代码——从键盘输入一串字符,程序帮忙打印出来”
关于递归循环的总结(包含题目解析与思路)
文章图片

算法思路就是:利用递归和求余,当a是一个两位数字以上的数字时,让它递归除以10,得到前两位数字,不断递归,直到最后一个数字,再求余求回来。
结果如下:
关于递归循环的总结(包含题目解析与思路)
文章图片

接着举一个很有名的例子——斐波那契数列
先介绍一下斐波那契额数列(即第三位数字永远是前两项的和)
:1 1 2 3 5 8 13 21 34 55…
思路:(数列数列,从小老师就教我们看到数列就去想通项公式嘛!)
关于递归循环的总结(包含题目解析与思路)
文章图片

所以我们就可以很好地想到递归思路,然后写出以下代码:
关于递归循环的总结(包含题目解析与思路)
文章图片

这样看起来真的很简单,但是当你将n赋值一个较大的数字时,比如40
程序就卡住了?!
别慌,这不是咱程序写错了,而是你得耐心,得给你宝贝电脑一些时间(doge 恐怕终于你等到了,算出来也是个越界的数字。。)
这就纳闷了,为啥呢?
学过数学的我们都知道,要想求第40个斐波那契数列,我们需要第39个和第38个,而第39个我们需要38和37,第38个我们需要37和36…
关于递归循环的总结(包含题目解析与思路)
文章图片

光是一个37,我们就重复计算了很多次。该函式使用了双递归,即函数每一集递归都要都调用本身两次
所以导致这些变量呈指数性增长,很快就消耗掉计算机内存导致栈溢出。
所以这里就引出了文章刚开始提到的“场合”问题,这里到底该用递归还是循环呢?
答案一定是循环,这也即是体现它们俩优缺点的明显区别。
将程序改写成用循环写:
关于递归循环的总结(包含题目解析与思路)
文章图片

这样同样可以解决问题,但是效率是递归的数倍。
所以以后考虑用到循环的问题,可以想想递归思路,但是也要想想其复杂度问题~(本人还没学过数据结构QAQ,所以我也不懂)
最后的最后,还有一个很著名的问题想和大家分享一下~~
——————汉诺塔问题(Hanio Tower)
汉诺塔问题:
首先要想解决它,你得先知道,啥是汉诺塔(说实话要不是C语言问题中有提到这一问题的话,我也不知道哈哈哈)
简单概括一下就是说,有A,B,C三根柱子,其中刚开始A柱子上有N个圆盘,(从上往下)从小到大,最终目标是,通过B柱子的辅助,将A柱子上的圆盘移动到C柱子上去,过程中,要遵循从上往下,从小到大的规律!(也即大盘子不能放在小盘子上)。
问:要移动几次?
关于递归循环的总结(包含题目解析与思路)
文章图片

其实看似有点难懂的问题里,这其实就是一个递归问题。
但是本人认为,如果你不将除了最下面那块最大的以外,即(n-1)个圆盘看成整体的话,不太好想~
思路:始终秉着一个目的,将当前最大的那块移到C盘上去。
最初版本(本人认为比较垮。。)
关于递归循环的总结(包含题目解析与思路)
文章图片

修改后
关于递归循环的总结(包含题目解析与思路)
文章图片

两个结果都一样如下
关于递归循环的总结(包含题目解析与思路)
文章图片

总结
C语言中函数规定,可以自己调用自己。那么既然如此就不能白白浪费这一特性,当然还是要看“场合”,因为递归效率实在是太低了。。
QAQ

    推荐阅读