本文用八皇后问题分析递归的运行过程
请先看题目以及代码,最核心的地方就在于递归,下面将给出递归的过程。
八皇后:
8*8的方格中放8个皇后,八个皇后不能再同一行同一列和同一条对角线反对角线上。
注意:
1.这个代码没有用回溯思想(也就是不断往回找出所有的八皇后的解),只能输出一个八皇后的解。
2.只用了一个一维数组储存列号,并没有出现二维数组,实际上没有用到棋盘
3.check方法检验位置是否合法要看懂,下面有详细注释
4.递归那里,自己设置一个断点去追踪过程,看了过程就懂了,注意递归的时候如果8列走完了还没有合适的位置他就会跳回上一行去更改上一行的皇后放置的位置。
/*算法思想:
* 8*8的方格从每一行开始向下填,建一个一维数组,代表每一行,数组里存的内容是每一行皇后所在的列号(行列号均是从0到7)
* 方法:一个check检查是否同列,同对角线,同反对角线。一个search递归寻找八皇后的位置。一个paint打印结果
*/
public class bahuanghou{
public static void main(String[] args) {
// TODO 自动生成的方法存根
bahuanghou queen= new bahuanghou(); //new一个八皇后的对象
queen.search(0); //调用方法开始递归
paint(); //打印八皇后
}
public static final int SIZE = 8;
private static int[] queens=new int[SIZE]; //queens代表行,数组内存放每一行的列号
private boolean check(int row ,int column) {
for(int i=1;i<=row;i++) //检查第row行的列号是否重复,对角线反对角线上是否有其他元素
//已知queens[row]=column, 三种皇后不能放置的情况数学表达式意义:
//1.距row行i个单位的行的列号为column,也就是上面的竖线,2.row行以前i个单位的行列号也比row前i个单位,即左上的对角线。3.row行以后i个单位的行,列号比row后i个单位,也就是右上对角线
if(queens[row-i]==column||queens[row-i]==column-i||queens[row-i]==i+column)
return false;
return true;
}
private boolean search(int row) {
if(row==SIZE) //填满8行后就退出了
return true;
for(int column = 0;column<SIZE;column++) {
//没填满8行,就继续填。每一行从第0列开始尝试,检查是否符合条件,不符合就下一列。
//走满了8列之后还是没有合适的位置,就会return false, 之后再返回到上一行的column,循环上一行column,把上一行的皇后移动位置继续递归.....继续循环,一行填好了就下一行
queens[row]=column;
if(check(row,column)&&search(row+1))
{
return true;
}
}
return false;
}
public static void paint() {
char[][] x= new char[SIZE][SIZE];
for(int i=0;i<SIZE;i++)
{
System.out.print(queens[i]+" ");
for(int j=0;j<SIZE;j++)
{
System.out.print("|");
if(queens[i]==j)
System.out.print("Q");
else
System.out.print("-");
}
System.out.print("|");
System.out.print("\n");
}
}
}
输出结果:
This is my first colorful code snippet in CSDN .
运行过程描述:
程序从main开始执行
新建一个八皇后对象
对象调用search方法,初始化的row=0
检验row!=7,
进入循环,column=0开始
第一行row=0,在column=0,调用check方法检验
第一行不进入check循环直接满足条件check(row,column)为真
在检验&&之后的search(row+1)时,又回到search(int row)方法
第二行row=1与第一行类似,填到了column=2
row=2 column=4
row=3 column=1
row=4 column=3;
前几行都可以找到满足条件的column直到填到第六行row=5时:
Column从0循环到7都没有找到满足条件的,这时候,row开始往前退;
循环又回到了第五行,之前的row=4的column=3,现在回到第五行从column=3开始循环
继续向后找合适的column;
row=4 找到一个新位置为column=7,递归来到row=5,column从0循环到7
发现还是没有满足条件的column;
于是又回到row=4,此时它的column=7,向后循环就跳出去了,进入到row=3;
之前的row=3,column=1,从这里开始循环,得到满足条件的column=6,进入row=4;
row=4,循环column=1,满足条件,进入row=5
row=5循环 column=3满足条件
.
.
.
.
.
.
递归到最后row=7,search(row+1)即row(8),满足SIZE=8退出search
然后调用paint方法,新建一个8*8的二维数组作为棋盘,用两个for遍历这个二维数组,当行号等于row[i] 列号column[j] 等于x[i][j]的时候就输出一个Q表示皇后,其他的输出-表示空。
(我理解递归为一个不断向后推进的过程,但该过程可以在某些条件下返回前面去,且之前的状态系统还记得。记得之前的状态这一点就是在写程序的时候用循环难以实现的,也是递归的优势之一。)