一.什么是递归?
程序调用自身的编程技巧称为递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。 递归算法通常指一个过程或函数在其定义或说明中直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。(也就是说我们现在学的需要使用递归的场景大多数通过循环也能解决,在下面介绍的例子中会用循环也实现一遍)
递归的主要思考方式在于:把大事化小
当你在使用递归时遇到思考瓶颈,请牢记大事化小的思想!!
具体有关递归知识的详解请看以下链接,这里我们是结合实战例子讲,就不在此具体展开了。
【C语言】带你玩转递归,迭代算法
实战一. 打印整型数据的每一位
接受一个整型值(无符号),按照顺序打印它的每一位。
例如:
输入:1234,输出 1 2 3 4
代码如下:
#include <stdio.h> void print(int n) { if(n>9)//如果不大于9直接打印当前n的值即可 { print(n/10); } printf("%d ", n%10); } int main() { int num = 1234; print(num); return 0; }
我们想要把一个四位数甚至更多位的数每一位给剥离出来,首先要想到的是怎么得到每一位
我们知道,对10取余%就可以得到这个数的个位的数,而除以10就可以把这一位给消去,此时我们就可以这样实现(以下把n当作一个四位数举例)
先让n对10%得到此时这一位的数,然后将n/10来到下一位,再让n对10%得到这位数继续朝下进行直至n对10%等于0,说明此时n是个小于10的数只剩下它需要取了,取下它结束递归即可
画图解释分析
递归的递就是传递的意思,而归的意思是回归
这就是递归!
解释完了递归在这段代码的应用,我们来讲讲这个代码中出现的问题
当我们中用户某天突发奇想输入了一个负数进去会发生什么呢?
我们这个程序设定的条件是只针对正数的,要想输入一个负数也能打印就得这样修改代码
void print(int n) { if (n > 9)//如果不大于9直接打印当前n的值即可 { print(n / 10); } else if (n < -9) { print(n / 10); } printf("%d ", n % 10); } int main() { int num = -1234; print(num); return 0; }
或者把我们传入的int改为一个无符号整型
void print(unsigned int n) { if (n > 9)//如果不大于9直接打印当前n的值即可 { print(n / 10); } /*else if (n < -9) { print(n / 10); }*/ printf("%d ", n % 10); }
我在这里想提醒大家的是,无论在递归或者任何其他程序的编写中我们都得尽可能考虑各方面的情况,在以后的程序猿工作中,我们要知道用户是不总是照着你的指示来使用程序的,我们得尽可能保证程序的避免上面这种bug。
递归往往都能通过循环实现,我们现在来把这个例子用循环的方法实现一下
循环实现
//判断输入数字位数 #include<math.h> int Strlen(unsigned int n) { int count = 0; while (n / 10) { count++; n /= 10; } return count; } void print(unsigned int n) { int i = 0; int ret = Strlen(n); if (n > 9) { for (i = ret; i > 0; i--) { int m = pow(10, i); printf("%d ", n / m); n %= m; } } printf("%d", n); } int main() { int num = 123456789; print(num); return 0; }
我们先来看看效果
实战二.汉诺塔问题
什么是汉诺塔?
汉诺塔(Tower of Hanoi)源自印度古老传说的一个游戏,大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,并且在移动时三根柱子之间一次只能移动一个圆盘。
从上面的对于汉诺塔问题的说明我们可以得到这样一个结论
如果要把A柱上的盘子全部都移动到C柱上,要遵循以下规则:
1.每次只能移动A柱最上面的一个盘子
2.小盘子上不能放大盘子。
我们来一步一步分析,首先设此时A中有n个盘子,我们现在的目标是借助B柱把A上的盘子全部移动到C柱上
思路分析:
当需要A上需要移动的盘子n=2时
我们只需要先把A最上面的盘子移到B上,再把A另一个盘子移到C上,最后把B上盘子移到C上即可。
当需要A上需要移动的盘子n=3时
将2个盘子从A移动到B上。重复n=2时的步骤,此时是将那2个盘子从A借助C移动到B上
接着,把A上的盘子移动到C上 ,将B上的2个盘子移动到C上。重复n=2时的步骤,此时是将那2个盘子从B借助A移动到C
当需要A上需要移动的盘子n=4时
将3个盘子从A移动到B上。重复n=3时的步骤,与n=3不同之处在于,我们此时是借助C把A上盘子移到B
将A上最后一个盘子移动到C上
将B上的3个盘子移动到C上。重复n=3时的步骤,与n=3不同之处在于,我们此时是借助A把B上盘子移到C
当需要A上需要移动的盘子为n时
怎么样,经过上面的讲解你发现规律了吗?
也就是说,对于任意一个大于1的正整数n,如果有一个n层汉诺塔的问题,我们就可以将之分解为两个n-1层汉诺塔问题求解
通过我们上面的分析,我们就可以把这个问题的解决分成这三步:
1.将A上n-1层的盘子通过C移动到B上
2.将此时A上剩余的盘子移动到C上
3.将B上此时n-1层的盘子通过A移动到C上
参考代码如下:
#include<stdio.h> void Move (char A, char C, int n) { printf("把第%d个盘子从%c--->%c\n", n, A, C); } void HanoiTower(char A, char B, char C, int n) { if (n == 1) { Move(A, C, n); } else { //将n-1个盘子从A柱借助于C柱移动到B柱上 HanoiTower(A, C, B, n - 1); //将A柱最后一个盘子移动到C柱上 Move(A, C, n); //将n-1个盘子从B柱借助于A柱移动到C柱上 HanoiTower(B, A, C, n - 1); } } int main() { int n = 0; printf("输入A柱子上的盘子个数:"); scanf("%d", &n); //将n个盘子从A柱借助于B柱移动到C柱上 HanoiTower('A', 'B', 'C', n); return 0; }
实战三.青蛙跳台阶问题
青蛙跳台阶问题的描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多上种跳法。
青蛙跳台阶问题解题思路分析
当N=1时,那么青蛙就只有一种跳法。
当N=2时,青蛙可以跳两次一层台阶也可以跳一次二层台阶,有两种跳法。
当N=3时,青蛙可以先跳一次一层台阶,那么还需要跳两层台阶,那它此时就是N=2时的跳法,有两种跳法。
当青蛙跳一次二层台阶时,此时只需要跳一层台阶,那么它就是N=1时的跳法。
此时它的跳法就等于(N=1)+(N=2)种跳法。
当N=4时,青蛙跳一次一层台阶时,还需要跳三层台阶,那它此时剩下的跳法就等于N=3时的跳法,即有三种跳法。
青蛙跳一次二层台阶时,还剩二层台阶需要跳,那它此时剩下的跳法就是N=2时的跳法,则有两种跳法。
那么此时它的跳法就等于(N=2)+(N=3)种跳法。
思路总结
那么,不难看出青蛙跳台阶的规律,当N>2时,此时的跳法数就等于前面两个青蛙跳台阶跳法数之和
青蛙跳台阶代码实现
#include<stdio.h> int Jump(int n) { if (n == 1) { return 1;//当只有一层台阶时直接返回1 } if (n == 2) { return 2;//当只有2层台阶时就返回2 } if (n > 2) { return Jump(n - 1) + Jump(n - 2); }//当n>2时,利用递归进行返回 } int main() { int n = 0; scanf("%d", &n); int num = Jump(n); printf("%d\n", num); return 0; }
以上的汉诺塔与青蛙跳台阶的思路分析这块由于篇幅原因都是简单的分析了一下,详细的可以看看下面我的这两篇博客:
【C语言】图文解析,深入浅出汉诺塔问题
【C语言】手把手带你解决青蛙跳台阶问题
总结
今天的内容暂时到这里就结束了,我们今天通过几个实战例子带大家了解了递归的应用,我希望你如果看懂了能够自己独立的实现一下,这样才叫真正的学会了。
好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!
新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!
**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**