kruskalCase克鲁斯卡尔算法

news2025/1/11 5:10:25

介绍

它的特点和Prim算法不一样,Prim是以点为主,通过顶点遍历没有访问的节点计算最小权重直至一条最小边出来;而Kruskal算法是以边为主,时间复杂度要低一些0(edge);

什么是最小生成树

  • 最小生成树:在一个有n个结点的无向图中选出最少的边,保证所选边权相加之和最小以及该图中依然有n个结点并且n个结点连通。
  • 一共有n个结点,要保证连通,至少需要n-1条边。
  • 最小生成树的权值:w ( t ) = ∑ ( u , v ) ∈ t w ( u , v ) w(t)=\sum\limits_{(u,v)\in t}^{}w(u,v)w(t)= (u,v)∈t∑w(u,v)
    下面我们用图看一下什么是最小生成树:

请添加图片描述
在该图中,我们留下这四条边就可以保证各个结点是连通的了,同时也保证所有边权之和最小,所以这个图的最小生成树权值为:1 + 2 + 3 + 5 = 11 1+2+3+5=111+2+3+5=11
请添加图片描述

Kruskal思路:

  1. 首先按照边权从小到大排序
  2. 然后从小到大看每条边,判断两个节点的顶点是否是同一个,需要判断是否会回路

例子:
3. 开始克鲁斯卡尔算法来找到第一条边
请添加图片描述
4. 找到第二条边
请添加图片描述

  1. 找到第三条边

请添加图片描述
6. 最关键的第四条边
当你找到第四条边的时候会发现第四条边的两边所依附的节点已经是连通的了,根据克鲁斯卡尔算法需要将构成回路的边给去掉,因为你要计算最小生成树,既然这两个点已经连通了,那我们肯定是可以不选这条边的,不选这条边必然不会让结果变得更差,所以我们直接跳过这条边
请添加图片描述
7. 计算第五条边
找到第五条边,找完五条边可以发现此时此刻所有的点已经连通了,最小生成树已经找到!
最小生成树的权值:1 + 2 + 3 + 5 = 11
请添加图片描述

代码实现

在这里插入图片描述

1.构造方法
在构造的时候我们会进行遍历矩阵判断节点是否有INF,如果都是有自己值的话就进行判断edgeNum++

 //1.构造克鲁斯卡尔的构造
    public KruskalCase(char[] vertexs, int[][] matrix) {
        /**
         * 1.初始化顶点数和边的个数
         */
        int vlen = vertexs.length;

        /**
         * 2.利用复制拷贝将传入的数组拷贝一份
         */
        this.vertexs = new char[vlen];
        for (int i = 0; i < vertexs.length; i++) {
            this.vertexs[i] = vertexs[i];
        }

        /**
         * 3.初始化边,使用的也是复制拷贝
         */
        this.matrix = new int[vlen][vlen];
        for (int i = 0; i < vlen; i++) {
            for (int j = 0; j < vlen; j++) {
                this.matrix[i][j] = matrix[i][j];
            }
        }

        /**
         * 4.统计边的条数
         */
        for (int i = 0; i < vlen; i++) {
            for (int j = i + 1; j < vlen; j++) {
                //4.1判断边是否有效(用INF来判断)
                if (this.matrix[i][j] != INF) edgeNum++;
            }
        }

    }
public static void main(String[] args) {
        char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        int[][] matrix = {
                {0, 12, INF, INF, INF, 16, 14},
                {12, 0, 10, INF, INF, 7, INF},
                {INF, 10, 0, 3, 5, 6, INF},
                {INF, INF, 3, 0, 4, INF, INF},
                {INF, INF, 5, 4, 0, 2, 8},
                {16, 7, 6, INF, 2, 0, 9},
                {14, INF, INF, INF, 8, 9, 0}
        };
        KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);
    }

2.将构造好的图打印出来

//2.打印邻接矩阵
    public void print() {
        System.out.println("邻接矩阵: \n");
        for (int i = 0; i < vertexs.length; i++) {
            for (int j = 0; j < vertexs.length; j++) {
                System.out.printf("%12d\t", matrix[i][j]);
            }
            System.out.println();
        }
    }

3.关键:将构造好的边进行排序处理

/**
     * 3.对边进行排序处理(冒泡排序)
     *
     * @param edges:边的集合
     */
    private void sortEdges(EData[] edges) {
        for (int i = 0; i < edges.length - 1; i++) {
            for (int j = 0; j < edges.length - 1 - i; j++) {
                if (edges[j].weight > edges[j + 1].weight) {
                    //进行交换
                    EData tmp = edges[j];
                    edges[j] = edges[j + 1];
                    edges[j + 1] = tmp;
                }
            }
        }
    }

4.寻找目标节点ch在数据数组中的下标位置

/**
     * 4.寻找对应的值的下标位置
     *
     * @param ch 顶点的值,比如'A','B'
     * @return 返回ch顶点对应的下标,如果找不到就返回-1
     */
    private int getPosition(char ch) {
        for (int i = 0; i < vertexs.length; i++) {
            if (vertexs[i] == ch) {
                return i;
            }
        }
        return -1;
    }

5.获取所有的边

/**
     * 5.获取图钟的边,将其放到EData[]数组当中
     * 通过邻接矩阵matrix获取
     *
     * @return
     */
    private EData[] getEdges() {
        int index = 0;
        //1.存储有效边的数组
        EData[] edges = new EData[edgeNum];
        for (int i = 0; i < vertexs.length; i++) {
            for (int j = i + 1; j < vertexs.length; j++) {
                //2.判断是否是有效边
                if (matrix[i][j] != INF) {
                    edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]);
                }
            }
        }
        return edges;
    }

在这里插入图片描述

7.获取下标i的顶点的终点——>在后面判断是否回路起到关键作用
思路:从ends数组中得到i的终点,并赋值给i返回的值为终点(一个变量i即可,减少了内存的消耗)

 /**
     * 6.功能:获取下标为 i 的顶点的终点,用于后面判断两个顶点的终点是否相同
     * 在已经生成边的时候才会进入while中,否则就是0
     * @param ends:记录了各个顶点对应的终点是哪个,ends是在遍历过程中,逐步形成的
     * @param i:表示传入顶点对应的下标
     * @return:返回的是下标为i的这个顶点对应的终点的下标
     */
    public int getEnd(int[] ends, int i) {
        //如果为0说明终点就是自己,ends装的是对应顶点i的终点
        while (ends[i] != 0) {
            i = ends[i];
        }
        return i;
    }

8.Kruskal算法的使用
1.首先得到所有的边
2.然后进行排序
3.遍历所有的边,判断是否构成回路,如果没有就加入到结果集中
得到中每条边的起点p1和终点p2,获取两个点的顶点判断是否构成回路,如果没有的话就将p1的终点的终点设置为p2的终点,并加入到结果集中

public void kruskal() {
        int index = 0; //表示最后结果的索引
        int[] ends = new int[edgeNum]; //用于保存“已有最小生成树中的每个顶点在最小生成树的终点"

        EData[] rets=new EData[edgeNum]; //保留结果,最后的最小生成树

        //1.获取图中所有边的集合,一共12条边
        EData[] edges = getEdges();
        System.out.println("图的边的集合=" + Arrays.toString(edges) + "共" + edges.length);

        //2.按照边的权值进行从小到大的排序
        sortEdges(edges);

        //3.遍历edges数组,将边添加到最小生成树时,判断准备加入的边是否会构成回路,如果没有就加入rets,否则不能加入
        for (int i = 0; i < edgeNum; i++) {
            //获取第i条边的第一个顶点(起点)
            int p1 = getPosition(edges[i].start);
            //获取到第i条边第2个顶点
            int p2 = getPosition(edges[i].end);

            //获取p1顶点在最小生成树的终点和 p2的顶点
            int m = getEnd(ends, p1);
            int n = getEnd(ends, p2);

            //4.判断是否构成回路
            if (m != n) { //终点不一致不构成回路——>m的顶点设置为n,也就是p1的顶点的顶点变为p2的顶点
                ends[m] = n; //设置m在已有最小生成树中的终点<E,F>[0,0,0,0,0,0,0,0,0,0,0]
                rets[index++]=edges[i];//有一条边加入到rets数组
            }

        }
        //5.输出最小生成树
        System.out.println("最小生成树为:");
        for (int i = 0; i < index; i++) {
            System.out.println(rets[i]);
        }
    }

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

blender教程

文章目录Three的部分课件blender相关资源模型下载地址视图基本操作实现甜甜圈下落的动画day01笔记Three的部分课件 blender相关资源 模型下载地址 视图基本操作 shiftd 复制多个 g键移动 x y z锁定方向 A可以全选 然后选择大小 s 键 拖拽大小 ctrl a 全部应用 切换到不同的编…

Python 图表利器 pyecharts

随着互联网的高速发展&#xff0c;数据量也在疯狂增长&#xff0c;近几年数据分析&#xff0c;数据挖掘的岗位越来越吃香。说到数据分析&#xff0c;就离不开数据的可视化&#xff0c;毕竟图表比冷冰冰的数字直观&#xff0c;一眼就可以看出趋势和结论&#xff0c;毕竟一图胜千…

【AIOT】BLE Paper Relative

Billah, Md Fazlay Rabbi Masum, et al. “BLE Can See: A Reinforcement Learning Approach for RF-based Indoor Occupancy Detection.” Proceedings of the 20th International Conference on Information Processing in Sensor Networks (co-located with CPS-IoT Week 20…

对象池模式

一、对象池模式 1、定义 对象池模式&#xff08;Object Pool Pattern&#xff09;是将对象预先创建并初始化后放入对象池中&#xff0c;对象提供者就能利用已有的对象来处理请求&#xff0c;减少频繁创建对象锁占用的内存空间和初始化时间。属于创建型设计模式。 一个对象池包…

python 模板注入

web 程序包括两个文件&#xff1a; flask-test.py 和 Config.py 文件 #!/usr/bin/env python # -*- coding:utf8 -*- import hashlib import logging from datetime import timedelta from flask import Flask from flask import request from flask import config from flask…

基于java(springboot)篮球竞赛预约管理系统(java毕业设计)

基于java(springboot)篮球竞赛预约管理系统 篮球竞赛管理系统是基于java编程语言&#xff0c;mysql数据库&#xff0c;springboot框架和idea工具开发&#xff0c;本系统分为用户和管理员两个角色&#xff0c;其中用户可以在线注册登陆&#xff0c;查看平台公告&#xff0c;查看…

JSP运动会信息网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 模块划分&#xff1a;通知类型、通知信息、裁判信息、运动员信息、项目类型、项目 信息、场地信息、项目安排、报名信息…

【记录】ubuntu20.04安装nvidia显卡驱动

新安装的Ubuntu20.04系统&#xff0c;如果想进行人工智能相关的学习&#xff0c;需要配置一系列的环境&#xff0c;这里我记录下具体的安装过程。 Nvidia显卡驱动的安装 1 安装前需要安装依赖(必须执行) sudo apt-get update #更新软件列表 #安装编译依赖 sudo apt-get inst…

Python urllib CRLF注入漏洞小结

Python urllib CRLF注入漏洞小结 CVE-2016-5699 https://www.suse.com/security/cve/CVE-2016-5699.html before 2.7.10 and 3.x before 3.4.4POC&#xff1a; http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:12345/foo漏洞&patch源码&#xff1a;http…

音视频大合集最终篇;学废了

前言 加企鹅群&#xff1a;1079654574 解锁 《音视频八大板块资料》音视频大合集&#xff0c;从初中高到面试应有尽有;让学习更贴近未来实战。已形成PDF版 八个模块内容如下&#xff1a; 1.音视频基础2.FFmpeg实战3.流媒体客户端4.流媒体服务器5.WebRTC项目实战6.Android NDK开…

零时 || 警惕恶意聊天软件!聊天记录被劫持损失数千万资产追踪分析

事件背景 近期&#xff0c;零时科技安全团队收到大量用户因为同一个原因导致加密资产被盗的情况&#xff0c;经调查都是因为过程中使用了恶意Whatsapp的原因&#xff0c;通过与受害者沟通&#xff0c;了解到情况如下&#xff1a; 受害者在使用恶意Whatsapp进行沟通时&#xf…

173. 二叉搜索树迭代器

实现一个二叉搜索树迭代器类BSTIterator &#xff0c;表示一个按中序遍历二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff1a; BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在…

STM32F4 | PWM输出实验

文章目录一、PWM 简介二、硬件设计三、软件设计四、实验现象五、STM32CubeMX 配置定时器 PWM 输出功能上一章&#xff0c;我们介绍了 STM32F429 的通用定时器 TIM3&#xff0c;用该定时器的中断来控制 DS1 的闪烁&#xff0c;这一章&#xff0c;我们将向大家介绍如何使用 S…

CososCreator (Android)-AppLovin MAX 广告聚合平台接入+Firebase统计

CososCreator 2.2.4 Android Studio &#xff1a;4.2.1 接入SDK有&#xff1a;接max聚合及中介平台(Admob&#xff0c;FB, applovin&#xff0c;pangle&#xff0c;mintegral&#xff0c;vungle&#xff0c;unity)&#xff0c;和Firebase 统计 1、构建Android工程 2、升级gr…

计算机SSM毕设推荐 40个高质量软件工程毕设项目分享【源码+论文】(一)

文章目录前言 题目1 : 基于SSM的毕业设计管理系统 <br /> 题目2 : 基于SSM的病人跟踪治疗信息管理系统 <br /> 题目3 : 基于SSM的大学生兼职跟踪系统 <br /> 题目4 : 基于SSM的大学生企业推荐系统 <br /> 题目5 : 基于SSM的电影院在线售票系统 <br …

电感和磁珠的区别

电感和磁珠在我们电路设计中经常会用到&#xff0c;他们都属于磁性元器件&#xff0c;今天就来分享下电感和磁珠的区别 1.从构成原理来看 电感其实就是导线这样一圈一圈绕在磁芯上&#xff0c;这样就构成了电感&#xff0c;而磁珠(插件)的话则是导线外围包裹着一层铁氧体磁性材…

Linux中磁盘存储相关命令

du 命令 Linux du命令也是查看使用空间的&#xff0c;但是与df命令不同的是Linux du命令是对文件和目录磁盘使用的空间的查看&#xff0c;还是和df命令有一些区别的. **1&#xff0e;**命令格式&#xff1a; du [选项][文件] **2&#xff0e;**命令功能&#xff1a; 显示每…

javaHelloWorld

java语言介绍 ​ 目前大系统开发中&#xff0c;很少使用单一语言进行开发&#xff0c;现有语言也十分发达&#xff0c;包含Java\C\C\PHP\Python等等。通常情况下&#xff0c;一个大系统底层驱动部分都是使用C语言开发&#xff0c;而在上层用户交互层使用java语言开发。因此&am…

新型材料厂电动葫芦PLC无线通讯应用方案详解

一&#xff0e;应用背景 电动葫芦是一种安装在天车、龙门吊之上的特种起重设备&#xff0c;具有体积小&#xff0c;自重轻&#xff0c;操作简单&#xff0c;使用方便等特点&#xff0c;是起升搬运物品&#xff0c;最理想的起重设备之一。目前电动葫芦的控制部分都是由PLC完成的…

【Spring Cloud】Ribbon负载均衡原理与实战(源码级讲解)

本期目录1. 负载均衡原理1.1 总体流程1.2 源码解析2. 负载均衡策略2.1 负载均衡策略继承关系2.2 负载均衡策略描述1&#xff09;ZoneAvoidanceRule2&#xff09;AvailabilityFilteringRule2.3 修改负载均衡策略方式1&#xff09;全局修改2&#xff09;局部修改3. 饥饿加载3.1 背…