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