递归作为一种算法在程序设计语言中广泛运用,是指程序在运行过程中直接或间接调动自身而产生的重入现象。
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
递归一般用于解决三类问题:
- 数据定义按递归定义(斐波那契函数)
- 问题解法按递归实现(回溯)——–(八皇后问题)
- 数据结构形式按递归定义(树的遍历,图的搜索)
规则:
在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,
即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
思路:
1. 构建二维数组,模拟棋盘
chess[r][c]=0表示:r行c列没有皇后,chess[r][c]=1表示:r行c列位置有一个皇后。
2. 从第一行第一列开始逐行摆放皇后
依题意每行只能有一个皇后,遂逐行摆放。
3. 摆放后立即调用一个验证函数(传递整个棋盘的数据),验证合理性
安全则进入下一行摆放下一个,不安全则尝试摆放这一行的下一个位置
1) 当这一行所有位置都无法保证皇后安全时,会退出在本行进的摆放方法,回退到上一行的摆放方法,并且在上一行的下一个位置进行摆放(回溯算法的核心)
当摆放到最后一行,并且调用验证函数确定安全后,输出结果、并累计成功数。
2) 当最后一行8个位置遍历完成后,会退出本行的摆放方法,回退到上一行的摆放方法,并且在上一行的下一个位置进行摆放(回溯算法的核心)
4. 需要扫描当前摆放皇后的 左上,正上,右上 方向是否有其他皇后,有的话存在危险,没有则表示安全,并不需要考虑当前位置棋盘下方的安全性
public class EightQueen { private static int count=0; //结果计数器 public static void main(String[] args) { //初始化棋盘,全部置0 short chess[][]=new short[8][8]; for(int i=0;i<8;i++){ for(int j=0;j<8;j++){ chess[i][j]=0; } } putQueenAtRow(chess,0); System.out.println("计算结果:"+count); } private static void putQueenAtRow(short[][] chess, int row) { /** * 递归终止判断:如果row==8,则说明已经成功摆放了8个皇后 * 输出结果,终止递归 */ if(row==8){ count++; System.out.println("第 "+ count +" 种解:"); for(int i=0;i<8;i++){ for(int j=0;j<8;j++){ System.out.print(chess[i][j]+" "); } System.out.println(); } return; } /** * 向这一行的每一个位置尝试排放皇后 * 然后检测状态,如果安全则继续执行递归函数摆放下一行皇后 */ for(int i=0;i<8;i++){ //摆放这一行的皇后,之前要清掉所有这一行摆放的记录,防止污染棋盘 for(int j=0;j<8;j++){ chess [row][j]=0; } chess [row][i]=1; if( isSafety( chess,row,i ) ){ putQueenAtRow(chess,row+1); } } } private static boolean isSafety(short[][] chess,int row,int col) { //判断中上、左上、右上是否安全 int step=1; while(row-step>=0){ if(chess[row-step][col]==1) //中上 return false; if(col-step>=0 && chess[row-step][col-step]==1) //左上 return false; if(col+step<8 && chess[row-step][col+step]==1) //右上 return false; step++; } return true; } }