今天學習了經典的8皇后問題,强化了對遞歸調用的理解,之前自己寫遞歸老是把出口條件理解錯,導致邏輯錯誤,時常抛棧溢出的錯誤.
其實簡單來説遞歸調用,在調用之前,一定要想明白,遞歸出口在哪裏,在調用遞歸的時候,怎麽能讓遞歸的代碼不斷向出口方向靠近,
最終能找到遞歸的出口.這個問題想明白了,遞歸調用也就成功了一半了.
之前在調用遞歸時還發現,遞歸説到底是通過棧進行計算,如果在遞歸裏調用了堆裏的東西,一定不能是new出來的對象.
而且遞歸調用時要盡量把調用遞歸用到的資源放到外面,減少遞歸調用的資源.
舉個簡單例子來説,寫一個輸出重複語句的遞歸方法,代碼本身沒問題,但是如果調用方法次數過多,仍然會抛出棧溢出的錯誤.
用代碼測試過,一個簡單的輸出語句,在我電腦上,用String直接調用遞歸方法,一旦超過6200次就可能抛異常,
用StringBuilder調用遞歸方法,一旦超過12000次也可能抛異常
今天老師講的遞歸實現8皇后的方法確實很經典.占用資源也不多,但老師說,實際上這樣的算法大概得調用14000多次遞歸方法
由此可見,其實遞歸方法代碼占用的資源和代碼本身的複雜程度關係並不大,關鍵還是看代碼怎麽設計的,
怎麽能夠在調用時還能保證不占用過多的計算機資源.
以上就是我本人對於遞歸的一些粗淺的理解.
下面放上我重寫過的遞歸解決8皇后問題的代碼.
1 package com.recursion; 2 3 /* 4 * 遞歸回溯解決8皇后問題 5 * 需求,根據象棋的規則,在棋盤上放置8個皇后,每個皇后的下一步棋不能吃子 6 * 棋盤上放置到第8個皇后時,8個皇后的位置作爲一個正解,算出總共有多少正解 7 * 8 * 遞歸回溯的思路 9 * 將第一個皇后放在第一行第一列,放第二個皇后,看下一步棋是否能吃子, 10 * 不能吃子則放第三個皇后,放置下一個子時,位置可能回溯,發生變化 11 * 放到第8個皇后時開始回溯求解 12 * 得到一個正確解就會退回一個棧,會把棧裏所有的可能性都嘗試一遍, 13 * 退回上一個棧,再次求解,一直回溯到第一個皇后 14 * 15 */ 16 public class EightQueen { 17 //1,共有8個皇后 18 int max = 8; 19 //1,定義存放解法的數組 20 int[] array = new int[max]; 21 //5,定義解法的變量 22 static int count = 0; 23 public static void main(String[] args) { 24 // TODO Auto-generated method stub 25 //1,用一維數組表示棋盤,索引表示行坐標,數值表示列坐標 26 //定義一個將皇后放的位置輸出的方法 27 //4,調用遞歸方法測試 28 EightQueen queen8 = new EightQueen(); 29 queen8.check(0); 30 //5,統計共有多少種解法 31 System.out.printf("一共有%d種解法",count); 32 } 33 34 //3,定義放置皇后的方法,每一次進入check都會循環遞歸,知道得出正解 35 private void check(int n) { 36 //n為8時,方法為正解,遞歸出口 37 if (n == max) { 38 print(); 39 return; 40 } 41 //放置皇后,判斷是否衝突 42 for (int i = 0; i < max; i++) { 43 //把皇后n放到第一列 44 array[n] = i; 45 if (judge(n)) { 46 //如果不冲突,開始放第n+1個皇后,開始遞歸 47 check(n + 1); 48 } 49 //如果衝突,遞歸繼續循環,去下一行 50 } 51 } 52 53 //2,定義查看放置第n個皇后是否滿足放置規則的方法 54 /** 55 * 56 * @param n 表示第n個皇后 57 * @return 58 */ 59 private boolean judge(int n) { 60 for (int i = 0; i < n; i++) { 61 //判斷第n個皇后和第n-1個皇后是否在同一列,n本身在自增運算,不需要判斷行 62 //判斷第n個皇后和第i個皇后是否在同一斜綫 63 if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) { 64 return false; 65 } 66 } 67 return true; 68 } 69 70 //1,定義打印輸出的方法 71 private void print() { 72 count++; 73 for (int i = 0; i < array.length; i++) { 74 System.out.print(array[i] + " "); 75 } 76 System.out.println(); 77 } 78 79 }
代碼不多,卻解決了一個比較複雜的經典計算問題.