-
Notifications
You must be signed in to change notification settings - Fork 88
/
Kruskal.java
138 lines (124 loc) · 4.27 KB
/
Kruskal.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package cn.codepub.algorithms.graph;
import cn.codepub.algorithms.graph.utils.UnionFindSet;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
/**
* <p>
* Created with IntelliJ IDEA. 15/12/16 15:39
* </p>
* <p>
* ClassName:Kruskal
* </p>
* <p>
* Description:使用克鲁斯卡尔算法求最小生成树,该算法的核心是一个不相交集,也就是说若加入当前边不形成回路的话即合法,否则不合法
* 而实现不相交集最常用的方法就是使用并查集,借助于实现的并查集来实现克鲁斯卡尔算法
* </P>
*
* @author Wang Xu
* @version V1.0.0
* @since V1.0.0
*/
public class Kruskal {
private static List<Vertex> vertexList = new ArrayList<>();//顶点集
/**
* 实现一个匿名类,提供了基于边的权值的比较器
*/
public static final Queue<Edge> QUEUE = new PriorityQueue<>((e1, e2) -> {
if (e1.value == e2.value) {
return 0;
} else {
return e1.value > e2.value ? 1 : -1;
}
});
private static List<Edge> visitedEdges = new ArrayList<>();//已访问的边集
private static List<Edge> edgeList = new ArrayList<>();//边集
private static class Vertex {
char name;//顶点名称
public Vertex(char name) {
this.name = name;
}
@Override
public String toString() {
return String.valueOf(name);
}
}
private static class Edge {
Vertex start;//边的起始点
Vertex end;//边的终结点
int value;//边的权值
public Edge(Vertex a, Vertex b, int val) {
this.start = a;
this.end = b;
this.value = val;
}
@Override
public String toString() {
return "顶点是:" + this.start.name + "-->" + this.end.name + ",权值:" + this.value;
}
}
/**
* 添加边的函数
*
* @param a 起始点
* @param b 终结点
* @param val 边的权值
*/
public static void addEdge(Vertex a, Vertex b, int val) {
Edge edge = new Edge(a, b, val);
edgeList.add(edge);
}
public static void minimumSpanningTree() {
UnionFindSet unionFindSet = new UnionFindSet(vertexList.size());
// 加入优先级队列
QUEUE.addAll(edgeList);
// queue.addAll(edgeList.stream().collect(Collectors.toList()));
while (!QUEUE.isEmpty()) {
Edge remove = QUEUE.remove();
Vertex start = remove.start;//获取起始点
Vertex end = remove.end;//获取终结点
int startNo = getVertexNo(vertexList, start.name);//得到起点编号
int endNo = getVertexNo(vertexList, end.name);//得到终点编号
int father1 = unionFindSet.findSet(startNo);
int father2 = unionFindSet.findSet(endNo);
if (father1 != father2) {//说明两棵树不在同一棵子树
unionFindSet.union(startNo, endNo);//合并之
visitedEdges.add(remove);//将当前访问的边加入已访问列表
}
}
}
private static int getVertexNo(List<Vertex> vertexList, char name) {
for (int i = 0; i < vertexList.size(); i++) {
if (vertexList.get(i).name == name) {
return i;
}
}
return -1;
}
@Test
public void create() {
//构造图
Vertex v0 = new Vertex('0');
Vertex v1 = new Vertex('1');
Vertex v2 = new Vertex('2');
Vertex v3 = new Vertex('3');
Vertex v4 = new Vertex('4');
vertexList.add(v0);
vertexList.add(v1);
vertexList.add(v2);
vertexList.add(v3);
vertexList.add(v4);
addEdge(v0, v1, 2);
addEdge(v1, v2, 3);
addEdge(v2, v4, 1);
addEdge(v0, v4, 4);
addEdge(v0, v3, 8);
addEdge(v2, v3, 5);
addEdge(v4, v3, 7);
minimumSpanningTree();
System.out.println("使用克鲁斯卡尔算法选取的边是:");
System.out.println(visitedEdges);
}
}