維基百科給出了以下定義: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…
推薦閱讀: