图的最小生成树Kruskal算法

最小生成树之Prim算法Kruskal算法 最小生成树 定义:无向连通G中,由所有顶点构成且总价值(连接权值和)最低的一棵树(拓扑结构)称为一个最小生成树最小生成树顶点为|V|个,边数为|V|-1,没有圈。 对任一生成树T,如果将中一条不属于T的边添加至T,则会产生一个圈,从该圈中除去任意一条边,则会又恢复成生成树。 下为一示例: 对于上面的无向有权连通,其最小生成树为: 解决最小生成树问题有两种算法Prim算法和... 阅读详情

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;
    }
}
 

Kruskal算法构造最小生成树 Kruskal算法的思想是: 假设联通网T=(V,{E}),则最小生成树的初始状态为只有n个顶点而无边的非连通T=(V,{}),中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点位于不同的连通分量中,则将该边加入T中,否则舍去该边而选择下一条代价最小的边。一次类推,直到T中所有的顶点都在同一个连通分量为止。 以下给出代码: 1、用数组实现,指定的结点数和弧数 #in 阅读详情

相关推荐

大话数据结构学习笔记 - 最小生成树Kruskal算法

大话数据结构学习笔记 - 最小生成树Kruskal算法 Kruskal算法 克鲁斯卡尔(Kruskal)算法,是用来求加权连通最小生成树算法 大话数据结构定义 假设 N=(V,{E})N=(V,{E}) N = (V, \{E\})是连通网,则令最小生成树的初始状态为只有n个顶点而无边的非连通 T={V,{}}T={V,{}} T = \{V, \{\}\}。中每...

hao555sky 2098

详解第三篇:最小生成树Kruskal算法+Prim算法

最小生成树Kruskal算法+Prim算法

m0_70980326的博客 2万+

最小生成树-Kruskal算法

【问题描述】 编写程序,利用带权无向的邻接矩阵存储,实现最小生成树Kruskal算法。 【输入形式】 输入的顶点序列及的边的情况。如样例所示。边的输入以输入-1,-1,-1作为结束。 0,1,6表示对应的顶点及边是:A到B的边权值为6. 【输出形式】 输出最小生成树

AIGC 1231

数据结构——及其C++实现(2)最小生成树Kruskal算法和Prim算法

在上一篇文章中,我们对的基本概念和的存储结构及两种遍历方式做了了解,既然已经认识了,那么对于中的顶点来说,我们思考当面临“用最小代价把所有点连起来”这类问题时,我们该如何做?接下来我们我们引出关于的另一个很重要的概念——最小生成树

学习日记 746

最小生成树:Prim算法Kruskal算法

1. 最小生成树 生成树的定义:如果连通G的一个子是一棵包含G的所有顶点的树,则该子称为G的生成树。 生成树是连通的包含中的所有顶点的极小连通子。它并不唯一,从不同的顶点出发进行遍历,可以得到不同的生成树。 其中,权值最小的树就是最小生成树。 关于最小生成树最经典的应用模型就是城市通信线路网最小造价的问题:网络G表示n个城市之间的通信线路(其中顶点表示城市,边表示两个城市之

jinzhao1993的博客 1万+

算法最小生成树(Kruskal算法)

前面介绍了最小生成树的Prim算法,这个算法是从顶点的角度来刻画生成树的。今天要说的Kruskal(克鲁斯卡尔)算法,是从边的角度来进行刻画的。 Kruskal算法用到的数据结构有: 1、边顶点与权值存储结构(即是由连接某一条边的两个顶点,以及这条边的权值来进行存储,具体看后面的例子) 2、并查集(具体是什么以及作用在后面的例子中解释) Kruskal算法步骤 – 我们今天要实现的目标依然与...

qq_44134712的博客 1274

- 最小生成树算法 - Kruskal - Prim

- 最小生成树算法 - Kruskal(克鲁斯卡尔) - Prim(普利姆)

2302_80023639的博客 865

最小生成树Kruskal算法详解(C语言版)

Kruskal算法(克鲁斯卡尔算法)查找最小生成树的方法是:将连通网中所有的边按照权值大小做升序排序,从权值最小的边开始选择,只要此边不和已选择的边一起构成环路,就可以选择它组成最小生成树。对于 N 个顶点的连通网,挑选出 N-1 条符合条件的边,这些边组成的生成树就是最小生成树

qq_44075108的博客 8034

C++ Kruskal最小生成树算法

权值排序,依次取出,判断闭环 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <fstream> #include <sstream> #include <cassert> #include <vector> #in...

牛~ 291

最小生成树算法: Prim算法Kruskal算法(C++)

本文介绍论中最小生成树算法, 包含Prim算法Kruskal算法. 通过代码和解希望能帮助读者理解.

一些C++相关的技术笔记或者教程. 1301

prim算法_最小生成树Kruskal算法

昨天说了最小生成树的其中一种算法,Prim算法,今天就再来说一下平时用的比较多的另一种最小生成树算法Kruskal(克鲁斯卡尔)算法。然后再来比较一下这两个算法之间的差异。首先回顾一下最小生成树到底是个什么东西。简单说就是在有权连通中,找到一组边,把所有的点连接在一起,并且这组边的权值加和最小,就是这个最小生成树。效果大概如下1,2就是生成树,而3因为边的权值加起来...

weixin_39878716的博客 101

kruskal算法最小生成树c语言,利用Kruskal算法最小生成树.doc

利用Kruskal算法最小生成树利用Kruskal算法最小生成树程序设计 2007-10-09 22:23 阅读160 评论1 字号: 大大 中中 小小 /*利用Kruskal算法最小生成树(2007.8.7)*/#include#include#define MaxVertexNum 12#define MaxEdgeNum 20#define MaxVal...

weixin_39610964的博客 464

算法:通过克鲁斯卡尔(Kruskal)算法,求出最小生成树

之前我给大家分享过用普利姆(Prim)算法来求出最小生成树(点我去看看),今天我再给大家分享一个也是求最小生成树的克鲁斯卡尔(Kruskal)算法 这两个算法都是求最小生成树,有什么区别呢: 1、Prim算法是通过一个点来进行动态扩张,Kruskal是从零开始逐渐加入最小权的边 2、Prim算法是动态规划算法Kruskal是将所有的边都遍历一遍,看哪些是组成最小生成树的边 接下来我们...

weixin_39448458的博客 8999

18 最小生成树Kruskal算法

最小生成树 Kruskal算法

xuqw11111的专栏 137

ds最小生成树_最小生成树的两种方法:Kruskal 算法和 Prim 算法

(给算法爱好者加星标,修炼编程内功)来源:勿在浮砂筑高台https://blog.csdn.net/luoshixian099/article/details/51908175关于的几个概念定义:连通:在无向中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向为连通。强连通:在有向中,若任意两个顶点vivi与vjvj都有路径相通,则称该有向为强连通。连通网:在连...

weixin_39737240的博客 110

C语言实现Kruskal最小生成树算法

Prim算法是以某顶点为起点逐步寻找各顶点上最小权值的边来构建最小生成树的,而Kruskal算法是以边为目标去构建,因为权值在边上,直接去找最小权值的边来构建生成树。 这里换了一种的存储结构,边集数组存储结构。 以下程序在DEV C++下编译运行通过。 #include typedef struct { int begin; int end; int weight; }Edge;

KittyGirl 2853

最小生成树算法:Kruskal算法与Prim算法

最小生成树算法 Kruskal算法 Prim算法 Kruskal算法<\span> struct Node { public: int val; Node * father; Node(int _val) { val = _val; father = this; } }; struct Edge { Node * snode; Node * enode; int weight; Edge(Nod

小飞侠的博客 190
上一篇: 图的拓扑排序
下一篇: 图的最小生成树Prim算法
听风客1
博客等级 码龄3年 912粉丝 155原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值