摘要:簡而言之,遞歸就是自己調用自己,但是這個調用它是有一定條件的,比如子問題須與原始問題為同樣的事,且更為簡單。當時,這層遞歸返回,也就是返回到的這層遞歸。這時,至此,遞歸結束,返回結果給調用方。
什么是遞歸?
維基百科給出了如下定義:
程序調用自身的編程技巧稱為遞歸.遞歸作為一種算法在程序設計語言中廣泛應用。
上面的說法略顯官方。簡而言之,遞歸就是自己調用自己,但是這個調用它是有一定條件的,比如:
子問題須與原始問題為同樣的事,且更為簡單。
調用自身的次數不能太多,否則會造成程序堆棧溢出。
必須設置遞歸邊界,也就是遞歸的結束條件,否則遞歸會無限循環直到程序堆棧溢出。
遞歸與循環的區別遞歸
優點:代碼簡潔、清晰(需要你理解算法,否則會更暈)
缺點:調用次數控制不好,容易造成堆棧溢出,此外,它的每次傳遞參數都是相當于在壓棧,每次返回結果都相當于出棧,這個過程是非常影響執行效率的。
循環
優點:邏輯簡單,速度快
缺點:不能解決所有的問題,有些問題必須用遞歸實現。比如,著名的漢若塔問題,如果有誰可以用其他方式寫出來我服。
關于使用場景,我總結了一句話:調用次數較少且用循環實現極為惡心的時候,可以嘗試使用遞歸。
關于遞歸的幾個實例計算 int 形數組的總和
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 。下面我說下看這類程序的小技巧。
首先,我們要找到程序的遞歸邊界,也就是遞歸結束的條件(這樣說也不準確,看具體的代碼實現,有時遞歸邊界確實是遞歸結束的條件,返回最終結果,但有時又是遞歸最后一層返回結果的條件,比如以下程序)。
當 z = 2 時,這層遞歸返回 0 ,也就是 x = 0、返回到 z = 1 的這層遞歸。
此時,res = arr[1] + 0 ,返回 res = 2 也就是 x = 2 給到 z = 0 的這層遞歸。
這時,res = arr[0] + 2 = 3 至此,遞歸結束,返回結果給調用方。
沒看懂的,請復制代碼 debug 一步一步的運行。一開始看反正我是被繞暈的。
計算 1 到 100 的總和
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); } }
以上寫法的遞歸邊界,就屬于我上面說的,它就是遞歸結束的條件。它的返回結果就是遞歸的最終結果,而不是上一層的結果。
斐波那契數列
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 一步一步運行理解。
參考鏈接:https://www.jianshu.com/p/edfc4e35f383
推薦閱讀:
1、java | 什么是動態代理
2、SpringBoot?| 啟動原理
3、SpringBoot | 自動配置原理
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75870.html
摘要:那么,有了循環,為什么還要用遞歸呢在某些情況下費波納切數列,漢諾塔,使用遞歸會比循環簡單很多很多話說多了也無益,讓我們來感受一下遞歸吧。 遞歸介紹 本來預算此章節是繼續寫快速排序的,然而編寫快速排序往往是遞歸來寫的,并且遞歸可能不是那么好理解,于是就有了這篇文章。 在上面提到了遞歸這么一個詞,遞歸在程序語言中簡單的理解是:方法自己調用自己 遞歸其實和循環是非常像的,循環都可以改寫成遞歸...
摘要:如果存在這么個函數,那么我們就可以通過求解的不動點來求出了。尋找轉換函數的不動點找到了轉換函數后,下一步就是確定其不動點了,而這個不動點就是我們最終想要的。 本文原發于個人博客 遞歸 作為計算機科學中很重要的一個概念,應用范圍非常廣泛。比較重要的數據結構,像樹、圖,本身就是遞歸定義的。比較常見的遞歸算法有階乘、斐波那契數等,它們都是在定義函數的同時又引用本身,對于初學者來說也比較好理解...
摘要:今天我們繼續使用的擼我們的實戰項目,只有在實戰中我們才會領悟更多,光紙上談兵然并卵,繼上篇我們的一個案例引發的動態組件與全局事件綁定總結之后,今天來聊一聊我們如何在項目中使用遞歸組件。 今天我們繼續使用 Vue 的擼我們的實戰項目,只有在實戰中我們才會領悟更多,光紙上談兵然并卵,繼上篇我們的《Vue一個案例引發的動態組件與全局事件綁定總結》 之后,今天來聊一聊我們如何在項目中使用遞歸組...
摘要:不斷執行這個操作代碼實現快速排序用遞歸比較好寫如果不太熟悉遞歸的同學可到遞歸就這么簡單。 前言 大概花了一周的時間把八大基礎排序過了一遍,這篇博文主要是用來回顧一下八大基礎排序的要點和一些總結~ 回顧: 冒泡排序就這么簡單 選擇排序就這么簡單 插入排序就這么簡單 快速排序就這么簡單 歸并排序就這么簡單 堆排序就這么簡單 希爾排序就這么簡單 基數排序就這么簡單 總的來說:快速排序是用...
閱讀 2592·2023-04-25 22:09
閱讀 2837·2021-10-14 09:47
閱讀 1889·2021-10-11 11:10
閱讀 2677·2021-10-09 09:44
閱讀 3372·2021-09-22 14:57
閱讀 2493·2019-08-30 15:56
閱讀 1615·2019-08-30 15:55
閱讀 775·2019-08-30 14:13