迷宫求解算法(java版)

迷宫求解算法一直是算法学习的经典,实现自然也是多种多样,包括动态规划,递归等实现,这里我们使用穷举求解,加深对栈的理解和应用。迷宫求解算法可以抽象为图的遍历问题。在图的遍历过程中通常由深度优先遍历(DFS)和广度优先遍历(BFS)两种。此例我们采用深度优先遍历,当然,在不同的情景之下,不同的优先遍历算法执行效率会有很大的差异,需要根据不同的使用环境选用合适的遍历算法。

深度优先遍历

深度优先遍历从某个顶点出发,首先访问这个顶点,然后找出刚访问这个结点的第一个未被访问的邻结点,然后再以此邻结点为顶点,继续找它的下一个新的顶点进行访问,重复此步骤,直到所有结点都被访问完为止。

广度优先遍历

广度优先遍历从某个顶点出发,首先访问这个顶点,然后找出这个结点的所有未被访问的邻接点,访问完后再访问这些结点中第一个邻接点的所有结点,重复此方法,直到所有结点都被访问完为止。

定义Position类用于存储坐标点

起点坐标为(1,1),终点坐标为(8,8)
地图打印在最下面

class Position {
    private int px;
    private int py;
    public Position(int px, int py) {
        this.px = px;
        this.py = py;
    }
    public int getPx() {
        return px;
    }
    public void setPx(int px) {
        this.px = px;
    }
    public int getPy() {
        return py;
    }
    public void setPy(int py) {
        this.py = py;
    }
}

这里我们简单介绍下move()函数

move函数分别向四个方向移动,然后将可行的path入栈.
注意,这里栈元素中每个栈元素Position都是new出来的,栈中存的是reference,
注意看下面这种写法:

currentPosition.setPy(currentPosition.getPy()+1);
stacks.push(currentPosition);

这种写法一度让我陷入困惑,因为pop出来的Position都是一样的,原因大家可能应该明白了。。。

 public void move() {
        if (moveRight()) {
            Position temp = new Position(currentPosition.getPx() + 1, currentPosition.getPy());
            test.add(temp);
            stacks.push(temp);
        } else if (moveBottom()) {
            Position temp = new Position(currentPosition.getPx(), currentPosition.getPy() + 1);
            test.add(temp);
            stacks.push(temp);
        } else if (moveTop()) {
            Position temp = new Position(currentPosition.getPx(), currentPosition.getPy() - 1);
            test.add(temp);
            stacks.push(temp);
        } else if (moveLeft()) {
            Position temp = new Position(currentPosition.getPx() - 1, currentPosition.getPy());
            test.add(temp);
            stacks.push(temp);
        } else {
            currentPosition = stacks.pop();//若当前位置四个方向都走不通,则将当前位置出栈,继续遍历上一节点
        }
    }

整体代码

class Position {
    private int px;
    private int py;
    public Position(int px, int py) {
        this.px = px;
        this.py = py;
    }
    public int getPx() {
        return px;
    }
    public void setPx(int px) {
        this.px = px;
    }
    public int getPy() {
        return py;
    }
    public void setPy(int py) {
        this.py = py;
    }
}
public class Maze {
    private final Position start;//迷宫的起点final
    private final Position end;//迷宫的终点final
    private ArrayList footPrint;//足迹
    private ArrayList test;
    private MyStack stacks;//自定义栈(也可以用java.util中的Stack栈)若想了解MyStack的实现,可以参考我的另一篇博客
    private Position currentPosition;//定义当前位置
    public Maze() {//集合,栈的初始化工作
        start = new Position(1, 1);
        end = new Position(8, 8);
        currentPosition = start;
        stacks = new MyStack<>();
        test = new ArrayList<>();
    }
    public static final int map[][] = //定义地图10*10的方格
            {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 0, 0, 1, 0, 0, 0, 1, 0, 1},
            {1, 0, 0, 1, 0, 0, 0, 1, 0, 1},
            {1, 0, 0, 0, 0, 1, 1, 0, 0, 1},
            {1, 0, 1, 1, 1, 0, 0, 0, 0, 1},
            {1, 0, 0, 0, 1, 0, 0, 0, 0, 1},
            {1, 0, 1, 0, 0, 0, 1, 0, 0, 1},
            {1, 0, 1, 1, 1, 0, 1, 1, 0, 1},
            {1, 1, 0, 0, 0, 0, 0, 0, 0, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
    public static void printMap() {//打印地图
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                if (map[i][j] == 1) System.out.print(" ■");
                else System.out.print("  ");
            }
            System.out.println();
        }
    }
    public boolean moveTop() {//上移
        String s = currentPosition.getPx() + "" + (currentPosition.getPy() - 1);
        if ((map[currentPosition.getPx()][currentPosition.getPy() - 1] != 1) & !isArrived(s)) {
            footPrint.add(s);
            return true;
        }
        return false;
    }
    public boolean moveRight() {//右移
        String s = (currentPosition.getPx() + 1) + "" + currentPosition.getPy();
        if (map[currentPosition.getPx() + 1][currentPosition.getPy()] != 1 & !isArrived(s)) {
            footPrint.add(s);
            return true;
        }
        return false;
    }
    public boolean moveBottom() {//下移
        String s = currentPosition.getPx() + "" + (currentPosition.getPy() + 1);
        if ((map[currentPosition.getPx()][currentPosition.getPy() + 1] != 1) & !isArrived(s)) {
            footPrint.add(s);
            return true;
        }
        return false;
    }
    public boolean moveLeft() {//左移
        String s = (currentPosition.getPx() - 1) + "" + currentPosition.getPy();
        if ((map[currentPosition.getPx() - 1][currentPosition.getPy()] != 1) & !isArrived(s)) {
            footPrint.add(s);
            return true;
        }
        return false;
    }
    public boolean isArrived(String position) {//判断当前位置是否已经到打过
        return footPrint.contains(position);
    }
    public void move() {//move函数分别向四个方向移动,然后将可行的path入栈
        if (moveRight()) {
            Position temp = new Position(currentPosition.getPx() + 1, currentPosition.getPy());
            test.add(temp);
            stacks.push(temp);
        } else if (moveBottom()) {
            Position temp = new Position(currentPosition.getPx(), currentPosition.getPy() + 1);
            test.add(temp);
            stacks.push(temp);
        } else if (moveTop()) {
            Position temp = new Position(currentPosition.getPx(), currentPosition.getPy() - 1);
            test.add(temp);
            stacks.push(temp);
        } else if (moveLeft()) {
            Position temp = new Position(currentPosition.getPx() - 1, currentPosition.getPy());
            test.add(temp);
            stacks.push(temp);
        } else {
            currentPosition = stacks.pop();//若当前位置四个方向都走不通,则将当前位置出栈,继续遍历上一节点
        }
    }
    public static void main(String[] args) {
        Maze m = new Maze();
        m.footPrint = new ArrayList<>();
        m.footPrint.add("11");
        m.stacks.push(m.start);
        while (m.currentPosition.getPx() != 8 || m.currentPosition.getPy() != 8) {
            m.move();
        }
        printMap();
        System.out.println("下面是足迹,长度是:" + m.footPrint.size());
        m.printFootPrint();
    }
    public void printFootPrint() {
        for (int i = 0; i < footPrint.size(); i++) {
            System.out.print(footPrint.get(i) + ",");
        }
        System.out.println();
    }
}
迷宫求解算法(java版)_第1张图片
Paste_Image.png

大家可能会疑惑,为什么足迹是不连续的(例如:21,12)两个位置是走不通的,是因为在path遍历过程中存在跳栈,既当前位置走不通便会将当前位置的Position出栈(stacks.pop),然后继续上一节点遍历。


更新:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

public class Maze {
    private Position startPosition;
    private Position endPosition;
    private HashMap pathMap;

    public Maze() {
        startPosition = new Position(1,1);
        endPosition = new Position(8,8);
        pathMap = new HashMap<>();
    }

    private final int mazeZone[][] = {
            {1,1,1,1,1,1,1,1,1,1},
            {1,0,1,0,0,0,0,1,0,1},
            {1,0,0,0,1,1,0,0,1,1},
            {1,1,1,1,1,0,0,1,0,1},
            {1,0,0,0,0,0,0,0,1,1},
            {1,0,1,1,1,1,0,0,0,1},
            {1,0,0,1,0,1,1,1,1,1},
            {1,0,1,0,0,0,1,0,0,1},
            {1,0,0,0,1,0,0,0,0,1},
            {1,1,1,1,1,1,1,1,1,1}
    };
    private class Position{
        private int indexX;
        private int indexY;
        public Position(int indexX, int indexY) {
            this.indexX = indexX;
            this.indexY = indexY;
        }
        public int getIndexX() {
            return indexX;
        }
        public int getIndexY() {
            return indexY;
        }
        @Override
        public boolean equals(Object obj) {
            if (obj == null)return false;
            Position temp=null;
            if (obj instanceof Position) {
                temp = (Position) obj;
            }else {
                return false;
            }
            if(temp.indexX == this.indexX && temp.indexY == this.indexY)return true;
            else return false;
        }
        @Override
        public int hashCode() {
            return this.indexX*10+indexY;
        }
        @Override
        public String toString() {
            return "["+this.indexX+","+indexY+"]";
        }
    }
    public void printMaze(){
        for (int i = 0;i < mazeZone.length;i++){
            for (int j = 0;j searchQueue=new LinkedBlockingQueue<>();
        HashSet visitedList=new HashSet<>();
        searchQueue.add(startPosition);
        visitedList.add(startPosition);
        while (!searchQueue.isEmpty()){
            Position currentPosition=searchQueue.poll();
            int tempX=currentPosition.getIndexX();
            int tempY=currentPosition.getIndexY();
            if(tempX == endPosition.getIndexX() && tempY == endPosition.getIndexY()){
                System.out.println("search finished! path has been detected!");
                break;
            }
            //test move up
            if(mazeZone[tempX-1][tempY]==0){
                Position p=new Position(tempX-1,tempY);
                if (visitedList.add(p)) {
                    searchQueue.add(p);
                    System.out.println("["+tempX+","+tempY+"]"+"->"+"["+(tempX-1)+","+tempY+"]");
                    pathMap.put(new Integer((tempX-1)*10+tempY),new Integer(tempX*10+tempY));
                }
            }
            //test move down
            if(mazeZone[tempX+1][tempY]==0){
                Position p=new Position(tempX+1,tempY);
                if (visitedList.add(p)) {
                    searchQueue.add(p);
                    System.out.println("["+tempX+","+tempY+"]"+"->"+"["+(tempX+1)+","+tempY+"]");
                    pathMap.put(new Integer((tempX+1)*10+tempY),new Integer(tempX*10+tempY));
                }
            }
            //test move left
            if(mazeZone[tempX][tempY-1]==0){
                Position p=new Position(tempX,tempY-1);
                if (visitedList.add(p)) {
                    searchQueue.add(p);
                    System.out.println("["+tempX+","+tempY+"]"+"->"+"["+tempX+","+(tempY-1)+"]");
                    pathMap.put(new Integer(tempX*10+tempY-1),new Integer(tempX*10+tempY));
                }
            }
            //test move right
            if(mazeZone[tempX][tempY+1]==0){
                Position p=new Position(tempX,tempY+1);
                if (visitedList.add(p)) {
                    searchQueue.add(p);
                    System.out.println("["+tempX+","+tempY+"]"+"->"+"["+tempX+","+(tempY+1)+"]");
                    pathMap.put(new Integer(tempX*10+tempY+1),new Integer(tempX*10+tempY));
                }
            }
        }
        int temp=pathMap.get(88);
        System.out.print(88 + "<-");
        while (temp != 11){
            System.out.print(temp + "<-");
            temp = pathMap.get(temp);
        }
        System.out.print(11);
        System.out.println();
        printMaze();
    }
}

更多关于java的文章请戳这里:(您的留言意见是对我最大的支持)

我的文章列表
Email:[email protected]

你可能感兴趣的:(迷宫求解算法(java版))