1. 程式人生 > 其它 >Java 初識遞迴

Java 初識遞迴

Java 遞迴

  • 什麼是遞迴
    • 遞迴: 即在成員方法內呼叫自身
  • 遞迴的優點
    • 能用簡潔的程式碼解決複雜的問題
  • 遞迴的缺點
    • 對記憶體的消耗大
  • 遞迴的應用場景
    • 當我們要獲取一個結果,但是這個結果依賴與上一步一樣操作所得到的結果,才能進行運算時,可以使用遞迴
    • 回溯:有多個選擇,但不確定哪個是正確的可以使用遞迴的回溯現象進行逐一嘗試

遞迴的使用

即在成員方法內呼叫自身方法

public class ...... {
    // 例項化物件
    Recursion func = new Recursion();
    // 呼叫 function 方法
    func.function(10);
}

class Recursion {
    public void function (int number) {
        if (number == 1) {
            return;
        }
        System.out.println(number);
    }
}

遞迴的注意事項

  1. 因為JVM會為每個呼叫的方法單獨開闢一個臨時棧,每呼叫一次開闢一個,只要方法不結束,這個棧就會一直存在,所以遞迴的層次不能太多次。
  2. 遞迴一定要有出口,即:退出條件
  3. 遞迴必須擁有最少一個形參

遞迴的經典應用

階乘

public class ...... {
    // 例項化物件
    Recursion object = new Recursion();
    // 呼叫 階層 方法
    object.factorial(10);
}

class Recursion {
    /**
     * @param number 階乘層數
     * @return 階層結果
    */
    public int factorial (int number) {
        if (number == 1) {
            // 當 number = 1 時退出遞迴
            return 1;
        }
        // 利用上一層的結果 來計算
        // factor...(number - 1) * 2
        // factor...(number - 1) * 3
        // factor...(number - 1) * 4......
        return factorial(number - 1) * number;
    }
}

遞迴的回溯現象

回溯也是遞迴的常用方法,如:

  • 當前有n個方案,方案1、方案2、方案3......,我們不確定哪個方案是能解決問題
  • 先嚐試方案1 方案1能通過執行後續程式碼
  • 如不同通過嘗試方案2以此類推

如尋路案例

public class ...... {
    public static void main (String[] args) {

        Map mapObject = new Map();
        int map[][] = mapObject.genMap(8, 7);
        System.out.println("尋路結果如下:\n" + mapObject.findWay(map, 1, 1));
        // 列印尋路結果
        new Arrayss().printArrays(map);

        
    }
}

class Map {
    // 用於記錄出口位置
    int exportX;
    int exportY;
    /**
     * 生成地圖
     * @param row 行
     * @param column 列
     * 0 表示可走 
     * 1 表示障礙物
    */
    public int[][] genMap (int row, int column) {
        int map[][] = new int[row][column];
        // 生成一個四邊圍的地圖
        for (int rows = 0; rows < row; rows++) {
            for (int columns = 0; columns < column; columns++) {
                if (rows == 0 || rows == row - 1 || columns == 0 || columns == column - 1) {
                    map[rows][columns] = 1;
                }
            }
        }
        // 隨機生成1~10個障礙物
        for (int randomCount = 1; randomCount <= (int)(Math.random() * 10) + 1; randomCount++) {
            // 隨機指定可活動行
            int randomRow = (int)(Math.random() * (row - 2)) + 1;
            // 隨機指定可活動列
            int randomColumn = (int)(Math.random() * (column - 2)) + 1;
            // 隨機位置生成障礙物
            map[randomRow][randomColumn] = 1;
        }
        // 記錄隨機出口位置
        exportX = (int)(Math.random() * (column - 2)) + 1;
        exportY = (int)(Math.random() * (row - 2)) + 1;
        map[exportY][exportX] = 2;

        // 列印地圖未尋路前
        new Arrayss().printArrays(map);
        map[exportY][exportX] = 0;
        return map;
    }
    
    /**
     * @param map 地圖
     * @param x 當前位置x座標
     * @param y 當前位置y座標
     * @return boolean 此位置是否可通
    */
    public boolean findWay (int map[][], int x, int y) {
        switch (map[exportY][exportX]) {
        	// 如果 出口位置等於2
        	// 說明程式已經走到出口位置,返回true
            case 2:
                return true;
            // 處理當前位置不為出口位置的情況
            default:
                switch (map[y][x]) {
                    // 當前位置為 0 說明可進行嘗試
                    case 0:
                        // 假定當前位置可從上下左右其中一個走同
                        map[y][x] = 2;
                        // 嘗試向下尋路
                        if (findWay(map, x, y+1)) {
                            return true;
                        }
                        // 嘗試向右尋路
                        else if (findWay(map, x+1, y)) {
                            return true;
                        }
                        // 嘗試向左尋路
                        else if (findWay(map, x-1, y)) {
                            return true;
                        }
                        // 嘗試向上尋路
                        else if (findWay(map, x, y-1)) {
                            return true;
                        }
                        // 如果四個方向都不通
                        else {
                            // 將當前位置記錄為 3 並返回false
                            map[y][x] = 3;
                            return false;
                        }
                    default:
                        // 當前位置不為 0 說明是死路返回false並退出
                        return false;
                }
        }
    }
}

class Arrayss {
    public void printArrays (int array[][]) {
        for (int twoDimensional = 0; twoDimensional < array.length; twoDimensional++) {
            for (int index = 0; index < array[twoDimensional].length; index++) {
                System.out.print(array[twoDimensional][index] + " ");
            }
            System.out.println();
        }
    }
}