# 并查集应用——生成随机迷宫

在读《数据结构与算法分析Java语言描述一书中》，在并查集章节的最后，作者给出了一个并查集的应用：生成随机迷宫

public class Item {

//元素所在索引
private Integer index;

//元素宽度
private Integer width;

//元素高度
private Integer height;

//是否显示
private Boolean display;

//背景颜色
private String color;

//css样式，供页面显示
private String style;

//根据各属性生成style
public String generateStyle(){
StringBuilder sb = new StringBuilder();
sb.append("width:").append(width).append("px;");
sb.append("height:").append(height).append("px;");
sb.append("background-color: ").append(color).append(";");
if(!display){
sb.append("visibility:hidden");
}

this.style = sb.toString();
return this.style;
}

/**
* 方格类
*/
public class Square extends Item {

// 上级方块的index, 并查集操作用
private Integer value;

public Square(){
//并查集操作前，初始化为-1
this.value = -1;
}

public Integer getValue() {
return value;
}

public void setValue(Integer value) {
this.value = value;
}
}

/**
* 墙壁类
*/
public class Wall extends Item {

//墙壁分隔的方格所在的index
private Integer squareIndex;

//墙壁分隔的另一个方格所在的index
private Integer anotherSquareIndex;

public Integer getSquareIndex() {
return squareIndex;
}

public void setSquareIndex(Integer squareIndex) {
this.squareIndex = squareIndex;
}

public Integer getAnotherSquareIndex() {
return anotherSquareIndex;
}

public void setAnotherSquareIndex(Integer anotherSquareIndex) {
this.anotherSquareIndex = anotherSquareIndex;
}
}

    //墙壁列表(只包括墙壁)
private List<Wall> walls = new ArrayList<>();
//item列表(包括方块和墙壁)
private List<Item> items = new ArrayList<>();
//方块总行数
final int rowCnt = config.getRowCnt();
//方块总列数
final int colCnt = config.getColCnt();
//方块边长
final int edgeLen = config.getEdgeLen();
//总行数(包括墙壁)
final int totalRowCnt = 2 * config.getRowCnt() - 1;
//总列数(包括墙壁)
final int totalColCnt = 2 * config.getColCnt() - 1;
//起点位置下标
final int startIndex = (config.getStartRow() * 2) * totalColCnt + config.getStartCol() * 2;
//终点位置下标
final int endIndex = (config.getEndRow() * 2) * totalColCnt + config.getEndCol() * 2;

int count = 0;
for(int i=0;i<totalRowCnt;i++){
if(i%2 == 0){
//方块和墙壁混合区域
for(int j = 0;j < totalColCnt;j++){
if(j%2==0){
//如果是方块
Square square = new Square();
square.setHeight(edgeLen);
square.setWidth(edgeLen);
square.setColor("black");
square.setIndex(count++);
} else {
Wall wall = new Wall();
wall.setHeight(edgeLen);
wall.setWidth(1);
wall.setColor("red");
wall.setIndex(count++);
wall.setSquareIndex(wall.getIndex() - 1);
wall.setAnotherSquareIndex(wall.getIndex() + 1);
}
}
}else{
//只是墙壁
for(int j=0;j<totalColCnt;j++){
Wall wall = new Wall();
wall.setHeight(1);
wall.setWidth(j%2==0?edgeLen:1);
wall.setColor("red");
wall.setIndex(count++);
wall.setSquareIndex(wall.getIndex() - totalColCnt);
wall.setAnotherSquareIndex(wall.getIndex() + totalColCnt);
if(j%2==0){
}
}
}
}


1.随机选取一面墙，并查看墙壁两边的方格是否连通。
2.如果不连通，拆掉这面墙。
3.如果连通，检查起点和终点是否连通，如果不连通则重复第一步，如果连通则循环结束。

//并查集生成迷宫
while(true){
Random random = new Random();
int i = random.nextInt(walls.size());

Wall wall = walls.get(i);
Integer wallIndex = wall.getSquareIndex();
Integer otherWallIndex = wall.getAnotherSquareIndex();

int i1 = find(wallIndex);
int i2 = find(otherWallIndex);
if(i1 == i2){
int i3 = find(startIndex);
int i4 = find(endIndex);
if(i3 == i4){
break;
}
} else {
wall.setDisplay(false);
union(i1, i2);
walls.remove(wall);
Vertex vertex1 = vMap.get(wallIndex);
Vertex vertex2 = vMap.get(otherWallIndex);
}
}

//*****************
//**disjoint sets**
//*****************
//查找
private int find(int x){
Square square = (Square)items.get(x);

if (square.getValue() < 0) {
return x;
} else {
//普通查找
//            return find(square.getValue(), items);
//路径压缩查找
square.setValue(find(square.getValue()));
return square.getValue();
}
}

//合并
private void union(int root1, int root2) {
// 普通求并
//		s[root2] = root1;
//        items.get(root2).setValue(root1);

//        //按高度求并
Square square2 = (Square)items.get(root2);
Square square1 = (Square)items.get(root1);

if (square2.getValue() < square1.getValue()) {
square1.setValue(root2);
} else {
if (square1.getValue().intValue() == square2.getValue().intValue()) {
square1.setValue(square1.getValue() - 1);
}

square2.setValue(root1);
}
}



// 生成最终样式
List<List<String>> uiStyles = new ArrayList<>();
List<String> uiStyle = null;
for(int i=0;i<items.size();i++){
if(i % totalColCnt == 0){
uiStyle = new ArrayList<>();
}

}

return uiStyles;


@GetMapping("execute")
public ModelAndView execute(Map<String, Object> map){
Config config = new Config.Builder().rowCnt(21).colCnt(41).build();

RandomLabyrinth randomLabyrinth = new RandomLabyrinth();
List<List<String>> lists = randomLabyrinth.generateLabyrinth(config);

map.put("itemlist", lists);
return new ModelAndView("labyrinth");
}


Config类里面包含一些可配置的参数

//总行数
private int rowCnt;
//总列数
private int colCnt;
//方块边长
private int edgeLen;
//起点所在行
private int startRow;
//起点所在列
private int startCol;
//终点所在行
private int endRow;
//终点所在列
private int endCol;


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<meta charset="UTF-8">
<title>random labyrinth</title>
<tr th:each="items,itemsStat:${itemlist}"> <td th:each="item,itemStat:${items}" th:style="\${item}">