前言
不像加减乘除,我们求学期间就已经见识过多次了,而大多数初学者在此之前可能都从未了解接触过递归思想,这使得很难上手递归算法,今天我希望能尽我所能结合画图已经例题的方法把递归算法讲解的通俗易懂,帮助大家入门
废话不多说了,我们开始今天的内容
一.什么是递归?
程序调用自身的编程技巧称为递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。 递归算法通常指一个过程或函数在其定义或说明中直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。(也就是说我们现在学的需要使用递归的场景大多数通过循环也能解决,在下面介绍的例子中会用循环也实现一遍)
递归的主要思考方式在于:把大事化小
当你在使用递归时遇到思考瓶颈,请牢记大事化小的思想!!
二.递归的两个必要条件
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续。
2.每次递归调用之后越来越接近这个限制条件。
当你不满足这两个条件的任意一条时,程序会陷入死循环
当你的递归写出bug时,往往是没考虑上面这两个条件或者条件设置有误,调试时多想想递归条件最好能够画下图帮助自己理解。
三.配合实例讲解
打印整型数据的每一位
实例一:
接受一个整型值(无符号),按照顺序打印它的每一位。
例如:
输入: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; }
我们先来看看效果
说实话,同样实现一个功能递归比循环简单多了,从代码的行数就能看出来。这就是我们使用递归算法的意义
求字符串长度
实例二
编写函数不允许创建临时变量,求字符串的长度。
#include <stdio.h> int Strlen(const char*str) { if(*str == '\0')//是个空字符串 return 0; else return 1+Strlen(str+1);//每次递归让Strlen朝后移动一位直至遇到"\0"不满足递归条件 } int main() { char *p = "abcde"; int len = Strlen(p); printf("%d\n", len); return 0; }
咱们还是画个图理解吧
结合咱们这个图理解起来就比较简单啦,我希望以后你自己写的时候在有弄不清逻辑时也能画一个类似的图来理解。
循环实现
int Strlen(char* s)
int Strlen(char* s) { int count = 0; while (*s != '\0') { count++; s++; } return count; } int main() { char* p = "abcde"; int len = Strlen(p); printf("%d\n", len); return 0; }
结合咱们这个图理解起来就比较简单啦,我希望以后你自己写的时候在有弄不清逻辑时也能画一个类似的图来理解。