不相交类集算法生成迷宫并求解路径
2017-12-07 16:50
429 查看
这两天看了不相交类集算法,十分高效于是写了一个迷宫生成的算法,事实证明该算法效率极高;但求解路径遇到了瓶颈,楼主这里用邻接表的方式寻找路径,用栈存储路径信息。该程序存在一个小问题:pain()函数闪烁的导致多次计算;而且路径求解的算法效率不高,本人菜鸟一枚,希望路过的大神予以指点。
这里为100x100的结果展示,耗时最多5s。200x200的迷宫大致需要20s左右。
public final class DisJoinSet { private int[] eleRoots; public DisJoinSet(int num){ this.eleRoots = new int[num]; for(int i=0;i<num;i++){ getEleRoots()[i] = -1; } } public int find(int ele){ if(getEleRoots()[ele] < 0){ return ele; } return find(getEleRoots()[ele]); } public void union(int root1,int root2){ //让深度较小的树成为深度较大的树的子树 if(getEleRoots()[root1] > getEleRoots()[root2]){ getEleRoots()[root1] = root2; }else{ if(getEleRoots()[root1] == getEleRoots()[root2]){//深度一样,则更新深度 getEleRoots()[root1]--; } getEleRoots()[root2] = root1; } } public int[] getEleRoots() { return eleRoots; } }
import javax.swing.*; import java.awt.*; import java.util.*; import java.util.List; /** * Created by 伟大的华仔 on 2017-11-30. */ public class Maze extends JFrame { private int row;//行数 private int col; //列数 private DisJoinSet disjSet; private int winHeight=1000;// 行高 private int winWidth=1000;//行宽 public Maze(int row,int col){ this.row = row; this.col = col; this.setTitle("迷宫");//设置标题 this.setSize(winWidth,winHeight);//设置组件大小 this.setVisible(true);//显示或隐藏此 Window this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置用户在此窗体上发起 "close" 时默认执行的操作 EXIT_ON_CLOSE(在 JFrame 中定义):使用 System exit 方法退出应用程序 } public static void main(String[] args) { /** * 定义迷宫的大小,必须是正方形的 * */ int rowCount = 100; int colCount = 100; Maze maze = new Maze(rowCount,colCount); } @Override public void paint(Graphics g){ super.paint(g); /** * 申请一个String集合,放置合并的节点 * */ List<Integer>DisList = new ArrayList<>(); //背景为白色 g.setColor(Color.white); g.fillRect(0, 0, winWidth, winHeight);//窗口填充矩形 g.setColor(Color.black); final int extraWidth = 20; final int cellWidth = (winWidth-2*extraWidth)/row;//定义每个格子的宽度 final int cellHeight = (winHeight-4*extraWidth)/col;//定义每个格子的高度 for(int i=0;i<row;i++) { for(int j=0;j<col;j++) { //初始化m*n矩阵格子 g.drawRect(i*cellWidth+extraWidth,j*cellHeight+2*extraWidth, cellWidth, cellHeight); } } int lastPos = getLastElePos();//迷宫最后一个格式的代表数字 //起点,终点特殊处理 g.setColor(Color.red); g.fillRect(extraWidth, 2*extraWidth, cellWidth, cellHeight); g.fillRect((lastPos% row)*cellWidth + extraWidth,(lastPos/ row)*cellHeight + 2*extraWidth, cellWidth, cellHeight); this.setDisjSet(new DisJoinSet(row*col)); // 路径记录操作 long start = System.currentTimeMillis(); ArrayList<LinkedList<Integer>> adjoinTable = new ArrayList(); LinkedList[] arrayFuck = new LinkedList[row*col]; for (int i = 0;i<row*col;i++){ LinkedList<Integer> temp = new LinkedList<Integer>(); temp.add(i); arrayFuck[i] = temp; temp.clear(); } Stack<Integer> pathSearch = new Stack<Integer>(); pathSearch.push(0); // for (int i = 0;i<row*col;i++){ // LinkedList<Integer> temp = new LinkedList<Integer>(); // temp.add(i); // adjoinTable.add(temp); // temp.clear(); // } long end1 = System.currentTimeMillis(); System.out.println("构建数据消耗:"+(end1-start)+"ms"); g.setColor(Color.white); //用后景色擦色 while(disjSet.find(0) != disjSet.find(lastPos)){//如果起点和终点还没在同一个等价类 /* * 在迷宫内随机挖一个点,再找到该点周围一点,使这两个点落在同一个等价类 */ Random random = new Random(); int randPos = random.nextInt(lastPos+1);//+1是为了能随机到最后一位 int rowIndex = randPos % row; int colIndex = randPos / col; List<Integer> neighborPos = getNeighborNums(rowIndex, colIndex) ; int randNeighbor = neighborPos.get(random.nextInt(neighborPos.size())); if(disjSet.find(randPos) == disjSet.find(randNeighbor)){//两点在同一个等价类 continue; }else{ int aRoot = disjSet.find(randPos); int bRoot = disjSet.find(randNeighbor); disjSet.union(aRoot, bRoot); DisList.add(randPos); DisList.add(randNeighbor); // /** // * 打印搜索过程 // * */ // System.out.println("***过程分析*****************"+Arrays.toString(this.disjSet.getEleRoots())); int maxNum = Math.max(randPos, randNeighbor);//取得较大点 int x1=0,y1=0,x2=0,y2=0; if(Math.abs(randPos-randNeighbor) == 1){//说明在同一行,用竖线隔开 x1= x2=(maxNum% row)*cellWidth + extraWidth; y1=(maxNum/ row)*cellHeight + 2*extraWidth; y2=y1+cellHeight; }else{//说明在同一列,用横线隔开 y1=y2=(maxNum/ row)*cellHeight + 2*extraWidth; x1=(maxNum% row)*cellWidth + extraWidth; x2=x1+cellWidth; } g.drawLine(x1, y1, x2, y2); } } long end2 = System.currentTimeMillis(); System.out.println("画线和记录数据数据消耗:"+(end2-end1)+"ms"); /** * 打印数组 * */ // System.out.println("***最终结构********************"+Arrays.toString(this.disjSet.getEleRoots())); // for (Iterator it = DisList.iterator();it.hasNext();){ // System.out.println("***节点***"+it.next()); // } for (int i = 0;i<DisList.size();i=i+2){ Integer j = DisList.get(i); Integer k = DisList.get(i+1); arrayFuck[j].addLast(k); arrayFuck[k].addLast(j); // adjoinTable.get(j).addLast(k); // adjoinTable.get(k).addLast(j); } // for (int i = 0;i<adjoinTable.size();i++){ // System.out.println("链表内容"+Arrays.toString(adjoinTable.get(i).toArray())); // } long end3 = System.currentTimeMillis(); System.out.println("构建邻接表消耗:"+(end3-end2)+"ms"); /** * 算法步骤 * 1、检索i节点的联通节点 * 2、存在就放入栈中(前提为栈中没有该元素),不存在弹出栈顶元素(删除邻接表中的数据),或者为终点元素结束 * 3、重复步骤1 * */ while (true){//while开始 // System.out.println("******栈中内容:"+Arrays.toString(pathSearch.toArray())); if (pathSearch.isEmpty()){ System.out.println("栈为空,迷宫没有路径"); break; } if (pathSearch.peek()==(row*col-1)){ System.out.println("迷宫已破解"); break; } //adjoinTable.get(pathSearch.peek()).size()==1 && pathSearch.peek() != 0 if (arrayFuck[pathSearch.peek()].size() == 1 && pathSearch.peek() != 0){ Integer temp = pathSearch.pop(); if(pathSearch.isEmpty()){ System.out.println("栈为空,迷宫没有路径"); break; }else { // adjoinTable.get(pathSearch.peek()).remove(temp); // adjoinTable.get(temp).remove(pathSearch.peek()); arrayFuck[pathSearch.peek()].remove(temp); arrayFuck[temp].remove(pathSearch.peek()); } }else { // pathSearch.search(adjoinTable.get(pathSearch.peek()).get(0))!= -1 if (pathSearch.search(arrayFuck[pathSearch.peek()].get(0))!= -1 ){ if (arrayFuck[pathSearch.peek()].size()>1){ // pathSearch.push(adjoinTable.get(pathSearch.peek()).get(1)); Iterator<Integer> boy = arrayFuck[pathSearch.peek()].listIterator(); while (boy.hasNext()){ int girl = boy.next(); if (!pathSearch.contains(girl)){ pathSearch.push(girl); } } } }else { Integer arrayMenber = Integer.parseInt(arrayFuck[pathSearch.peek()].get(0).toString()); pathSearch.push(arrayMenber); } } }//while结束 long end4 = System.currentTimeMillis(); System.out.println("遍历路径表消耗:"+(end4-end3)+"ms"); /** * 输出路径 * */ // System.out.println("迷宫路径"+Arrays.toString(pathSearch.toArray())); g.setColor(Color.BLUE); while (!pathSearch.isEmpty()){ int boy = pathSearch.pop(); //左右 g.fillOval((boy% row)*cellWidth + cellWidth/4+extraWidth,(boy/ row)*cellHeight + cellHeight/4+2*extraWidth, cellWidth/2, cellHeight/2); } long end5 = System.currentTimeMillis(); System.out.println("画路径消耗:"+(end5-end4)+"ms"); long end = System.currentTimeMillis(); System.out.println("时间流程:"+Long.toString(end-start)+"ms"); adjoinTable.clear(); pathSearch.clear(); } /** * 取得目标坐标点周围四个有效点 */ public List<Integer> getNeighborNums(int rowIndex,int colIndex){ List<Integer> neighborPos = new ArrayList<Integer>(4); //右元素 if(isPointInMaze(rowIndex+1,colIndex)){ neighborPos.add(getCoordinateNum(rowIndex+1,colIndex)); } //下元素 if(isPointInMaze(rowIndex,colIndex+1)){ neighborPos.add(getCoordinateNum(rowIndex,colIndex+1)); } //左元素 if(isPointInMaze(rowIndex-1,colIndex)){ neighborPos.add(getCoordinateNum(rowIndex-1,colIndex)); } //上元素 if(isPointInMaze(rowIndex,colIndex-1)){ neighborPos.add(getCoordinateNum(rowIndex,colIndex-1)); } return neighborPos; } public int getLastElePos(){ return row*col-1; } public DisJoinSet getDisjSet() { return disjSet; } public void setDisjSet(DisJoinSet disjSet) { this.disjSet = disjSet; } /** * 根据坐标返回对应的值 * 例如在4*3矩阵,(0,0)返回0;(3,2)返回10 */ public int getCoordinateNum(int x,int y){ return y*col + x; } /** * 判断给定坐标是否在迷宫矩阵内 */ public boolean isPointInMaze(int x,int y){ if(x < 0 || y < 0) return false; return x < row && y <col; } }
这里为100x100的结果展示,耗时最多5s。200x200的迷宫大致需要20s左右。
相关文章推荐
- 【算法题集锦之三】--迷宫的随机生成和路径搜索
- 用并查集(find-union)实现迷宫算法以及最短路径求解
- 回溯算法经典应用:迷宫求解
- 小算法系列-迷宫最短路径
- 迷宫最短路径求解(BFS)
- 算法:求解AOE网的关键路径
- 本人目前最短的迷宫生成算法程序源代码
- 栈的应用:利用顺序栈求解迷宫问题(改编自严蔚敏算法)
- [转载]不太规则的迷宫生成算法1
- 蓝桥杯 算法提高 学霸的迷宫(简单bfs+记录路径)
- 迷宫求解最优路径
- 利用非循环顺序队列采用广度搜索法求解迷宫问题(一条路径)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 算法求解:MxN迷宫问题
- 基于递归分割的迷宫生成算法与自动寻路
- 无向图的最短路径求解算法之——Dijkstra算法【转】
- 迷宫最短路径求解
- 求解最小生成树的算法 kruskal算法(附模板)