java之递归【通俗易懂】
概念
递归:指在当前方法内调用自己。
递归的分类:
- 直接递归:方法直接调用自己。比如方法A调用方法A
- 间接递归:方法间接调用自己。比如A方法调用B方法,B方法调用C方法,C方法调用A方法。
注意事项:
- 递归一定要有结束条件,否则会无限递归,直至栈内存溢出。
- 虽然递归有结束条件,但是递归次数太多,也会发生栈内存溢出。
- 构造方法,禁止递归(直接编译报错,因为如果允许无限new对象,会导致堆内存溢出。)
为什么会栈内存溢出:
代码演示:
public class Demo01DiGui {
public static void main(String[] args) {
// a();
b(1);
}
/*
* 1.递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
* Exception in thread "main"
* java.lang.StackOverflowError
*/
private static void a() {
System.out.println("a方法");
a();
}
/*
* 2.在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
* 4993
* Exception in thread "main" java.lang.StackOverflowError
*/
private static void b(int i) {
System.out.println(i);
//i==5000的时候结束递归
if(i==5000){
return;
}
b(++i);
}
/*
* 3.构造方法,禁止递归
* 编译报错:构造方法是创建对象使用的,不能让对象一直创建下去
*/
public Demo01DiGui() {
//Demo01DiGui();
}
}
图解:
简单案例A
需求: 求1~n的和
分析:1~n的累计和 = 1 + 2 + 3 +…+ (n-1) + n,可以看成是 n + (n-1) + …+ 3 + 2 + 1。因此可以把累和的操作定义成一个方法,递归调用。
结束条件就是 n = 1。
代码演示:
/**
* @author layman
*/
public class Demo02Recurison {
public static void main(String[] args) {
int s = sum(3);
System.out.println(s);
}
public static int sum(int n){
// 结束条件
if(n == 1){
return 1;
}
return n + getSum(n-1);
}
}
原理图解
简单案例B
需求:求1~n的阶乘
分析:1~n的阶乘= 1 * 2 * 3 … (n-1) * n,可以看成是 n * (n-1) * …* 3 * 2 * 1。因此可以把累和的操作定义成一个方法,递归调用。
结束条件就是 n = 1。
代码演示:
/**
* @author layman
*/
public class Demo01 {
//计算n的阶乘,使用递归完成
public static void main(String[] args) {
int n = 20;
long value = getJC(n);
System.out.println("n的阶乘为:"+ value);
}
/**
* 通过递归实现n的阶乘
*/
public static long getJC(int n) {
if (n == 1) {
return 1;
}
return n * getJC(n - 1);
}
}
简单案例C
需求:递归打印文件的多级目录(包括子文件夹和子文件)
分析:多级目录的打印,就是目录的嵌套。在遍历之前,无法知道到底有多少级目录,所以我们依然要使用递归实现
遍历的文件目录如下:
代码演示:
import java.io.File;
/**
* @author layman
*/
public class Demo02 {
public static void main(String[] args) {
File dir = new File("D:\\movie");
printDir(dir);
}
public static void printDir(File dir) {
// 获取文件和文件夹
File[] files = dir.listFiles();
/**
* 判断:
* 如果是文件,则打印绝对路径。
* 如果是文件夹时,则递归再次调用该方法,继续遍历。
*/
for (File file : files) {
if (file.isFile()) {
System.out.println("文件名:"+ file.getAbsolutePath());
} else {
System.out.println("目录:"+file.getAbsolutePath());
printDir(file);
}
}
}
}
运行结果:
目录:D:\movie\Japanese
文件名:D:\movie\Japanese\愤怒的大象.avi
目录:D:\movie\Japanese\电车
文件名:D:\movie\Japanese\电车\葫芦.avi
目录:D:\movie\欧美
文件名:D:\movie\法外狂徒.3gp