维基百科给出了以下定义:java
程序调用自身的编程技巧称为递归.递归做为一种算法在程序设计语言中普遍应用。算法
上面的说法略显官方。简而言之,递归就是本身调用本身,可是这个调用它是有必定条件的,好比:编程
优势:代码简洁、清晰(须要你理解算法,不然会更晕) 缺点:调用次数控制很差,容易形成堆栈溢出,此外,它的每次传递参数都是至关于在压栈,每次返回结果都至关于出栈,这个过程是很是影响执行效率的。数组
优势:逻辑简单,速度快 缺点:不能解决全部的问题,有些问题必须用递归实现。好比,著名的汉若塔问题,若是有谁能够用其余方式写出来我服。spa
关于使用场景,我总结了一句话:调用次数较少且用循环实现极为恶心的时候,能够尝试使用递归。debug
public class Main {
private static int sum(int[] arr, int z) {
if (z == arr.length) {
return 0;
}
int x = sum(arr, z + 1);
int res = arr[z] + x;
return res;
}
public static void main(String[] args) {
int arr[] = {1, 2};
sum(arr, 0);
}
}
复制代码
这个示例最简单,固然这里是为了方便说明问题,实际上用循环实现才是最好的。目的就是计算 arr 数组各元素的总和,看输入参数,你们能够猜到返回结果是 3 。下面我说下看这类程序的小技巧。设计
首先,咱们要找到程序的递归边界,也就是递归结束的条件(这样说也不许确,看具体的代码实现,有时递归边界确实是递归结束的条件,返回最终结果,但有时又是递归最后一层返回结果的条件,好比如下程序)。3d
没看懂的,请复制代码 debug 一步一步的运行。一开始看反正我是被绕晕的。代理
public class Main {
static int i = 1;
public static void show(int sum) {
sum = sum + i; //业务代码1
//递归头
if (i == 10) {
System.out.println(sum);
return;
}
i++; //业务代码2
show(sum); //递归体
}
public static void main(String[] args) {
int sum = 0;
show(sum);
}
}
复制代码
以上写法的递归边界,就属于我上面说的,它就是递归结束的条件。它的返回结果就是递归的最终结果,而不是上一层的结果。code
public class Main {
public static int f(int n) throws Exception {
if(n==0){
throw new Exception("参数错误!");
}
if (n == 1 || n == 2) {
return 1;
} else {
return f(n-1)+f(n-2); //本身调用本身
}
}
public static void main(String[] args) throws Exception {
for (int i = 1; i <=10; i++) {
System.out.print(f(i)+" ");
}
}
}
复制代码
因为 File 类下length() (返回值类型为 long 型) 方法只能统计文件的大小,没有方法直接统计文件夹的大小,须要使用递归的方法遍历到全部的文件,并累加,最终计算出文件夹大小。
public class Main {
public static void main(String[] args) {
File dir = getDir();
System.out.println(getFileLength(dir));
System.out.println("统计完成!");
}
public static File getDir() {
//1,建立键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个文件夹路径:");
//2,定义一个无限循环
while(true) {
//3,将键盘录入的结果存储并封装成File对象
String line = sc.nextLine();
File dir = new File(line);
//4,对File对象判断
if(!dir.exists()) {
System.out.println("您录入的文件夹路径不存在,请从新录入:");
}else if(dir.isFile()) {
System.out.println("您录入的是文件路径,请从新录入:");
}else {
//5,将文件夹路径对象返回
return dir;
}
}
}
public static long getFileLength(File dir) {
//1,定义一个求和变量
long len = 0;
//2,获取该文件夹下全部的文件和文件夹listFiles();
File[] subFiles = dir.listFiles();
//3,遍历数组
if(subFiles != null) {
for (File subFile : subFiles) {
//4,判断是文件就计算大小并累加
if(subFile.isFile()) {
len = len + subFile.length();
//5,判断是文件夹,递归调用
}else {
len = len + getFileLength(subFile);
}
}
}
return len;
}
}
复制代码
总结:这篇主要是介绍下递归的定义、与循环的区别以及它的使用场景,最后提供了几个代码示例给你们研究,看不懂的请复制代码,debug 一步一步运行理解。
参考连接:www.jianshu.com/p/edfc4e35f…
推荐阅读: