演算法之遞迴
阿新 • • 發佈:2020-12-07
一. 遞迴可以解決哪些問題
- 各種數學問題,比如:迷宮問題,八皇后問題,漢諾塔問題,階乘問題等。
- 各種演算法中也會用到遞迴,比如:快排,歸併排序,二分查詢,分治演算法等。
二. 遞迴應該遵循的重要規則
- 執行一個方法時,就建立一個新的受保護的獨立空間(棧空間)。
- 方法中區域性變數是獨立的,不會相互影響。
- 如果方法中使用的是引用資料型別(如陣列),就會共享該引用型別的資料。
- 遞迴必須向退出遞迴的條件逼近,否則會無限遞迴,出現StackOverflowError.
- 當一個方法執行完畢,或者遇到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次。)