1. 程式人生 > 實用技巧 >演算法之遞迴

演算法之遞迴

一. 遞迴可以解決哪些問題

  1. 各種數學問題,比如:迷宮問題,八皇后問題,漢諾塔問題,階乘問題等。
  2. 各種演算法中也會用到遞迴,比如:快排,歸併排序,二分查詢,分治演算法等。

二. 遞迴應該遵循的重要規則

  1. 執行一個方法時,就建立一個新的受保護的獨立空間(棧空間)。
  2. 方法中區域性變數是獨立的,不會相互影響。
  3. 如果方法中使用的是引用資料型別(如陣列),就會共享該引用型別的資料。
  4. 遞迴必須向退出遞迴的條件逼近,否則會無限遞迴,出現StackOverflowError.
  5. 當一個方法執行完畢,或者遇到return,就會返回,遵守誰呼叫就將結果返回誰,同時當方法執行完或者返回時,方法也就執行完畢。

三. 迷宮問題

package com.bzw.recursion;

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

        //構建一個8*7的二維陣列表示迷宮
        //其中 “1” 表示牆 ;“0” 表示路
        int[][] map = new int[8][7];
        for (int i=0;i<8;i++){
            for (int j=0;j<7;j++){
                map[i][0] = 1;
                map[i][
6] = 1; map[0][j] = 1; map[7][j] = 1; } } map[3][1] = 1; map[3][2] = 1; // map[2][2] = 1; for (int i=0;i<8;i++){ for (int j=0;j<7;j++){ System.out.print(map[i][j] + " "); } System.out.println(); } System.out.println(
"迷宮路徑為:"); setWay(map,1,1); for (int i=0;i<8;i++){ for (int j=0;j<7;j++){ System.out.print(map[i][j] + " "); } System.out.println(); } } //走迷宮 1表示牆,2表示探測過且可以走,3表示死路 //走迷宮之前得先確定策略:下->右->上->左(策略不唯一,策略與路徑長度有關) public static boolean setWay(int map[][],int i,int j){ if (map[6][5] == 2){ return true; }else{ if (map[i][j] == 0) { map[i][j] = 2; //先假設可以走,設定為2 if (setWay(map, i + 1, j)) { return true; } else if (setWay(map, i, j + 1)) { return true; } else if (setWay(map, i - 1, j)) { return true; } else if (setWay(map, i, j - 1)) { return true; }else { map[i][j] = 3; //如果上下左右都不可以走,設定為3,死路 return false;} }else { return false; } } } }

四. 八皇后問題

package com.bzw.recursion;

public class Queen8 {
    static int max = 8;
    int[] array = new int[max];
    static int count = 0;
    static int judgeCount = 0;
    public static void main(String[] args) {

        Queen8 queen8 = new Queen8();
        queen8.check(0);
        System.out.println("一共有" + count + "種");
        System.out.println("判斷了" + judgeCount + "次");

    }

    private void check(int n){
        if (n == max){  //如果n = max 說明所有皇后已經擺放完畢
            print();
            count++;
            return;
        }
        for (int i=0;i<max;i++){    // i 表示皇后擺放在第幾列
            array[n] = i;
            if (judge(n)){      //如果這裡不滿足擺放條件,皇后的位置向後移一位(在回溯時,皇后位置還會再變化)
                check(n+1);  //當一個皇后擺放完畢再擺放下一個
            }
        }


    }
    /**
     *
     * @param n 表示第幾個皇后
     * @return
     * 雖然8皇后問題是在棋盤上描述的,但這裡用一個一維陣列表示第幾個皇后及對應的位置
     * 即一維陣列的下標表示第幾個皇后(皇后所在的行),對應的陣列值表示皇后在第幾列
     */
    private boolean judge(int n){
        judgeCount++;
        for (int i=0;i<n;i++){
            //皇后不能在同一列,同一斜線上(也不能在同一行,但此演算法必不可能在同一行)
            if (array[i] == array[n] || Math.abs(n-i) == Math.abs(array[n] - array[i])){
                return false;
            }
        }
        return true;
    }

    private void print(){
        for (int i=0;i<array.length;i++){
            System.out.print(array[i] + " ");
        }
        System.out.println();
    }


}

五. 總結

  遞迴這種思想為我們在解決問題時提供了一種思路,有時候也確實能夠比較好的解決問題,同時還有程式碼比較簡潔的優點。但是,有時候雖然能用遞迴解決問題,但遞歸回溯次數太多,時間複雜度較高,並不是最優解。(八皇后問題光判斷就要15720次。)