帝龟出世
大家好,我是今天的主角,帝龟!
-
- 一只自带帝王之气的乌龟殿下 - -
wo来自遥远的东海之滨,每天清晨我…咳咳, 有些扯远了
下面进入重点:
寻欢初识帝龟
下文为循环和递归的一些基本概念
循环:重复性的执行某段程序
"寻欢"和"帝龟"不一样,它是个直性子,它会一次性干脆利落的把活全都干完,然后再也不回来,永远不回头。
递归:程序调用自身的一种编程技巧
在Java中具体表现为方法在方法体内部调用方法本身。
"帝龟"是个小懒龟,每次做事情都会留一些,然后再回来反序地把这些剩下的事情一一做完。再打个不太恰当的比方,就像使用吸尘器扫地,第一遍没有扫干净,还需要反方向回来再拖一遍。
初现端倪
可能在很多人包括以前的我看来,递归和循环除了实现方式(语法)不同,其实没有什么两样。
我们先来看一下以下两段代码:
/**
* @author guqueyue
* @Date 2020/2/19
* for循环输出十句话
**/
public class For1 {
public static void main(String[] args) {
System.out.println("============循环结果============");
for (int i = 9; i >= 0; i--) {
// 输出一句大实话
System.out.println("您的点赞、评论和关注是对我最大的支持" + i);
}
}
}
/**
* @author guqueyue
* @Date 2020/2/19
* 递归输出十句话
**/
public class Recursion1 {
public static void main(String[] args) {
System.out.println("============递归结果============");
recursion1(9);
}
private static void recursion1(int n) {
// 递归终止条件,也就是递归的出口
if (n == 0);
else
recursion1(n-1);
// 输出一句大实话
System.out.println("您的点赞、评论和关注是对我最大的支持" + n);
}
}
上文两段代码看起来没有什么两样,都是从9开始,步长为1,逐渐递减,到0截止,但是我们来看一下输出结果:
这个时候可能大家就会发现不一样的地方了,Why?
不要着急,下一章节《来龙去脉》为您揭晓
来龙去脉
原理:原来递归是在栈中执行的,栈是一种先进后出的数据结构,方法先要入栈,然后再出栈。
入栈
出栈
递归递归,递去归来,有递去就有归来
还是有点懵?那就再上两段代码:
/**
* @author guqueyue
* @Date 2020/2/19
* 用循环求5的阶乘
**/
public class forFactorial {
public static void main(String[] args) {
int num = 1;
for (int i = 5; i >= 1; i--) {
num *= i;
}
System.out.println("循环求出5的阶乘为:" + num);
}
}
/**
* @author guqueyue
* @Date 2020/2/19
* 用递归求5的阶乘
**/
public class recursionFactorial {
public static void main(String[] args) {
int num = factorial(5);
System.out.println("递归求出5的阶乘为:" + num);
}
private static int factorial(int n) {
// 终止条件
if (n == 1)
return 1;
return n * factorial(n - 1);
}
}
结果是一样的,但其实递归和循环差别还是蛮大的:
循环:num = 5 * 4 * 3 * 2 * 1 = 120
递归:
num
逐渐递进,其实是一个压栈的过程
= factorial(5)
= factorial(5 * factorial(4))
= factorial(5 * factorial(4 * factorial(3)))
= factorial(5 * factorial(4 * factorial(3 * factorial(2))))
= factorial(5 * factorial(4 * factorial(3 * factorial(2 * factorial(1)))))
遇到终止条件:factorial(1) = 1,开始出栈
= factorial(5 * factorial(4 * factorial(3 * factorial(2 * 1))))
= factorial(5 * factorial(4 * factorial(3 * 2 * 1)))
= factorial(5 * factorial(4 * 3 * 2 * 1))
= factorial(5 * 4 * 3 * 2 * 1))
= 5 * 4 * 3 * 2 * 1
= 120
回归完毕,完成出栈
迷失的帝龟
特需注意的是:递归一定要写终止条件,也就是递归一个要有一个出口,不然的话就会报出栈溢出异常,成了一个死递归。
/**
* @author guqueyue
* @Date 2020/2/19
* 这是一个死递归
**/
public class Error {
public static void main(String[] args) {
error();
}
private static void error() {
error();
}
}
如图所示:
我要这递归有何用?
如果大家能够看到这里的话,想必大家会产生一个小小的疑惑:递归能干的,循环貌似也能干,而且好像更加简单,那么要递归干嘛?
答:循环能解决的问题,递归一般也能解决;但是递归能解决的问题,循环就不一定能解决了。
递归运用的是"分而治之"的思想,把一个复杂的原问题拆分成若干个子问题来解决。秒就秒在,递归能用有限的语句,表现出无限的过程。如果我们不了解递归,我们可能也掌握不了快速排序,归并排序等算法。
考考你
下面是一个递归遍历删除文件夹的例子,你理解了吗?
/**
* @author guqueyue
* @Date 2020/02/20
* 递归遍历删除文件夹
**/
public class DeleteFiles {
public static void main(String[] args) {
// 创建文件对象
File file = new File("C:\\java");
deleteFile(file);
}
/**
* 遍历删除方法
* @param file
*/
public static void deleteFile(File file) {
//判断是否为文件,如果文件对象只是一个文件,直接删除
if (file.isFile())
file.delete();
// 获取一个抽象路径名数组
File[] files = file.listFiles();
for (File f : files) {
// 终止条件
if (f.isFile())
// 删除此抽象路径名表示的文件或目录
// 如果此路径名表示一个目录,则该目录必须为空才能删除
f.delete();
else
// 继续递进
deleteFile(f);
}
file.delete();
}
}
参考思路
1.在C盘下面新建一个命名为"java"的文件夹,再在"java"文件夹里新建一个命名为"a"的文件夹,以此类推,分别建立"b"、"c"文件夹,再在"c"文件夹下新建一个命名为"d"的.txt文件
2.试着打印一下当前路径,以及删除文件操作时的文件名,
为了以示区分,最后一个输出语句我用了红色的错误输出流。
3.我们来看一下打印结果