一.题意说明
求迷宫问题(见实验4-17)的所有路径。分别使用栈、队列、递归算法等实现(至少三种方法)。要求迷宫地图大小可自定义,障碍物可随机生成。
题意分析:用二维数组定义迷宫大小,确定迷宫方向。迷宫通路为1,不通为0,随机分配0和1,构造迷宫。分别用栈、队列、递归方法求解迷宫路径。采用链表存储迷宫内数据。
二.算法设计与分析
首先确定迷宫的大小,用二维数组构造迷宫,并且规定方向0—3代表上下左右。Path方法存放路径。随机使用0和1填充迷宫,0为不可通过点,1为可通过点。记录好起点和终点。1.栈:用栈格式存储路径,首先判断是否为终点,是就直接输出。不是就循环,判断该点是否来过,来过就退至栈顶,换个方向重来,如果退至栈空则没有符合的路径。2.队列:类似用广度优先遍历算法:当该点没有可走的路的时候,则放入队列,如遇到思路则回退,如遇到终点,则完成迷宫。否则队列空,则表明没有通路。3.递归调用:该算法递归调用自身没有路时,就抛出异常退出循环打印路径。首先判断上下左右有没有终点,进行循环调用自身。如果没有终点,则看上下左右有没有道路,设置数字5代表走过的路径,9代表无相通的路径。如果本次调用所有条件都不满足,说明该方向的道路是死路,该层递归结束返回上一层继续查找其他方向的路。在第一层递归调用中,如果上述条件都不满足。说明迷宫没有出口,则程序正常退出,不会抛出异常。
三. 源码
1)确认迷宫的大小和方向
① public class Path {
public int x, y; //存放横纵坐标
public int direction; //行走的方向,以0-3表示上下左右
public Path(int x, int y, int direction) //存放路径
{
this.x = x;
this.y = y;
this.direction = direction;
}
public Path()
{
this(0, 0, 0);
}
public boolean equals(Object obj)
{
if(super.equals(obj))
return true;
if(obj instanceof Path)
{
if(((Path)obj).x == this.x && ((Path)obj).y == this.y)
return true;
else
return false;
}
else
return false;
}
}
② public class Direction {
private int x;
private int y;
public Direction(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
2)栈
public class CreateLabyrinth {
private Stack<Path> pathstack = new Stack<Path>(); //以栈格式存储Path
public int[][] labyrinth; //以二维数组构造迷宫
public int x, y;
public static double rate0=0.05;
public static double rate1=0.95;
public CreateLabyrinth(int[][] mg)
{
this.labyrinth = mg;
this.x = mg.length;
this.y = mg[0].length;
}
public CreateLabyrinth(int x, int y)
{
CreateLaby(x, y);
}
public void CreateLaby(int x, int y)
{
this.x = x;
this.y = y;
this.labyrinth = new int[x][y];
MathRandom(x, y);
}
public void MathRandom(int x, int y)
{
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
//this.labyrinth[i][j] = (int) (Math.random() * 2); //随机使用0和1填充迷宫,0为不可通过点,1为可通过点
this.labyrinth[i][j]=(int)(Prandom());
}
private int Prandom() {
double randomnumber=Math.random();
if(randomnumber>=0&&randomnumber<=rate0){
return 0;
}else
return 1;
}
public void printAll()
{
for (int i = 0; i < this.x; i++)
{
for (int j = 0; j < this.y; j++)
System.out.print(this.labyrinth[i][j]+" ");
System.out.println();
}
}
public Path pathnext(Path ph, boolean status)
{
if (!status)
ph.direction++;
Path newpath = new Path(ph.x, ph.y, 0);
if (ph.direction == 0)
newpath.y++;
if (ph.direction == 1)
newpath.x++;
if (ph.direction == 2)
newpath.y--;
if (ph.direction == 3)
newpath.x--;
if (newpath.x >= 0 && newpath.x < this.x && newpath.y >= 0 && newpath.y < this.y) {
return newpath;
}
return null;
}
public Path startpath(int x, int y, int direction)
{
Path startpath = new Path(x, y, direction);
this.labyrinth[x][y] = 1;
return startpath;
}
public Path endpath(int x, int y, int direction)
{
Path endpath = new Path(x, y, direction);
this.labyrinth[x][y] = 1;
return endpath;
}
public void move(Path startpath, Path endpath, int direction) //使用栈的算法
{
do{
if(this.labyrinth[startpath.x][startpath.y] == 3) // 判断是否为终点
{
if(startpath.x == endpath.x && startpath.y == endpath.y)
{
pathstack.push(startpath);
System.out.println("(" + startpath.x + "," + startpath.y + ")");
System.out.println("到达终点");
this.pathstack.removeAllElements();
return;
}
System.out.print("(" + startpath.x + "," + startpath.y + ")");
if(pathstack.contains(startpath)) // 判断是否来过
{
pathstack.pop(); // 来过则后退一个,换个方向重来
try
{
startpath = pathstack.peek();
}
catch(EmptyStackException e) //如果退至栈空,则表明没有符合条件的路
{
System.out.println("\n没有找到到达终点的路");
return;
}
startpath = pathnext(startpath, false);
}
else //未来过该点,则入栈
{
pathstack.push(startpath);
startpath = pathnext(startpath, true);
}
}
else
{
try
{
startpath = pathstack.peek();
startpath = pathnext(startpath, false);
}
catch(EmptyStackException e) //如果退至栈空,则表明没有符合条件的路
{
System.out.println("\n没有找到到达终点的路");
return;
}
}
}while (!pathstack.empty());
}
3)队列
public void queuemove(Path startpath, Path endpath) //使用队列
{
x = startpath.x;
y = startpath.y;
Queue<Point> que = new LinkedList<Point>();
int step = 0, flag = 0;
que.offer(new Point(startpath.x, startpath.y));
while(!que.isEmpty())
{
if(step >= 100)
break;
Point p = que.poll();
if(p.x == endpath.x && p.y == endpath.y)
{
System.out.println("成功到达: (" + p.x + ", " + p.y + ")! 本次遍历共走了" + step + "步");
flag = 1;
break;
}
else //类BFS算法,当该点周围有可走的路径时放入队列,若遇到死胡同则回退,若过程中遇到终点,则完成迷宫,否则若队列空,则表示无通路
{
if(x + 1 < this.labyrinth.length && this.labyrinth[x + 1][y] == 1)
{
this.labyrinth[x + 1][y] = 5;
que.offer(new Point(x + 1, y));
x++;
step++;
}
if(y + 1 < this.labyrinth[0].length && this.labyrinth[x][y + 1] == 1)
{
this.labyrinth[x][y + 1] = 5;
que.offer(new Point(x, y + 1));
y++;
step++;
}
if(y - 1 >= 0 && this.labyrinth[x][y - 1] == 1)
{
this.labyrinth[x][y - 1] = 5;
que.offer(new Point(x, y - 1));
y--;
step++;
}
if(x - 1 >= 0 && this.labyrinth[x - 1][y] == 1)
{
this.labyrinth[x - 1][y] = 5;
que.offer(new Point(x - 1, y));
x--;
step++;
}
}
}
if(flag == 0)
System.out.println("没有符合的路径!");
}
4)递归调用
public void loopmove(Path startpath, Path endpath) //递归算法
{
try
{
loopRun(startpath.x, startpath.y, endpath);
System.out.println("该迷宫没有出口!!!"); //如果程序正常退出,说明迷宫没有出口
}
catch(IndexOutOfBoundsException exp)
{
System.out.println("该迷宫没有出口!!!");
}
catch(Exception e) //接收异常,退出循环并打印路径
{
System.out.println();
System.out.println("找到出口! 路径如下(5代表路径):");
for (int i = 0; i < this.labyrinth.length; i++)
{
for(int j = 0; j < this.labyrinth[0].length; j++)
{
System.out.print(this.labyrinth[i][j]);
if(j == this.labyrinth[0].length - 1)
System.out.println();
else
System.out.print(" ");
}
}
}
}
public void loopRun(int x, int y, Path endpath) throws Exception //递归函数
{
this.labyrinth[x][y] = 5;
if(x == endpath.x && y == endpath.y)
{
Exception exp= new Exception();
throw exp; //当找到出口时,抛出一个异常,便于跳出递归循环
}
//判断上下左右有没有终点
if(y - 1 >= 0 && x == endpath.x && y - 1 == endpath.y)
{
loopRun(x, y - 1, endpath);
}
if(x - 1 >= 0 && x - 1 == endpath.x && y == endpath.y)
{
loopRun(x - 1, y, endpath);
}
if(y + 1 < this.labyrinth[0].length && x == endpath.x && y + 1 == endpath.y)
{
loopRun(x, y + 1, endpath);
}
if(x + 1 < this.labyrinth.length && x + 1 == endpath.x && y == endpath.y)
{
loopRun(x + 1, y, endpath);
}
//如果没有终点,则看上下左右有没有道路
if(x + 1 < this.labyrinth.length && this.labyrinth[x + 1][y] == 1)
{
loopRun(x + 1, y, endpath);
}
if(y + 1 < this.labyrinth[0].length && this.labyrinth[x][y + 1] == 1)
{
loopRun(x, y + 1, endpath);
}
if(y - 1 >= 0 && this.labyrinth[x][y - 1] == 1)
{
loopRun(x, y - 1, endpath);
}
if(x - 1 >= 0 && this.labyrinth[x - 1][y] == 1)
{
loopRun(x - 1, y, endpath);
}
this.labyrinth[x][y] = 9;
// 再看上下左右有没有之前走过的路并返回之前走过的路
if(x + 1 < this.labyrinth.length && this.labyrinth[x + 1][y] == 5)
{
loopRun(x + 1, y, endpath);
}
if(y + 1 < this.labyrinth[0].length && this.labyrinth[x][y + 1] == 5)
{
loopRun(x, y + 1, endpath);
}
if(y - 1 >= 0 && this.labyrinth[x][y - 1] == 5)
{
loopRun(x, y - 1, endpath);
}
if(x - 1 >= 0 && this.labyrinth[x + 1][y] == 5)
{
loopRun(x - 1, y, endpath);
}
}
public static void main(String[] args)
{
int map[][]=new int[30][30];
CreateLabyrinth CL= new CreateLabyrinth(map);
CL.CreateLaby(30,30);
CL.startpath(0,0,1);
CL.endpath(29,29,3);
System.out.println("迷宫地图为: ");
CL.printAll();
Path spath = CL.startpath(0, 0, 1);
Path endpath = CL.endpath(29, 29, 3);
//CL.move(spath, endpath,0);
//CL.queuemove(spath, endpath);
CL.loopmove(spath, endpath);
}
}
四。结果
1.随机生成的30*30的迷宫
2.每一步走过的坐标,显示如下
3.图中“5”代表行走的路径: