一文帶你搞懂Java中的遞歸
概述
遞歸:指在當(dāng)前方法內(nèi)調(diào)用自己的這種現(xiàn)象。
遞歸的分類:
- 遞歸分為兩種,直接遞歸和間接遞歸。
- 直接遞歸稱為方法自身調(diào)用自己。
- 間接遞歸可以A方法調(diào)用B方法,B方法調(diào)用C方法,C方法調(diào)用A方法。
注意事項:
- 遞歸一定要有條件限定,保證遞歸能夠停止下來,否則會發(fā)生棧內(nèi)存溢出。
- 在遞歸中雖然有限定條件,但是遞歸次數(shù)不能太多。否則也會發(fā)生棧內(nèi)存溢出。
- 構(gòu)造方法,禁止遞歸
public class Demo01DiGui { public static void main(String[] args) { // a(); b(1); } /* * 3.構(gòu)造方法,禁止遞歸 * 編譯報錯:構(gòu)造方法是創(chuàng)建對象使用的,不能讓對象一直創(chuàng)建下去 */ public Demo01DiGui() { //Demo01DiGui(); } /* * 2.在遞歸中雖然有限定條件,但是遞歸次數(shù)不能太多。否則也會發(fā)生棧內(nèi)存溢出。 * 4993 * Exception in thread "main" java.lang.StackOverflowError */ private static void b(int i) { System.out.println(i); //添加一個遞歸結(jié)束的條件,i==5000的時候結(jié)束 if(i==5000){ return;//結(jié)束方法 } b(++i); } /* * 1.遞歸一定要有條件限定,保證遞歸能夠停止下來,否則會發(fā)生棧內(nèi)存溢出。 Exception in thread "main" * java.lang.StackOverflowError */ private static void a() { System.out.println("a方法"); a(); } }
遞歸累加求和
計算1 ~ n的和
分析:num的累和 = num + (num-1)的累和,所以可以把累和的操作定義成一個方法,遞歸調(diào)用。 實現(xiàn)代碼:
public class DiGuiDemo { public static void main(String[] args) { //計算1~num的和,使用遞歸完成 int num = 5; // 調(diào)用求和的方法 int sum = getSum(num); // 輸出結(jié)果 System.out.println(sum); } /* 通過遞歸算法實現(xiàn). 參數(shù)列表:int 返回值類型: int */ public static int getSum(int num) { /* num為1時,方法返回1, 相當(dāng)于是方法的出口,num總有是1的情況 */ if(num == 1){ return 1; } /* num不為1時,方法返回 num +(num-1)的累和 遞歸調(diào)用getSum方法 */ return num + getSum(num-1); } }
代碼執(zhí)行圖解
小貼士:遞歸一定要有條件限定,保證遞歸能夠停止下來,次數(shù)不要太多,否則會發(fā)生棧內(nèi)存溢出。
遞歸求階乘
階乘:所有小于及等于該數(shù)的正整數(shù)的積。
n的階乘:n! = n * (n-1) *...* 3 * 2 * 1
分析:這與累和類似,只不過換成了乘法運算,學(xué)員可以自己練習(xí),需要注意階乘值符合int類型的范圍。
推理得出:n! = n * (n-1)!
代碼實現(xiàn):
public class DiGuiDemo { //計算n的階乘,使用遞歸完成 public static void main(String[] args) { int n = 3; // 調(diào)用求階乘的方法 int value = getValue(n); // 輸出結(jié)果 System.out.println("階乘為:"+ value); } /* 通過遞歸算法實現(xiàn). 參數(shù)列表:int 返回值類型: int */ public static int getValue(int n) { // 1的階乘為1 if (n == 1) { return 1; } /* n不為1時,方法返回 n! = n*(n-1)! 遞歸調(diào)用getValue方法 */ return n * getValue(n - 1); } }
遞歸打印多級目錄
分析:多級目錄的打印,就是當(dāng)目錄的嵌套。遍歷之前,無從知道到底有多少級目錄,所以我們還是要使用遞歸實現(xiàn)。
代碼實現(xiàn):
public class DiGuiDemo2 { public static void main(String[] args) { // 創(chuàng)建File對象 File dir = new File("D:\\aaa"); // 調(diào)用打印目錄方法 printDir(dir); } public static void printDir(File dir) { // 獲取子文件和目錄 File[] files = dir.listFiles(); // 循環(huán)打印 /* 判斷: 當(dāng)是文件時,打印絕對路徑. 當(dāng)是目錄時,繼續(xù)調(diào)用打印目錄的方法,形成遞歸調(diào)用. */ for (File file : files) { // 判斷 if (file.isFile()) { // 是文件,輸出文件絕對路徑 System.out.println("文件名:"+ file.getAbsolutePath()); } else { // 是目錄,輸出目錄絕對路徑 System.out.println("目錄:"+file.getAbsolutePath()); // 繼續(xù)遍歷,調(diào)用printDir,形成遞歸 printDir(file); } } } }
綜合案例
文件搜索
搜索D:\aaa
目錄中的.java
文件。 分析:
- 目錄搜索,無法判斷多少級目錄,所以使用遞歸,遍歷所有目錄。
- 遍歷目錄時,獲取的子文件,通過文件名稱,判斷是否符合條件。
代碼實現(xiàn):
public class DiGuiDemo3 { public static void main(String[] args) { // 創(chuàng)建File對象 File dir = new File("D:\\aaa"); // 調(diào)用打印目錄方法 printDir(dir); } public static void printDir(File dir) { // 獲取子文件和目錄 File[] files = dir.listFiles(); // 循環(huán)打印 for (File file : files) { if (file.isFile()) { // 是文件,判斷文件名并輸出文件絕對路徑 if (file.getName().endsWith(".java")) { System.out.println("文件名:" + file.getAbsolutePath()); } } else { // 是目錄,繼續(xù)遍歷,形成遞歸 printDir(file); } } } }
文件過濾器優(yōu)化
java.io.FileFilter
是一個接口,是File的過濾器。 該接口的對象可以傳遞給File類的listFiles(FileFilter)
作為參數(shù), 接口中只有一個方法。 boolean accept(File pathname)
:測試pathname是否應(yīng)該包含在當(dāng)前File目錄中,符合則返回true。
分析:
1.接口作為參數(shù),需要傳遞子類對象,重寫其中方法。我們選擇匿名內(nèi)部類方式,比較簡單。
2.accept
方法,參數(shù)為File,表示當(dāng)前File下所有的子文件和子目錄。保留住則返回true,過濾掉則返回false。保留規(guī)則:
- 要么是.java文件。
- 要么是目錄,用于繼續(xù)遍歷。
3.通過過濾器的作用,listFiles(FileFilter)
返回的數(shù)組元素中,子文件對象都是符合條件的,可以直接打印。
代碼實現(xiàn):
public class DiGuiDemo4 { public static void main(String[] args) { File dir = new File("D:\\aaa"); printDir2(dir); } public static void printDir2(File dir) { // 匿名內(nèi)部類方式,創(chuàng)建過濾器子類對象 File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.getName().endsWith(".java")||pathname.isDirectory(); } }); // 循環(huán)打印 for (File file : files) { if (file.isFile()) { System.out.println("文件名:" + file.getAbsolutePath()); } else { printDir2(file); } } } }
Lambda優(yōu)化
分析:FileFilter
是只有一個方法的接口,因此可以用lambda表達式簡寫。 lambda格式:
()->{ }
代碼實現(xiàn):
public static void printDir3(File dir) { // lambda的改寫 File[] files = dir.listFiles(f ->{ return f.getName().endsWith(".java") || f.isDirectory(); }); // 循環(huán)打印 for (File file : files) { if (file.isFile()) { System.out.println("文件名:" + file.getAbsolutePath()); } else { printDir3(file); } } }
以上就是一文帶你搞懂Java中的遞歸的詳細內(nèi)容,更多關(guān)于Java遞歸的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring boot+mybatis+thymeleaf 實現(xiàn)登錄注冊增刪改查功能的示例代碼
這篇文章主要介紹了Spring boot+mybatis+thymeleaf 實現(xiàn)登錄注冊增刪改查功能的示例代碼,本文通過實例圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07SpringBoot多環(huán)境切換的配置實現(xiàn)
在日常的開發(fā)中,一般都會分好幾種環(huán)境,本文就來介紹一下SpringBoot多環(huán)境切換的配置實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-03-03java中map和對象互轉(zhuǎn)工具類的實現(xiàn)示例
這篇文章主要介紹了java中map和對象互轉(zhuǎn)工具類的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08SpringBoot編譯target目錄下沒有resource下的文件踩坑記錄
這篇文章主要介紹了SpringBoot編譯target目錄下沒有resource下的文件踩坑記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08Springboot3整合Mybatis-plus3.5.3報錯問題解決
在日常學(xué)習(xí)springboot3相關(guān)的代碼時,在使用 SpringBoot3 整合 MyBatisplus 時出現(xiàn)了一些問題,花了不少時間處理,這篇文章主要介紹了Springboot3整合Mybatis-plus3.5.3報錯問題解決,需要的朋友可以參考下2023-11-11