1. 程式人生 > 實用技巧 >Java基礎(二十二) 遞迴

Java基礎(二十二) 遞迴

遞迴

  概述

  • 遞迴:指的是當前方法呼叫自己的現象。
  • 遞迴的分類:
        • 遞迴分為兩類:直接遞迴和間接遞迴
        • 直接遞迴:成為方法自身呼叫自己的情況
        • 間接遞迴:可以歸結為:方法A呼叫了方法B,方法B呼叫了方法C,方法C返回來又呼叫了方法A。

   注意事項:

      • 遞迴一定要有邊界條件(條件限定),保證遞迴能夠停止下來,否則會發生棧記憶體溢位。
      • 在遞迴當中雖然有限定條件,但是遞迴的次數也不能太多,否則也會發生棧記憶體異常現象。
      • 構造方法禁止遞迴。

使用遞迴實現累計求和

  計算1~n之間的和

  分析:1+2+3+...+n---->n + (n-1) + (n - 2) + ...+1的累加和,遞迴呼叫。

  程式碼示例:

1 public static void main(String[] args) {  
2         int sum = sum(10);
3         System.out.println(sum);
4     }
 /*
        定義一個方法,使用遞迴操作
        1 + 2 + 3+ 4 +...+n
        n+(n-1)+(n-2)+(n-3)+…+1
        已知:
            最大值:n
            最小值:1
            使用遞迴必須明確:
                    1.遞迴的結束條件
                    2.遞迴的目的:獲取下一個被加的數字(n-1)
    
*/ public static int sum(int n){ if(n == 1){ return 1; } //獲取下一個被加的數字 return n + sum(n-1); //return n == 1 ? 1 : sum(n-1) + n; 使用三目運算子更方便 }

備註:使用遞迴當中,main方法呼叫sum方法,sum方法會一直呼叫sum方法,導致在記憶體當中出現了很多個sum方法(頻繁地建立方法、呼叫方法、銷燬方法)效率非常低下,最好的方式就是for迴圈。

遞迴求階乘

  階乘:所有小於及等於該數的正整數的乘積。

  n的階乘:n! = n * (n-1) * (n-2) * (n-3) * ... * 3 * 2 * 1

程式碼示例:

1 public  static  int producr(int n){
2 
3         if( n == 1){
4            return 1;  
5         }
6         return producr(n-1) * n;
7 }        

使用遞迴列印多級目錄

   程式碼示例:

 1  public static void main(String[] args) {
 2         // 找到Hello檔案的路徑
 3         File file = new File("C:\\Users\\admin\\Desktop\\Hello");
 4         //呼叫getAllFiles()
 5         getAllFiles(file);
 6     }
 7 
 8     /*
 9         定義一個方法,引數傳遞File型別的目錄
10         方法中要對目錄進行遍歷
11      */
12     public static void getAllFiles(File file) {
13         // 表明file此時是一個目錄
14         System.out.println(file);
15         //首先先獲取到它直接子目錄和直接子檔案
16         File[] files = file.listFiles();
17         // 遍歷files目錄
18        if (files != null) {
19             for (File f : files) {
20                 //判斷如果得到的f是一個目錄的,需要再次遍歷
21                 if (f.isDirectory()) {
22                     //表明f是一個目錄,則繼續遍歷這個目錄
23                     //getAllFiles方法就是獲取所有的檔案,引數傳遞的剛好是目錄,所以直接呼叫
24                     //getAllFiles目錄
25                     System.out.println(f);
26                     getAllFiles(f);
27                 } else {
28                     System.out.println(f);
29                 }
30             } 
31         }
32     }

綜合案例

  檔案搜尋

  搜尋:C:\Users\admin\Desktop\Hello目錄中的所有的.txt檔案

  分析:

    1.目錄搜尋,無法判斷有多少級目錄,所以使用遞迴,遍歷所有的目錄

    2.遍歷目錄的時候,獲取的是所有的子檔案,通過檔案的名稱來進行診斷,判斷是否符合給定的條件.txt

程式碼實現:

 1 public static void main(String[] args) {
 2         //構建一個File物件得到C:\Users\admin\Desktop\Hello路徑
 3         File file = new File("C:\\Users\\admin\\Desktop\\Hello");
 4         getAllTxt(file);
 5 
 6     }
 7     /*
 8         定義一個方法,遍歷所有的.txt檔案
 9         方法中依然需要傳遞引數目錄 
10      */ 
11     public static  void getAllTxt(File dir){
12         File[] files = dir.listFiles();
13         //遍歷files
14         if(files != null){
15             for (File f : files) {
16                 //判斷f是否是一個目錄
17                 if(f.isDirectory()){
18                     getAllTxt(f);
19                 }else {
20                     //先獲取檔案的名稱
21                     //再次判斷名稱是否以.txt結尾
22                     //鏈式程式設計
23                     if(f.getName().toLowerCase().endsWith(".txt")){
24                         System.out.println(f);
25                     }
26                 }
27             }
28         }
29     }

檔案過濾器優化

    java.io.FileFilter是一個介面,是File的過濾器,該介面的物件可以傳遞給File類的ListFiles(FileFilter)作為引數,介面當中只有一個方法:

   boolean accept(File pathname):測試pathname是否應該包含在當前的File目錄中,如果符合返回true

示例程式碼:

 1  public static void main(String[] args) {
 2         //構建一個File物件得到C:\Users\admin\Desktop\Hello路徑
 3         File file = new File("C:\\Users\\admin\\Desktop\\Hello");
 4         getAllTxt(file);
 5     }
 6     /*
 7         定義一個方法,遍歷所有的.txt檔案
 8         方法中依然需要傳引數目錄
 9      */
10     public static void getAllTxt(File dir) {
11         //System.out.println(dir);
12         //File[] files = dir.listFiles();
13         File[] files = dir.listFiles(new FileFilterImpl());
14         //遍歷files
15         for (File f : files) {
16             // 判斷f是否是一個目錄
17             if (f.isDirectory()) {
18                 getAllTxt(f);
19             } else {
20                 // 先獲取檔案的名稱
21                 System.out.println(f);
22             }
23         }
24     }
25 // 實現類中的程式碼
26  @Override
27 public boolean accept(File pathname) {
28     if (pathname.isDirectory()) {
29         return true;
30     }
31     return pathname.getName()
32         .toLowerCase()
33         .endsWith(".txt");
34 }

Lambda優化

  示例程式碼:

1  //FilenameFilter介面
2 File[] files = dir.listFiles((d,name)  -> new File(d,name).isDirectory() || name.toLowerCase().endsWith(".txt"));
3 //FileFilter介面
4 File[] files = dir.listFiles(pathname ->pathname.getName().toLowerCase().endsWith(".txt") || pathname.isDirectory());