图的最小生成树Kruskal算法

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.Stack;

public class test37 {
    // 定义节点类
    public static class Node {
        public int value; // 节点的值
        public int in; // 入度
        public int out; // 出度
        public ArrayList<Node> nexts; // 邻接表,存储与该节点相连的其他节点
        public ArrayList<Edge> edges; // 存储从该节点出发的边

        public Node(int value) {
            this.value = value;
            in = 0;
            out = 0;
            nexts = new ArrayList<>();
            edges = new ArrayList<>();
        }
    }

    // 定义边类
    public static class Edge {
        public int weight; // 边的权重
        public Node from; // 起始节点
        public Node to; // 终止节点

        public Edge(int weight, Node from, Node to) {
            this.weight = weight;
            this.from = from;
            this.to = to;
        }
    }

    // 定义图类
    public static class Graph {
        public HashMap<Integer, Node> nodes; // 存储图中的所有节点,键为节点值,值为节点对象
        public HashSet<Edge> edges; // 存储图中的所有边

        public Graph() {
            nodes = new HashMap<>();
            edges = new HashSet<>();
        }
    }

    // 根据给定的矩阵创建图
    public static Graph createGraph(Integer[][] matrix) {
        Graph graph = new Graph();

        for (int i = 0; i < matrix.length; i++) {
            Integer weight = matrix[i][0]; // 边的权重
            Integer from = matrix[i][1]; // 起始节点的值
            Integer to = matrix[i][2]; // 终止节点的值

            // 如果图中不存在起始节点,则添加该节点
            if (!graph.nodes.containsKey(from)) {
                graph.nodes.put(from, new Node(from));
            }
            // 如果图中不存在终止节点,则添加该节点
            if (!graph.nodes.containsKey(to)) {
                graph.nodes.put(to, new Node(to));
            }

            // 获取起始节点和终止节点的对象
            Node fromNode = graph.nodes.get(from);
            Node toNode = graph.nodes.get(to);

            // 创建一条新的边并添加到图中
            Edge newEdge = new Edge(weight, fromNode, toNode);

            // 更新节点的邻接表和度数信息
            fromNode.nexts.add(toNode);
            fromNode.out++;
            toNode.in++;
            fromNode.edges.add(newEdge);
            graph.edges.add(newEdge);
        }
        return graph;
    }

    // 定义并查集类
    public static class UnionFind{
        private HashMap<Node , Node> fatherMap; // 存储每个节点的父节点
        private HashMap<Node ,Integer> sizeMap; // 存储每个集合的大小

        public UnionFind(){
            fatherMap = new HashMap<Node ,Node>();
            sizeMap = new HashMap<Node , Integer>();
        }

        // 初始化并查集,将所有节点作为单独的集合
        public void makeSets(Collection<Node> nodes){
            fatherMap.clear();
            sizeMap.clear();

            for (Node node : nodes){
                fatherMap.put(node , node);
                sizeMap.put(node ,1);
            }
        }

        // 查找节点的根节点,并进行路径压缩优化
        private Node findFather(Node n){
            Stack<Node> path = new Stack<>();
            while (n != fatherMap.get(n)){
                path.add(n);
                n = fatherMap.get(n);
            }
            while (!path.isEmpty()){
                fatherMap.put(path.pop() , n);
            }
            return  n ;
        }

        // 判断两个节点是否属于同一个集合
        public boolean isSameSet(Node a ,Node b){
            return  findFather(a) == findFather(b);
        }

        // 合并两个集合,将较小的集合合并到较大的集合中
        public void union(Node a , Node b){
            if(a == null || b == null){
                return;
            }
            Node aDai = findFather(a);
            Node bDai = findFather(b);

            if(aDai != bDai){
                int aSetSize = sizeMap.get(aDai);
                int bSetSize = sizeMap.get(bDai);
                if(aSetSize <= bSetSize){
                    fatherMap.put(aDai , bDai);
                    sizeMap.put(bDai , aSetSize + bSetSize);
                    sizeMap.remove(aDai);
                }else{
                    fatherMap.put(bDai , aDai);
                    sizeMap.put(aDai , aSetSize + bSetSize);
                    sizeMap.remove(bDai);
                }
            }
        }
    }

    // 定义边的比较器,用于优先队列中的排序操作
    public static class EdgeComparator implements Comparator<Edge>{
        // 根据权值排序,权值小的在左,权值大的在右
        public int compare(Edge o1 , Edge o2){
            return o1.weight - o2.weight;
        }
    }

    // Kruskal算法求最小生成树
    public static Set<Edge> kruskalMST(Graph graph){
        UnionFind unionFind = new UnionFind();
        unionFind.makeSets(graph.nodes.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(!unionFind.isSameSet(edge.from , edge.to)){
                result.add(edge);
                unionFind.union(edge.from , edge.to);
            }
        }

        return result;
    }
}
 

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值