不了解并查集的可以看我之前写的: 👇https://blog.csdn.net/Smartbbbb/article/details/123623055?spm=1001.2014.3001.5501
/**
* 最小生成树(保持树的连通性,保证权值最小)
*
* K算法:
* 思路: 将所有边按照权值排序,从最低权值的边开始,判断边两边的节点
* 是否在同一集合,不在union,在,放弃这条边 ... 直到遍历结束,使用
* 并查集解决,最终连成一片,因为并查集解决的就是连通性的问题!
*
* 使用并查集处理时核心方法是getParent,它是判定是否为同集合的关键
* 有些节点的父节点并不一样但是同属于一个集合,所以需要往上迭代,所以
* 又做了扁平化处理(使用栈)
*
* 数据结构选择: HashMap,Set,PriorityQueue
*
* 注: 对于无向图时,那就少一条边,只要边两边节点已经是一个集合,那么就不要了
*/
public class Kruskal {
public static void main(String[] args) {
int[][] matrix = {
{5, 1, 5},
{10, 4, 1},
{12, 6, 1},
{7, 6, 5},
{8, 8, 6},
{1, 5, 8},
{40, 8, 4},
{3, 4, 6}
};
Graph graph = GraphGenerate.generate(matrix);
Set<Edge> edges = kruskal(graph);
System.out.println(edges);
}
//求最小生成树,返回结果为最小权值边集合
public static Set<Edge> kruskal(Graph graph){
PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
priorityQueue.addAll(graph.edges);
UnionSet unionSet = new UnionSet();
unionSet.initMap(graph.nodes.values());//初始化
Set<Edge> result = new HashSet<>();
while (!priorityQueue.isEmpty()){
Edge cur = priorityQueue.poll();
Node from = cur.from;
Node to = cur.to;
if(!unionSet.isSameSet(from,to)){
unionSet.union(from,to);
result.add(cur);
}
}
return result;
}
private static class EdgeComparator implements Comparator<Edge>{
@Override
public int compare(Edge o1, Edge o2) {
return o1.weight - o2.weight;
}
}
private static class UnionSet{
public HashMap<Node,Node> parents;
public HashMap<Node,Integer> sizeMap;
public UnionSet() {
this.parents = new HashMap<>();
this.sizeMap = new HashMap<>();
}
public void initMap(Collection<Node> nodes){
this.parents.clear();
this.sizeMap.clear();
for (Node node : nodes) {
this.parents.put(node,node);
this.sizeMap.put(node,1);
}
}
//判断是否属于同一集合
public boolean isSameSet(Node left,Node right){
if(left == null || right == null){
return false;
}
return getFather(left) == getFather(right);
}
//合并不同集合的元素
public void union(Node left,Node right){
if(left == null || right == null){
return;
}
Node lf = getFather(left);
Node rf = getFather(right);
if(lf != null && rf != null){
if(lf != rf){
int lsize = sizeMap.get(lf);
int rsize = sizeMap.get(rf);
Node big = lsize < rsize ? rf : lf;
Node small = big == rf ? lf : rf;
parents.put(small,big);
sizeMap.put(big,lsize + rsize);
sizeMap.remove(small);
}
}
}
//获取节点所在集合的集合代表
private Node getFather(Node node){
if(node == null){
return null;
}
Stack<Node> stack = new Stack<>();
Node cur = node;
while (cur != parents.get(cur)){
stack.push(cur);
cur = parents.get(cur);
}
//扁平化处理形成的并查集树
while (!stack.isEmpty()){
parents.put(stack.pop(),cur);
}
return cur;
}
}
}
左肾算法学习