关于用深度优先算法生成迷宫与寻找路径的一些回忆

当老师教完类这一章,就给我们布置了几个实验,其中一个就是迷宫问题,属于其中最难的一个实验了,这一个实验也折腾我好几个礼拜,然而对于班上的几个大神,这个也就是个小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

版权声明:本文为博主原创文章,转载请注明原文连接。

posted @ 2014-04-18 20:40  剑舞星魂  阅读(1694)  评论(5编辑  收藏  举报