您的位置:首页 > 其它

不相交类集算法生成迷宫并求解路径

2017-12-07 16:50 429 查看
这两天看了不相交类集算法,十分高效于是写了一个迷宫生成的算法,事实证明该算法效率极高;但求解路径遇到了瓶颈,楼主这里用邻接表的方式寻找路径,用栈存储路径信息。该程序存在一个小问题:pain()函数闪烁的导致多次计算;而且路径求解的算法效率不高,本人菜鸟一枚,希望路过的大神予以指点。

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左右。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: