递归的概念:
递归能够做解决什么问题?
使用递归时需要注意的问题:
递归的第一个应用:迷宫回溯问题
迷宫模拟:
定义一个8×7的数组模拟迷宫:
1表示围墙,0表示可以走的路
图中左上红圈为起点,右下红圈为终点
利用代码找到从起点到终点的路径
使用递归回溯找寻路
说明
1.定义map 表示地图
2.定义i,j,表示从地图的哪个位置开始出发
3.如果能到map[6][5]位置,则说明通路找到
4.约定:当map[i][j] 为 0 表示该点没有走过,当为1表示墙,2表示通路可以走,3表示该点已经走过,但是走不通
5.在走迷宫时,需要确定一个策略(方法)下 -> 右 -> 上 -> 左,如果该点走不通,则开始回溯
/**
*
* @param map 表示地图
* @param i 从哪个位置开始找
* @param j
* @return 如果找到位置,就返回true,否则返回false
*/
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;// 假定该点是可以走通的
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;
return false;
}
}else {
//如果该点不为0,为1、2、3,就返回false,(为什么有2:如果从2继续找路,可能会进入死循环)
//不再自我调用,开始回溯
return false;
}
}
}
递归的第二个应用:八皇后问题
八皇后问题介绍
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。(92种)
思路分析:
使用递归解决八皇后问题的完整代码(可直接复制运行):
public class Queen8 {
// 定义一个max表示共有多少个皇后
int max = 8;
// 定义数组array,保存皇后放置位置的结果,比如arr = {0,4,7,5,2,6,1,3}
int[] array = new int[max];
static int count = 0;//用来计数
public static void main(String[] args) {
Queen8 queen8 = new Queen8();
queen8.check(0);
System.out.printf("一共有%d种解法",count);
}
// 核心方法
// 查看当我们放置 第 n 个皇后、就去检测该皇后是否和前面已经摆放的皇后冲突
// 使用递归,每一次递归都有一个for循环,因此会有回溯
private void check(int n) {
if (n == max) {// n = 8,其实已经放好皇后了,因为从0开始
print();// 开始回溯的起点,直接打印
return;
}
for (int i = 0; i < max; i++) {
//先把当前这个皇后 n ,放到该行的第 1 列
array[n] = i;
//判断当放置第 n 个皇后到 i 列,是否冲突
if(judg(n)) {//不冲突
//接着开始放n+1个皇后,即开始递归
check(n+1);
}
//如果有冲突,不要紧,进入循环
}
}
/**
*
* @param n 表示第 n 个皇后
* @return
*/
private boolean judg(int n) {
for (int i = 0; i < n; i++) {
// 下标表示行,值表示列
// array[i] == array[n] -> 值相等 -> 列相等
// Math.abs(i-n)->下标之差-> 行之间的差距
// Math.abs(array[i]-array[n])->值之间的差->列之间的差距
// Math.abs(i-n) == Math.abs(array[i]-array[n]) ->
// 行之间的差距和列之间的差距相等,构成等腰直角三角形,即在斜线上
if (array[i] == array[n] || Math.abs(i - n) == Math.abs(array[i] - array[n]))
return false;
}
return true;
}
// 将结果输出
private void print() {
count++;
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
}