什么是递归呢:
简而言之,当你面前有一扇门,你打开面前这扇门,看到屋里面还有一扇门,你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开它。若干次之后,你打开面前的门后,发现只有一间屋子,没有门了。然后,你开始原路返回,每走回一间屋子,你数一次,走到入口的时候,你可以回答出你到底用这你把钥匙打开了几扇门,这就是递归。
现在我们使用迷宫路径求解,进一步理解递归的含义。
需求:
给定任意设定的迷宫,左上角为入口,有下角为出口,判断该迷宫是否存在通路,若有,则非递归求解迷宫的一条通路以及三元组路径,并且递归求解迷宫的所有通路以及对应的三元组路径;若无,则提示该迷宫无路。
以下是类的设计:
以下是非递归求解的流程及主要代码:
/*
非递归求解迷宫一条通路及三元组路径
*/
public class MiGong1 {
private int[][] maze;
private int row, col;
public int[][] getMaze() {
return maze;
}
//定义链式栈
SingleLinkedListStack<Coord1> singleStack;
//进入下一个节点的四个方向,分别是(右、下、左、上)的优先顺序
Coord1[] move = {new Coord1(0, 1), new Coord1(1, 0),
new Coord1(0, -1), new Coord1(-1, 0)};
public MiGong1(int[][] map) {
//创建链式栈
singleStack = new SingleLinkedListStack<>();
//索引按照正常坐标形式
row = map.length + 2;
col = map[0].length + 2;
maze = new int[row][col];
//将迷宫map四周都增加一行0和一列0,得到maze
for (int x = 1; x < row - 1; x++) {
for (int y = 1; y < col - 1; y++) {
maze[x][y] = map[x - 1][y - 1];
}
}
//将四周边缘的0变为1(障碍物)
for (int i = 0; i < maze.length; i++) {
maze[i][0] = 1;
maze[i][maze[0].length - 1] = 1;
}
for (int j = 0; j < maze[0].length; j++) {
maze[0][j] = 1;
maze[maze.length - 1][j] = 1;
}
}
//寻找判断是否有路径
public boolean findPath(int i, int j, int[][] maze, int maxRow, int maxColumn) {
int x, y, dNo, nextX, nextY;//x,y表示当前节点坐标,dNo表示移动方向,nextX,nextY表示下一个节点坐标
Coord1 temp = new Coord1(i, j, null, -1);//创建起点坐标,这里dNo=-1为了适应下面的temp.dNo+1,满足初始情况
singleStack.push(temp);//将入口进栈
//深度优先搜索
while (singleStack.size() != 0) {
temp = singleStack.pop();//三元组出栈
System.out.printf("(%d,%d,%s)出栈\n",temp.x,temp.y,temp.d);
maze[temp.x][temp.y] = 0;//走不通,迷宫矩阵元素恢复为0
//坐标替换
x = temp.x;
y = temp.y;
dNo = temp.dNo + 1;//这里加一,走下一个方向
//当一条路走不通时,下面的while循环结束,后面循环将这条死路的三元组坐标出栈,矩阵元素恢复为0,
//直到可以再次进入下面的while循环,到出口为止
while (dNo < 4) {
nextX = x + move[dNo].x;
nextY = y + move[dNo].y;
if (maze[nextX][nextY] == 0) {//下一个坐标可走
maze[x][y] = 6;//前一个坐标设为6
//看走到下一个坐标是哪个方向
if (dNo == 0) {
temp = new Coord1(x, y, "右", dNo);
} else if (dNo == 1) {
temp = new Coord1(x, y, "下", dNo);
} else if (dNo == 2) {
temp = new Coord1(x, y, "左", dNo);
} else if (dNo == 3) {
temp = new Coord1(x, y, "上", dNo);
}
singleStack.push(temp);//三元组进栈
System.out.printf("(%d,%d,%s)入栈\n", singleStack.peek().x, singleStack.peek().y, singleStack.peek().d);
//坐标替换,进行下一次循环寻路
x = nextX;
y = nextY;
//如果找到通路,将结束循环
if (x == maxRow - 2 && y == maxColumn - 2) {
maze[x][y] = 66;
temp = new Coord1(x, y, "end", -1);
singleStack.push(temp);
return true;//说迷宫有通路
} else {
dNo = 0;//没到出口,继续遍历
}
} else {
dNo++; //使用下一个移动方向
}
}
}
return false;//到不了出口,说明找不到通路
}
}
以下是递归求解的流程及主要代码:
/*
递归求解迷宫所有通路及三元组路径
*/
public class MiGong2 extends MiGong1 {
public MiGong2(int[][] map) {
super(map);
}
public boolean canMove(int x, int y, int nextX, int nextY, int[][] maze, int maxRow, int maxColumn) {
//到达最左边或最右边
if (nextX < 1 || nextY < 1 || nextX > maxRow - 2 || nextY > maxColumn - 2) {
return false;
}
//到墙
if (maze[nextX][nextY] == 1) {
return false;
}
//避免走已经走过的路
if (maze[nextX][nextY] == 6) {
return false;
}
return true;
}
public void findAllPath(int x, int y, int[][] maze, int maxRow, int maxColumn) {
Coord1 temp;
// 递归出口(如果到达右下角)
if (x == maxRow - 2 && y == maxColumn - 2) {
maze[x][y] = 66;//出口为设为66
temp = new Coord1(x, y, "end");
singleStack.push(temp);//将出口push进栈
printPath(maze, maxRow, maxColumn);//输出第i条路径和三元组路径
singleStack.pop();//输出所有路径后要将出口pop出来,以便后面的通路求解
return;
}
//向右走
if (canMove(x, y, x, y + 1, maze, maxRow, maxColumn)) {//如果下一个节点能走,将前一个节点设置为6
maze[x][y] = 6;
temp = new Coord1(x, y, "右");
singleStack.push(temp);
//递归,从下一个节点继续寻路
findAllPath(x, y + 1, maze, maxRow, maxColumn);
//如果路走不通,将恢复原来的样子
singleStack.pop();
maze[x][y] = 0;
}
//向下走
if (canMove(x, y, x + 1, y, maze, maxRow, maxColumn)) {//如果下一个节点能走,将前一个节点设置为6
maze[x][y] = 6;
temp = new Coord1(x, y, "下");
singleStack.push(temp);
//递归,从下一个节点继续寻路
findAllPath(x + 1, y, maze, maxRow, maxColumn);
//如果路走不通,将恢复原来的样子
singleStack.pop();
maze[x][y] = 0;
}
//向左走
if (canMove(x, y, x, y - 1, maze, maxRow, maxColumn)) {//如果下一个节点能走,将前一个节点设置为6
maze[x][y] = 6;
temp = new Coord1(x, y, "左");
singleStack.push(temp);
//递归,从下一个节点继续寻路
findAllPath(x, y - 1, maze, maxRow, maxColumn);
//如果路走不通,将恢复原来的样子
singleStack.pop();
maze[x][y] = 0;
}
//向上走
if (canMove(x, y, x - 1, y, maze, maxRow, maxColumn)) {//如果下一个节点能走,将前一个节点设置为6
maze[x][y] = 6;
temp = new Coord1(x, y, "上");
singleStack.push(temp);
//递归,从下一个节点继续寻路
findAllPath(x - 1, y, maze, maxRow, maxColumn);
//如果路走不通,将恢复原来的样子
singleStack.pop();
maze[x][y] = 0;
}
}
}
一些测试图:
需要完整代码可以去我的资源下载!!!
附链接:
maze_code