最小生成树—Kruskal算法

什么是最小生成树?

首先,最小生成树一定数无向图,并且在不影响所有点都连通的情况下,所有边的权重加起来最小值是多少。

比如说:无向图abcp如下图所示,每条边权重也标记出来了。最小生成树就如右侧所示。

当然,不要1和2的边也可使所有点连通,但不是最小的。

Kruskal算法

用Kruskal生成最小树的思路可总体概括为:贪心算法+并查集 的思路。

考察所有的边,从权重小的边到权重大的边依次考察(贪心),如果当前边不会形成环,就保留当前边,如果会形成环,就不要当前边。

仍然用上面abcp图来举例:

从小到大检查,权重1的边连接AC,不会形成环,保留。

权重2的边连接BC,不会形成环,保留。

权重3的边连接CP,不会形成环,保留。

权重100边连接AB,此时ABC形成了环,不要它,AP边也是如此,形成了最终的最小树。

那该如何检查环呢?此时就用到了并查集。不了解的建议先看下并查集介绍及其原理

代码实现

通过小根堆将Edge的权重排序,小的在堆顶,而后弹出,看边的from和to节点在并查集中是否在一个集合。不在则union,在则说明有环。

java 复制代码
public static class UnionFind {
        HashMap<Node, Integer> sizeMap;
        HashMap<Node, Node> parent;

        public UnionFind() {
            sizeMap = new HashMap<>();
            parent = new HashMap<>();
        }

        public void makeSets(Collection<Node> nodes) {
            sizeMap.clear();
            ;
            parent.clear();

            for (Node cur : nodes) {
                sizeMap.put(cur, 1);
                parent.put(cur, cur);
            }
        }

        public Node findParent(Node cur) {
            Stack<Node> stack = new Stack<>();
            while (cur != parent.get(cur)) {
                stack.add(cur);
                cur = parent.get(cur);
            }

            while (!stack.isEmpty()) {
                parent.put(stack.pop(), cur);
            }
            return cur;
        }

        public boolean isSameSet(Node a, Node b) {
            return findParent(a) == findParent(b);
        }

        public void union(Node a, Node b) {
            if (a == null || b == null) {
                return;
            }
            Node aNode = findParent(a);
            Node bNode = findParent(b);

            if (aNode != bNode) {
                int aSize = sizeMap.get(aNode);
                int bSize = sizeMap.get(bNode);

                if (aSize >= bSize) {
                    parent.put(bNode, aNode);
                    sizeMap.put(aNode, aSize + bSize);
                    sizeMap.remove(bNode);
                } else {
                    parent.put(aNode, bNode);
                    sizeMap.put(aNode, aSize + bSize);
                    sizeMap.remove(aNode);
                }
            }
        }
    }
    
    public static class MyComparator implements Comparator<Edge>{

        @Override
        public int compare(Edge o1, Edge o2) {
            return o1.weight - o2.weight;
        }
    }

    public static Set<Edge> kruskalMST(Graph graph) {
        UnionFind uf = new UnionFind();
        uf.makeSets(graph.nodes.values());
        
        PriorityQueue<Edge> heap = new PriorityQueue(new MyComparator());
        for (Edge edge : graph.edges){
            heap.add(edge);
        }

        Set<Edge> result = new HashSet<>();
        
        while (!heap.isEmpty()){
            Edge edge = heap.poll();
            while (!uf.isSameSet(edge.from,edge.to)){
                uf.union(edge.from,edge.to);
                result.add(edge);
            }
        }
        return result;
    }
相关推荐
风_流沙2 分钟前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
Lenyiin13 分钟前
01.02、判定是否互为字符重排
算法·leetcode
鸽鸽程序猿28 分钟前
【算法】【优选算法】宽搜(BFS)中队列的使用
算法·宽度优先·队列
Jackey_Song_Odd29 分钟前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
ProtonBase31 分钟前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
Watermelo61732 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
乐之者v38 分钟前
leetCode43.字符串相乘
java·数据结构·算法
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
古希腊掌管学习的神2 小时前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
云边有个稻草人2 小时前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法