1. 最小生成树
什么是最小生成树?
1. 图中每个节点要连通
2. 在保证1的前提下边的权重和最小
Kruskal:最小生成树算法之一(从边考虑),要求图为无向图,算法思想:
1. 将图中的边全部移除,只剩点
2. 找到当前权重最小的边添加到图中,检查是否形成环
3. 没有形成环说明可以添加到图中,继续找下一个小边;形成了就不添加到图中,继续找下一条小边
4. 重复2-3直到全部节点连通
2.检查环
如何检查是否形成环?并查集可以实现,这里使用自定义的效率较低。假设图中的节点集为{A,B,C,D}
1. 每个节点形成一个set集合,即{A}、{B}、{C}、{D}
2. 找到权重最小的边,看其from节点和to节点(假如分别为A和B)
3. 将{A}和{B}合并为一个集合{A,B}
4. 找下一个最小的边,看其from节点和to节点(假如分别为B和C)
5. 将{A,B}和{C}合并为一个集合{A,B,C}
6. 找下一个最小的边,看其from节点和to节点(假如分别为A和C)
7. 由于A和C已经在一个集合中,说明添加该边后就会形成环
8. 继续找下一个边直至所有节点都在集合中
3. 代码实现
public class Kruskal {
public static class MySets{
public HashMap<Node, List<Node>> setMap;
public MySets(List<Node> nodes){
for (Node cur : nodes){
List<Node> set = new ArrayList<>();
set.add(cur);
setMap.put(cur, set);
}
}
public boolean isSameSet(Node from, Node to){
List<Node> fromSet = setMap.get(from);
List<Node> toSet = setMap.get(to);
return fromSet == toSet;
}
public void union(Node from, Node to){
List<Node> fromSet = setMap.get(from);
List<Node> toSet = setMap.get(to);
for (Node toNode : toSet){
fromSet.add(toNode);
setMap.put(toNode, fromSet);
}
}
}
public static class EdgeComparator implements Comparator<Edge>{
@Override
public int compare(Edge o1, Edge o2) {
return o1.weight - o2.weight;
}
}
public static Set<Edge> kruskalMST(Graph graph) {
List<Node> values = (List<Node>) graph.nodes.values();
MySets mySets = new MySets(values);
PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
for (Edge edge : graph.edges){
priorityQueue.add(edge);
}
Set<Edge> result = new HashSet<>();
while (!priorityQueue.isEmpty()){
Edge edge = priorityQueue.poll();
if (!mySets.isSameSet(edge.from, edge.to)){
result.add(edge);
mySets.union(edge.from, edge.to);
}
}
return result;
}
}