Kruskal算法解析及Java代码实现(附图)

本文详细介绍了克鲁斯卡尔算法在求解最小生成树问题中的应用,通过实例解析了算法的基本思想和具体步骤,展示了如何从加权连通图中找到权值总和最小的生成树。

最小生成树

       在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树。

example:

例如,对于如上图G4所示的连通网可以有多棵权值总和不相同的生成树。

 

克鲁斯卡尔(Kruskal)算法

克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法,基于连续的按照最小边的策略进行生成树的构建。Kruskal算法开始的时候把每个顶点都当做棵树,这样就是个森林,然后选取最小的边进行树的连接,最后生成只含有一棵树。

基本思想:将图的存储结构使用边集数组的形式表示,并将边集数组按权值从小到大排序,遍历边集数组,每次选取一条边并判断是否构成环路,不会构成环路则将其加入最小生成树,最终只会包含n-1条边(n为无向图的顶点数)。


具体做法

  1. 每次选取最小的边来构成生成树
  2. 将这条边加入后不能形成闭环

 

伪代码:

图解:

第1步:将边<E,F>加入R中。 
边<E,F>的权值最小,因此将它加入到最小生成树结果R中。 
第2步:将边<C,D>加入R中。 
上一步操作之后,边<C,D>的权值最小,因此将它加入到最小生成树结果R中。 
第3步:将边<D,E>加入R中。 
上一步操作之后,边<D,E>的权值最小,因此将它加入到最小生成树结果R中。 
第4步:将边<B,F>加入R中。 
上一步操作之后,边<C,E>的权值最小,但<C,E>会和已有的边构成回路;因此,跳过边<C,E>。同理,跳过边<C,F>。将边<B,F>加入到最小生成树结果R中。 
第5步:将边<E,G>加入R中。 
上一步操作之后,边<E,G>的权值最小,因此将它加入到最小生成树结果R中。 
第6步:将边<A,B>加入R中。 
上一步操作之后,边<F,G>的权值最小,但<F,G>会和已有的边构成回路;因此,跳过边<F,G>。同理,跳过边<B,C>。将边<A,B>加入到最小生成树结果R中。

此时,最小生成树构造完成!它包括的边依次是:<E,F> <C,D> <D,E> <B,F> <E,G> <A,B>

 

package kruskal;

import java.util.ArrayList;
import java.util.List;

public class Kruskal {
	 
    /** 邻接矩阵, 为二维数组, 也称地图 */
    private int[][] matrix;
    /** 设置最大权重范围, 表示正无穷 */
    private int MAX_WEIGHT = Integer.MAX_VALUE;
    /** 边集数组, 采用List接口的实现类ArrayList(数组线性表), 遍历元素和随机访问元素的效率比较高 */
    private List<Edge> edgeList = new ArrayList<Edge>();
 
    /**
     * 创建地图
     */
    private void createGraph(int index) {  //index表示顶点个数
        matrix = new int[index][index];    //邻接矩阵是一个长宽相等的正方形矩阵
        //邻接矩阵中每一行的数组, 按照原图以此填充
        int[] v0 = { 0, 10, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 11, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT };
        int[] v1 = { 10, 0, 18, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 16, MAX_WEIGHT, 12 };
        int[] v2 = { MAX_WEIGHT, 18, 0, 22, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 8 };
        int[] v3 = { MAX_WEIGHT, MAX_WEIGHT, 22, 0, 20, MAX_WEIGHT, MAX_WEIGHT, 16, 21 };
        int[] v4 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 20, 0, 26, MAX_WEIGHT, 7, MAX_WEIGHT };
        int[] v5 = { 11, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 26, 0, 17, MAX_WEIGHT, MAX_WEIGHT };
        int[] v6 = { MAX_WEIGHT, 16, MAX_WEIGHT, 24, MAX_WEIGHT, 17, 0, 19, MAX_WEIGHT };
        int[] v7 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 16, 7, MAX_WEIGHT, 19, 0, MAX_WEIGHT };
        int[] v8 = { MAX_WEIGHT, 12, 8, 21, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 0 };
        matrix[0] = v0;
        matrix[1] = v1;
        matrix[2] = v2;
        matrix[3] = v3;
        matrix[4] = v4;
        matrix[5] = v5;
        matrix[6] = v6;
        matrix[7] = v7;
        matrix[8] = v8;
    }
    
    /**
     * 创建边集数组,并且对他们按权值从小到大排序(顺序存储结构也可以认为是数组吧)
     */
    public void createEdges() {
    	//调用带参构造,此处三个参数分别为begin,end,weight
        Edge v0 = new Edge(4, 7, 7);
        Edge v1 = new Edge(2, 8, 8);
        Edge v2 = new Edge(0, 1, 10);
        Edge v3 = new Edge(0, 5, 11);
        Edge v4 = new Edge(1, 8, 12);
        Edge v5 = new Edge(3, 7, 16);
        Edge v6 = new Edge(1, 6, 16);
        Edge v7 = new Edge(5, 6, 17);
        Edge v8 = new Edge(1, 2, 18);
        Edge v9 = new Edge(6, 7, 19);
        Edge v10 = new Edge(3, 4, 20);
        Edge v11 = new Edge(3, 8, 21);
        Edge v12 = new Edge(2, 3, 22);
        Edge v13 = new Edge(3, 6, 24);
        Edge v14 = new Edge(4, 5, 26);
        
        //同时加入边集数组中(数组线性表)
        edgeList.add(v0);
        edgeList.add(v1);
        edgeList.add(v2);
        edgeList.add(v3);
        edgeList.add(v4);
        edgeList.add(v5);
        edgeList.add(v6);
        edgeList.add(v7);
        edgeList.add(v8);
        edgeList.add(v9);
        edgeList.add(v10);
        edgeList.add(v11);
        edgeList.add(v12);
        edgeList.add(v13);
        edgeList.add(v14);
    }
 
    /**
     * 克鲁斯卡尔算法
     */
    public void kruskal() {
        //创建图和边集数组, 该图有v0-v8共9个顶点s
        createGraph(9);
        //可以由图转出边集数组并按权从小到大排序,这里为了方便观察直接写出来了
        createEdges();
        
        //定义一个数组用来判断边与边是否形成环路(并查集知识)
        int[] parent = new int[9];
        
        /** 权值总和, 是判断最小生成树的重要依据 , 初始化为0 */
        int sum = 0;
        
        int n, m;
        
        //遍历得到每一条边
        for (int i = 0; i < edgeList.size(); i++) {
            Edge edge= edgeList.get(i);
            n = find(parent, edge.getBegin());  
            m = find(parent, edge.getEnd());    
            
            //如果 m == n 说明形成了环路或者两个结点都在一棵树上
            //反之,如果 n和m 不等则说明没有闭合线路
            if (n != m) {
                parent[n] = m;   // 设置n在"已有的最小生成树"中的终点为m(就是把n合并在m所在的连通分量中)
                System.out.println("(" + edge.getBegin() + "," + edge.getEnd() + ")" +edge.getWeight());
                
                sum += edge.getWeight();  //加上对应边的权重,更新sum值
            }
        }
        
        System.out.println("权值总和为:" + sum);
    }
 
    public int find(int[] parent, int index) {
        while (parent[index] > 0) {
        	//parent[0] = 1表示顶点0,1已经加入生成树中
            index = parent[index];
        }
        return index;
    }
 
    public static void main(String[] args) {
        Kruskal graph = new Kruskal();
        graph.kruskal();
    }
 
}
package kruskal;

/**
 * 克鲁斯卡尔->最小生成树边实体
 * @author Administrator
 *
 */
class Edge {
 
    private int begin;   //边的起点
    private int end;     //边的终点
    private int weight;  //边的权重
 
    public Edge(int begin, int end, int weight) {  //带参构造
        super();
        this.begin = begin;
        this.end = end;
        this.weight = weight;
    }
 
    public int getBegin() {
        return begin;
    }
 
    public void setBegin(int begin) {
        this.begin = begin;
    }
 
    public int getEnd() {
        return end;
    }
 
    public void setEnd(int end) {
        this.end = end;
    }
 
    public int getWeight() {
        return weight;
    }
 
    public void setWeight(int weight) {
        this.weight = weight;
    }
 
    @Override
    public String toString() {
        return "Edge [begin=" + begin + ", end=" + end + ", weight=" + weight + "]";
    }
 
}

代码中所用的图数据如下:

运行结果:

内容概要:本文围绕基于Boost MPPT与双PI闭环双向DC-DC的离网光伏储能系统展开,系统性地研究了其动力学建模与稳态特性分析,并通过Simulink平台实现了完整的仿真验证。研究构建了涵盖光伏阵列、最大功率点跟踪(MPPT)控制、双向DC-DC变换器及储能电池的整体系统架构,采用Boost电路实现高效MPPT控制,并引入电压-电流双闭环PI控制策略,实现对储能系统精确的充放电管理。文章深入分析了系统在光照强度与环境温度双重扰动下的动态响应与稳态性能,验证了所提出模型的准确性与控制策略在不同工况下的鲁棒性与有效性,为离网光伏储能系统的优化设计与工程应用提供了坚实的理论基础和仿真依据。; 适合人群:具备电力电子技术、新能源系统或自动控制理论等相关专业知识背景,从事光伏储能系统、微电网或可再生能源领域研究与仿真的研究生、科研人员及工程技术人员。; 使用场景及目标:① 掌握离网光伏储能系统的完整建模方法与关键参数设计流程;② 深入理解Boost电路MPPT控制与双向DC-DC变换器双PI闭环控制的协同工作机制与实现细节;③ 通过Simulink仿真分析系统在光照突变、温度变化等动态扰动下的稳态特性、电压稳定性和能量管理性能;④ 为实际离网系统的控制器设计、参数整定及性能优化提供可靠的理论指导和仿真验证手段。; 阅读建议:建议结合提供的Simulink仿真模型同步学习,重点关注MPPT算法实现逻辑、双PI控制器的参数整定方法以及系统在不同环境条件和负载变化下的响应特性,可在此基础上进一步探索多目标优化控制或智能控制策略的应用。
内容概要:本文围绕基于虚拟阻抗与统一有源阻尼的三相并网逆变器在SVPWM和SPWM两种调制策略下的仿真研究展开,系统阐述了其在Simulink环境中的建模过程与控制策略实现。研究重点包括逆变器的主电路结构设计、调制方式的原理与实现、虚拟阻抗的引入方法及其对系统稳定性的影响机制,以及统一有源阻尼技术在抑制LC滤波器谐振方面的关键作用。通过构建完整的闭环控制系统,结合仿真对比不同调制策略下系统的动态响应、稳态精度及抗干扰能力,验证所提出控制策略在提升并网电能质量与系统鲁棒性方面的有效性。; 适合人群:具备电力电子技术、自动控制理论及新能源并网系统基础知识,熟悉MATLAB/Simulink仿真平台的操作,正在从事相关领域科研或工程开发的专业技术人员,尤其适用于电气工程、自动化等专业的研究生、高校研究人员及从事逆变器控制算法设计的工程师。; 使用场景及目标:①用于三相并网逆变器高性能控制系统的研发与性能优化;②深入理解虚拟阻抗与统一有源阻尼在抑制电网谐振、增强并网稳定性中的作用机理;③对比分析SVPWM与SPWM调制策略在实际控制系统中的动态响应速度、谐波抑制能力和实现复杂度差异;④为相关科研项目、毕业设计或工程实践提供可复现的仿真模型与技术支持。; 阅读建议:建议读者结合提供的Simulink仿真模型进行同步学习,重点关注电流内环与电压外环的双闭环控制结构、坐标变换模块、调制信号生成以及阻尼控制环节的参数设计与整定方法,同时可延伸学习弱电网条件下逆变器的阻抗建模与稳定性判据,以深化对并网系统交互特性的理解。
内容概要:软著助手是一款面向开发者与企业的软件著作权申请辅助工具,专注解决软著申请过程中源程序鉴别材料与文档鉴别材料的整理难题。用户只需提供 GitHub 或 Gitee 代码仓库地址,软件即可自动拉取代码、智能筛选源代码文件,并按官方规范完成分页排版与随机打乱顺序,最终生成可直接提交的 PDF 材料。核心功能包括:克隆 Git 仓库、提取源代码文件、自动排版代码页、生成鉴别材料 PDF、随机打乱代码顺序、设定每页行数、导出源程序材料、生成文档鉴别材料,以及适配中文字体确保 PDF 显示正确。 适用人群:本工具适合需要申请软件著作权的个人开发者、中小型企业的技术或知识产权部门、高校科研团队,以及知识产权代理机构中负责材料整理的专员。无论您开发的是桌面软件、Web 应用还是移动应用,只要代码托管在 Git 仓库,均可通过本工具快速生成符合要求的鉴别材料。 使用场景及目标:在软著申请流程中,准备源程序鉴别材料通常需要手动复制代码、调整排版、截图或拼接文档,耗时且易出错。使用软著助手后,您只需输入仓库地址,即可自动完成代码提取、过滤、分页排版和 PDF 导出,将原本可能需要数小时的工作压缩到几分钟完成。随机打乱功能可满足鉴别材料的抽样要求,而本地处理机制保护了核心代码安全。该工具适用于个人开发者申报软著、企业批量提交著作权材料、高校科研成果登记等典型场景,显著提升申报效率,让您将精力集中于产品研发而非文书工作。 其他说明:软著助手支持 Windows、Linux、macOS 多平台运行,安装方式为下载压缩包后解压即用,免安装。整个代码提取与材料生成过程完全在本地完成,无需联网(拉取 Git 仓库时需要网络),代码不会上传至任何第三方服务器。后端服务与前端界面分离设计,便于在本地或私有环境部署。导出的 PDF 内置常见中文字体适配,确保不同系统下版式一致。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值