遞歸回溯解決8皇后問題

今天學習了經典的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 }

代碼不多,卻解決了一個比較複雜的經典計算問題.

猜你喜欢

转载自www.cnblogs.com/zzzzzpaul/p/11588020.html
今日推荐