关于用深度优先算法生成迷宫与寻找路径的一些回忆
当老师教完类这一章,就给我们布置了几个实验,其中一个就是迷宫问题,属于其中最难的一个实验了,这一个实验也折腾我好几个礼拜,然而对于班上的几个大神,这个也就是个小case了,对于菜鸟的我,花了我好几个礼拜,也终于在最近给完成了。
为了生成一个迷宫,当然用数组表示是最好的了,我是基于深度优先算法用栈生成一个迷宫数组,深度优先的基本思想就是把初始点给标记为已访问并入栈,然后寻找该点的邻居节点,如果它的邻居节点没有访问过并且存在,就把邻居节点入栈并标记为已访问,当存在邻居节点时,就一直执行上面的步骤,当不存在未访问的邻居节点时,就出栈一个节点,并以当前栈顶元素继续访问它的未访问过的邻居节点,执行前面相同的步骤。它的终止条件就是栈为空时,也就访问完了所有节点。
为了生成一个迷宫数组,需要注意几点:
-
一是迷宫有墙,这就需要在访问邻居节点时中间的隔一个元素当作墙。
-
二是要随机生成一个方向来访问,这样每次生成的迷宫就不一样了。
-
三是随机访问一个方向时,最好标记该方向已访问过。至于寻找路径也是相同的思想。
下面是主要的代码:
DFS算法生成迷宫:
public class DFSGenerateStrategy implements GenerateMazeStrategy {
private int[][] map;// 地图数组
private int size;// 迷宫尺寸
/**
* 初始化迷宫数组
*/
private void init() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
map[i][j] = BlockStatus.INIT;
}
}
}
@Override
public int[][] generate(int size) {
this.size = size;
map = new int[size][size];
init();
Stack<Point> stack = new Stack<>();// 用于生成迷宫时的栈
Direction direction;
map[1][1] = BlockStatus.OPEN;// 初始点
stack.push(new Point(1, 1));// 将当前点压入栈中
VisitStatus visitStatus = new VisitStatus();// 标记某方向是否走过
int n = 0;// 标记某方向是否有未访问节点
Random rand = new Random();
while (!stack.isEmpty()) {
direction = Direction.valueOf(rand.nextInt(4));
n = 0;
if (direction == Direction.UP) {// up
if (!isVisted(stack.peek().x - 2, stack.peek().y)) {
// 标记该点的邻居节点,打开之间的墙,并把邻居节点压入栈中
map[stack.peek().x - 1][stack.peek().y] = BlockStatus.OPEN;
map[stack.peek().x - 2][stack.peek().y] = BlockStatus.OPEN;
stack.push(new Point(stack.peek().x - 2, stack.peek().y));
n++;
}
visitStatus.up = true;// 标记该方向已走过
} else if (direction == Direction.DOWN) {// down
if (!isVisted(stack.peek().x + 2, stack.peek().y)) {
map[stack.peek().x + 1][stack.peek().y] = BlockStatus.OPEN;
map[stack.peek().x + 2][stack.peek().y] = BlockStatus.OPEN;
stack.push(new Point(stack.peek().x + 2, stack.peek().y));
n++;
}
visitStatus.down = true;
} else if (direction == Direction.LEFT) {// left
if (!isVisted(stack.peek().x, stack.peek().y - 2)) {
map[stack.peek().x][stack.peek().y - 1] = BlockStatus.OPEN;
map[stack.peek().x][stack.peek().y - 2] = BlockStatus.OPEN;
stack.push(new Point(stack.peek().x, stack.peek().y - 2));
n++;
}
visitStatus.left = true;
} else if (direction == Direction.RIGHT) {// right
if (!isVisted(stack.peek().x, stack.peek().y + 2)) {
map[stack.peek().x][stack.peek().y + 1] = BlockStatus.OPEN;
map[stack.peek().x][stack.peek().y + 2] = BlockStatus.OPEN;
stack.push(new Point(stack.peek().x, stack.peek().y + 2));
n++;
}
visitStatus.right = true;
}
if (n == 0) {
if (visitStatus.isAllVisited()) {// 如果四个方向都走过且没有未访问的节点,则退回上一个节点
stack.pop();
visitStatus.reset();
}
} else {
visitStatus.reset();
}
}
return map;
}
// 判断该点是否存在并访问过
private boolean isVisted(int x, int y) {
if ((x > 0 && x < size) && (y > 0 && y < size) && map[x][y] == BlockStatus.INIT) {
return false;
}
return true;
}
}
DFS算法寻找迷宫出口:
public class DFSSearchStrategy implements SearchPathStrategy {
@Override
public Point[] search(int[][] array) {
Stack<Point> stack = new Stack<>();// 用于寻找路径时的栈
stack.push(new Point(1, 1));
array[1][1] = BlockStatus.VISTID;
int size = array.length;
while (!stack.isEmpty() && (stack.peek().x != size - 2 || stack.peek().y != size - 2)) {
if (array[stack.peek().x][stack.peek().y + 1] == BlockStatus.OPEN) { // right
stack.push(new Point(stack.peek().x, stack.peek().y + 1));
array[stack.peek().x][stack.peek().y] = BlockStatus.VISTID;
} else if (array[stack.peek().x + 1][stack.peek().y] == BlockStatus.OPEN) { // down
stack.push(new Point(stack.peek().x + 1, stack.peek().y));
array[stack.peek().x][stack.peek().y] = BlockStatus.VISTID;
} else if (array[stack.peek().x - 1][stack.peek().y] == BlockStatus.OPEN) { // up
stack.push(new Point(stack.peek().x - 1, stack.peek().y));
array[stack.peek().x][stack.peek().y] = BlockStatus.VISTID;
} else if (array[stack.peek().x][stack.peek().y - 1] == BlockStatus.OPEN) { // left
stack.push(new Point(stack.peek().x, stack.peek().y - 1));
array[stack.peek().x][stack.peek().y] = BlockStatus.VISTID;
} else {
array[stack.peek().x][stack.peek().y] = BlockStatus.COMMON;
stack.pop();
}
}
return getPathLocation(stack).toArray(new Point[0]);
}
// 得到路径坐标
private List<Point> getPathLocation(Stack<Point> sw) {
LinkedList<Point> p = new LinkedList<>();// 用于存储路径坐标
while (!sw.isEmpty()) {
p.addFirst(new Point(sw.peek().x, sw.peek().y));
sw.pop();
}
return p;
}
}
完整项目已提交到码云: https://gitee.com/uyong/study.maze
版权声明:本文为博主原创文章,转载请注明原文连接。