前言
本篇文章是韩顺平老师课程P221(第7章:面向对象编程)中有关方法递归调用应用实例1:老鼠出迷宫问题的具体分析。
本篇文章会详细分析每一步解决思路,对应的每步代码构建,最后会放上完整源代码供大家参考,可以作为老韩学Java课程系列笔记的补充,也可以作为想要单独弄清楚迷宫问题的专题文章,希望能够帮助到的大家。
关于方法递归调用的前置知识,欢迎查看我的从零开始学Java(超详细韩顺平老师笔记梳理)06——面向对象编程基础(上):类与对象、成员方法、传参机制、对象克隆、递归(斐波那契、迷宫、汉诺塔、八皇后)笔记。
老鼠迷宫问题:
思路分析:
-
首先我们需要把迷宫这个地图和障碍表示出来(数组是从0开始的,不是从1 开始)
-
这里我们可以使用一个二维数组画出格子图,即8行七列
-
用1表示地图中的障碍,用0表示无障碍可以正常通行
-
通过观察可以知道,第一行和最后一行、第一列和最后一列(红色)全是障碍物,所以可以先通过一个for循环来将这四部分写为1(有障碍)
- 先将第一行和最后一行设置为1
我们将此时的地图打印一下,检测是否符合预期效果:
- 把第一列和最后一列也设置为1
打印一下地图看看:
- 先将第一行和最后一行设置为1
-
除去边框的部分,我们发现在图中坐标为[3][1]、[3][2]的地方也是障碍,这两个障碍我们单独设置一下
打印看一下:
至此地图和障碍部分我们已经实现了。
-
-
接下来要实现老鼠找路的过程
-
我们先把找到终点 (返回true) 和**有障碍、已经走过(返回false)**的情况给写出来
-
而找路的核心代码为:当map[i][j] == 0时,即这个地方没有障碍,之前也没有走过
- 首先我们往下走一步,再递归调用找路方法,如果发现往下走一步,map[i][j] 还是= 0,那么就说明往下走一步是行得通的,返回true
- 按照我们的走路策略(下->右->上->左),按照往下走的相同思路实现完4条路的递归实现:
- 但是如果这四步都没有走通,那说明我们的前提条件map[i][j] == 2(这条路能走通)就不成立,我们直接把这个条件map[i][j]设为3(走过但走不通)
- 至此,我们这个findWay方法就已经写完了,我们需要在main方法中调用该方法 , 把老鼠的初始坐标设置为map[1][1],再次打印出地图,看看路径。
- 首先我们往下走一步,再递归调用找路方法,如果发现往下走一步,map[i][j] 还是= 0,那么就说明往下走一步是行得通的,返回true
-
至此,我们的迷宫问题就已经实现了,大家可以自己更换走路策略,然后再次测试,会得到很多种不同的路径。
完整代码如下:
public class Migong{
public static void main(String[] args) {
//1. 先创建迷宫,用二维数组表示 即int[][] map = new int[8][7]
//2. 我们先规定map数组的元素值,0表示没有障碍,1表示有障碍
int[][] map = new int[8][7];
//第一行和最后一行全是障碍物,全部设置为1
for(int i = 0; i < 7; i++){
//第1行的1、2、3、4...7列格子(即第一行全部)全部设置为1
map[0][i] = 1;
//第8行的1、2、3、4...7列格子(即最后一行全部)全部设置为1
map[7][i] = 1;
}
//第一列和最后一列全是障碍物,全部设置为1
for(int i = 0; i < 8; i++) {
//第1列的1、2、3、4...8行格子(即第一行全部)全部设置为1
map[i][0] = 1;
//第7行的1、2、3、4...8行格子(即最后一行全部)全部设置为1
map[i][6] = 1;
}
map[3][1] = 1;
map[3][2] = 1;
//输出当前地图,用于每一步的测试
System.out.println("======当前地图为======");
for(int i =0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j] + " "); //输出一行
}
System.out.println();
}
//使用findWay给老鼠找路
T t1 = new T();
t1.findWay(map, 1, 1);
System.out.println("\n======找路后的情况如下======");
for(int i =0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
System.out.print(map[i][j] + " "); //输出一行
}
System.out.println();
}
}
}
class T {
//使用递归回溯的思想来解决老鼠出迷宫
/*
1. findWay方法就是专门用来找迷宫的路径
2. 如果找到,就返回true,否则返回false
3. map 就是二维数组,即表示迷宫
4. 老鼠的初始位置为map[1][1]
5. 因为是递归找路,我们规定map数组的各个值的含义:
0--无障碍
1--障碍
2--这个路能走通,我们已经走过了测试过了(插个棋子)
3--走过,但是走不通
6. 当map[6][5]=2时,说明找到通路了,否则就继续找
7. 先确定老鼠找路的策略(这部分可以自己定义)
先往下走,下走不通了就往右走,右走不通就往上走,上走不通就往左走
下->右->上->左
*/
public boolean findWay(int[][] map, int i, int j) {
if(map[6][5] == 2) { //说明已经找到
return true;
} else {
if(map[i][j] == 0) { //说明这个地方没有障碍可以走,但是我们还没有走过
//我们假定可以走通
map[i][j] = 2;
//使用找路策略,来确定该位置是否真的可以走通
//下->右->上->左
if(findWay(map, i + 1, j)){ //i+1就是表示往下走一步
//这里递归调用方法,如果往下走一步还是map[i][j] == 0
//那么这条路可以走通,返回true
return true;
} else if(findWay(map, i, j + 1)) {//j+1就是表示往右走一步
//如果往下走并没有走通,就往右走
return true;
} else if(findWay(map, i - 1, j)) {//i-1就是表示往上走一步
//如果往右走并没有走通,就往上走
return true;
} else if(findWay(map, i, j - 1)) {//j-1就是表示往左走一步
//如果往上走并没有走通,就往左走
return true;
} else {
//但是如果这四步都没有走通
//那说明我们的前提条件map[i][j] == 2(这条路能走通)就不成立
//我们直接把这个条件map[i][j]设为3(走过但走不通)
map[i][j] =3;
return false;
}
} else { //map[i][j] = 1, 2, 3
//1表示有障碍
//2表示已经测试过能走通,走过了
//3表示走过,走不通
return false;
}
}
}
}
总结
本篇文章是韩顺平老师课程P221(第7章:面向对象编程)中有关方法递归调用应用实例1:老鼠出迷宫问题的具体分析。
本篇文章会详细分析每一步解决思路,对应的每步代码构建,最后会放上完整源代码供大家参考,可以作为老韩学Java课程系列笔记的补充,也可以作为想要单独弄清楚迷宫问题的专题文章,希望能够帮助到的大家。
关于方法递归调用的前置知识,欢迎查看我的从零开始学Java(超详细韩顺平老师笔记梳理)06——面向对象编程基础(上):类与对象、成员方法、传参机制、对象克隆、递归(斐波那契、迷宫、汉诺塔、八皇后)笔记。