递归的概述及注意事项
/*
递归:
方法定义本身调用方法本身的现象叫做递归
StringBuffer.append().append().append() 这个不叫递归,这个叫方法的连续调用
Math.max(Math.max(a,b),c) 这个也不叫递归,这个叫方法的嵌套使用
递归的注意事项:
1、递归一定要有一个出口,结束条件,否则就是死循环
2、递归的次数不能太多,否则就会发生内存溢出
3、构造方法不能使用递归
*/
public class RecursionDemo1 {
//构造方法不能使用递归
// RecursionDemo1(){
// RecursionDemo1();
// }
public static void show(int i){
//第一步:定义结束条件
if(i<0){
System.out.println("结束递归");
}else {
System.out.println(i);
//不能是 i--
//因为 i-- 都是先赋值再 --
//那么i永远都是10
show(--i);
}
}
public static void main(String[] args) {
show(10);
}
}
递归内存图
递归思想的应用
/*
递归求阶乘:
5!= 5*4*3*2*1 = 120
= 5*4!
= 5*4*3!
= 5*4*3*2!
= 5*4*3*2*1!
*/
public class RecursionDemo2 {
public static void main(String[] args) {
//在学习递归之前的做法:
int result = 1;
for (int x = 2; x <= 5; x++) {
result = result * x;
}
System.out.println("5的阶乘是:" + result);
System.out.println("====================");
//学习递归之后
System.out.println("5的阶乘是:" + recursionFun(5));
}
/*
递归的实现思想:
1、结束条件:
if(i==1){return 1}
2、寻找规律:
if(i!=1){
return i * recursionFun(i-1);
}
*/
public static int recursionFun(int i) {
if(i==1){
return 1;
}else {
//5 * recursionFun(4)
//5 * 4 * recursionFun(3)
//5 * 4 * 3 * recursionFun(2)
//5 * 4 * 3 * 2 * recursionFun(1)
//5 * 4 * 3 * 2 * 1
return i * recursionFun(i-1);
}
}
}
/*
兔子问题(斐波那契数列)
有一对兔子,从出生第三个月开始,每个月都生一对兔子,
小兔子长到三个月后每个月又生一对兔子,假设这些兔子都不会死,
问:20个月,又多少对兔子?
找规律:
月 兔子对数
1 1
2 1
3 2
4 3
5 5
6 8
7 13
...
由此可见,兔子的对数数量是:
1、1、2、3、5、8、13、21...
发现的规律是:
1、从第三项开始,每一项都是前两项之和
2、说明每一项的前两项的数据是已知的
如何实现呢?
1、数组方式实现
2、基本变量实现
3、递归方式实现
*/
public class RecursionDemo3 {
public static void main(String[] args) {
//第一种方式:使用数组实现
int[] arr = new int[20];
arr[0] = 1;
arr[1] = 1;
// arr[2] = arr[0]+arr[1];
// arr[3] = arr[1]+arr[2];
// arr[4] = arr[2]+arr[3];
// //...
// arr[19] = arr[17] + arr[18];
for (int i = 2; i < arr.length; i++) {
arr[i] = arr[i - 2] + arr[i - 1];
}
System.out.println("第20个月的兔子对数为:" + arr[19]);
System.out.println("====================================");
//第二种方式:基本变量
//定义两个变量表示相邻的两项
//第1个相邻的数据:a=1,b=1;
//第2个相邻的数据:a=1,b=2;
//第3个相邻的数据:a=2,b=3;
//第4个相邻的数据:a=3,b=5;
//第5个相邻的数据:a=5,b=8;
//...
//规律:
//下一次的相邻数据a是上一次相邻数据的b的值,下一次相邻数据的b是上一次的a+b的值
int a = 1;
int b = 1;
//第1和第2个月的兔子对数给出来了
//剩下的18个月中有17个相邻的
for (int i = 0; i < 18; i++) {
//定义一个临时变量,保存上一次a的值
int temp = a;
a = b;
b = temp + b;
}
System.out.println("第20个月的兔子对数为:" + b);
System.out.println("======================================");
//第三种方式:递归方式实现
System.out.println("第20个月的兔子对数为:" + fibonacci(20));
}
/*
递归实现:
1、结束条件是什么?
当month的值是1或者2的时候,return 1;
2、递归的逻辑:
从month==3到month==20的时候,每一个月都是前两个月之和
*/
public static int fibonacci(int month){ //如果month=5
if(month==1 ||month==2){
return 1;
}else {
//fibonacci(4) + fibonacci(3)
//fibonacci(3) + fibonacci(2) + fibonacci(2) + fibonacci(1)
//fibonacci(2) + fibonacci(1) + 1 + 1 + 1
//1 + 1 + 1 + 1 + 1
//5
return fibonacci(month-1) + fibonacci(month-2);
}
}
}
import java.io.File;
/*
递归遍历目录下指定后缀名结尾的文件名称E:\数加科技\十四期所有.png结尾的文件名称
*/
public class RecursionDemo4 {
public static void main(String[] args) {
//将该目录封装成一个File对象
File file = new File("E:\\数加科技\\十四期");
//定义一个方法实现递归
getPngFile(file);
}
public static void getPngFile(File file){
//获取该目录下所有的file对象数组
File[] files = file.listFiles();
//遍历数组得到每一个File对象
for(File f:files){
//判断该File对象是否是一个文件夹
if(f.isDirectory()){
getPngFile(f);
}else {
//判断文件的名称是否以.png后缀
if(f.getName().endsWith(".png")){
//是,就输出
System.out.println(f.getName());
}
}
}
}
}
import java.io.File;
/*
递归删除带内容的目录E:\数加科技\十四期副本
*/
public class RecursionDemo5 {
public static void main(String[] args) {
File file = new File("E:\\数加科技\\十四期副本");
//定义方法实现递归
deleteFileFun(file);
}
public static void deleteFileFun(File file) {
//获取该目录下所有的file对象组成的数组
File[] files = file.listFiles();
//判断该数组是不是空,如果是空直接删除
if (files != null) {
//遍历数组,得到每一个File对象
for(File f:files){
//判断是否是文件夹
if(f.isDirectory()){
deleteFileFun(f);
}else {
//不是文件夹的时候,直接删除
System.out.println(f.getName()+": "+f.delete());
}
}
//如果在执行完上面的步骤之后十四期副本里面内容为空,就删除十四期副本。
System.out.println(file.getName()+": "+file.delete());
}else {
//如果走if判断时十四期副本为空,则直接删除十四期副本
System.out.println(file.getName()+": "+file.delete());
}
}
}