[Java]图论进阶--最小生成树算法

news2024/11/28 8:37:37


专栏简介 :MySql数据库从入门到进阶.

题目来源:leetcode,牛客,剑指offer.

创作目标:记录学习MySql学习历程

希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长.

学历代表过去,能力代表现在,学习能力代表未来! 


目录

1. 最小生成树

1.1 Kruskal(克鲁斯卡尔) 算法

1.2 Prime(普里姆) 算法


1. 最小生成树

连通图中的每一棵生成树 , 都是原图的极大无环子图 , 即: 从中删去任何一条边 , 生成树就不再连通;反之 , 在其中引入任何一条新边 , 都会形成一条回路.

若连通图由n个顶点组成 , 则其生成树必含n个顶点和n-1条边 , 因此构造最小生成树有三个准则:

  • 1.只能使用图中的边来构造最小生成树
  • 2.只能使用恰好n-1条边来连接图中的n个顶点
  • 3.选用的n-1条边不能构成回路 

常见求解最小生成树的算法有: Kruskal算法和Prime算法.两种算法都采用逐步求解的贪心策略.

贪心算法: 通过局部最优解来推出全局最优解.


1.1 Kruskal(克鲁斯卡尔) 算法

给定一个有n个顶点的连通网络N={V,E}

首先构造一个由这n个顶点组成 , 不含任何边的图G={V,NULL}.

其次不断从E中取出权值最小的一条边(若有多条任选其一) , 若该边的两个顶点来自不同的连通分量 , 则将此边加入到G中.

如此反复 , 直到G中边数达到顶点数-1为止.

核心: 每次迭代时 , 选出权值最小且两端点不在同一连通分量上的边 , 加入生成树.

步骤分析:

  • 1.由于该算法的思想是全局贪心 , 因此将所有图中所有边全部放入优先级队列中.
  • 2.构造一个最小生成树 , 将优先级队列中的边依次加入.
  • 3.为了防止出现环 , 使用并查集判断每次取出的边的顶点是否来自同一个集合 .
  • 4.如果不是同一集合 , 将该边加入最小生成树并用并查集将该边的领接顶点放入同一个       集合.

代码示例: 

 /**
     * 克鲁斯卡尔算法实现
     * @param minTree
     * @return
     */
    /**
     * 模拟实现一条边
     */
    static class Edge{
        public int srcIndex;
        public int destIndex;
        public int weight;

        public Edge(int srcIndex, int destIndex, int weight) {
            this.srcIndex = srcIndex;
            this.destIndex = destIndex;
            this.weight = weight;
        }
    }

    public int kruskal(GraphOfMatrix minTree) {
        //1.定义一个优先级队列
        PriorityQueue<Edge> minQ = new PriorityQueue<Edge>(new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        int n = arrayV.length;
        //2.遍历领接矩阵,将所有的边都放入优先级队列中
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i < j && Matrix[i][j] != Integer.MIN_VALUE) {
                    minQ.offer(new Edge(i, j, Matrix[i][j]));
                }
            }
        }
        //3.构造并查集将符合要求的边加入到最小生成树中
        UnionFindSet ufs = new UnionFindSet(n);

        int size = 0;//记录最小生成树中边的数量
        int totalWeight = 0;//记录权值
        while (size < n - 1 && !minQ.isEmpty()) {
            Edge edge = minQ.poll();
            int srcIndex = edge.srcIndex;
            int destIndex = edge.destIndex;
            //同一边的相邻顶点不能来自同一集合
            if (!ufs.isSameUnionFindSet(srcIndex, destIndex)) {
                //将符合条件的边加入到最小生成树中
                minTree.addEdgeUseIndex(srcIndex, destIndex, Matrix[srcIndex][destIndex]);
                System.out.println("选择的边"+arrayV[srcIndex]+" -> "+arrayV[destIndex]+Matrix[srcIndex][destIndex]);
                size++;
                totalWeight += Matrix[srcIndex][destIndex];
                //将添加过的边的相邻顶点放入同一集合,防止出现环.
                ufs.union(srcIndex, destIndex);
            }
        }
        if (size == n - 1) {
            return totalWeight;
        } else {
            throw new RuntimeException("没有最小生成树");
        }
    }

   //按照下标将边加入到最小生成树中
    public void addEdgeUseIndex(int srcIndex,int destIndex,int weight){
        Matrix[srcIndex][destIndex] = weight;
        //如果是无向图邻接矩阵对称位置也要添加
        if (!isDirect){
            Matrix[destIndex][srcIndex] = weight;
        }
    }
    //测试克鲁斯卡尔算法
    public static void main(String[] args) {
        String str = "abcdefghi";
        char[] array =str.toCharArray();
        graph.GraphOfMatrix g = new graph.GraphOfMatrix(str.length(),false);
        g.initArray(array);
        g.addEdge('a', 'b', 4);
        g.addEdge('a', 'h', 8);
//g.addEdge('a', 'h', 9);
        g.addEdge('b', 'c', 8);
        g.addEdge('b', 'h', 11);
        g.addEdge('c', 'i', 2);
        g.addEdge('c', 'f', 4);
        g.addEdge('c', 'd', 7);
        g.addEdge('d', 'f', 14);
        g.addEdge('d', 'e', 9);
        g.addEdge('e', 'f', 10);
        g.addEdge('f', 'g', 2);
        g.addEdge('g', 'h', 1);
        g.addEdge('g', 'i', 6);
        g.addEdge('h', 'i', 7);
        graph.GraphOfMatrix kminTree = new graph.GraphOfMatrix(str.length(),false);
        System.out.println(g.kruskal(kminTree));
        kminTree.printGraph();
    }

构造并查集:

public class UnionFindSet {
    public int[] elem;

    public UnionFindSet(int n){
        this.elem = new int[n];
        Arrays.fill(elem,-1);
    }

    /**
     * 查找数据x的根节点
     * @param x
     * @return
     */
    public int findRoot(int x){
        if (x < 0){
            throw new RuntimeException("下表不合法");
        }
        while (elem[x] >= 0){
            x = elem[x];
        }
        return x;
    }
    /**
     * 查询x1和x2是不是同一个集合
     * @param x1
     * @param x2
     * @return
     */
    public boolean isSameUnionFindSet(int x1 , int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if (index1 == index2){
            return true;
        }
        return false;
    }

    /**
     * 这是合并操作
     * @param x1
     * @param x2
     */
    public void union(int x1 , int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if (index1 == index2) return;
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }

    /**
     * 有几对关系
     * @return
     */
    public int getCount(){
        int count = 0;
        for (int x:elem) {
            if (x < 0){
                count++;
            }
        }
        return count;
    }
    public void Print(){
        for (int x:elem){
            System.out.print(x+" ");
        }
        System.out.println();
    }
}

 测试结果:


1.2 Prime(普里姆) 算法

普里姆算法与克鲁斯卡尔算法类似 , 核心区别是普里姆算法采用局部贪心的思想.

首先 , 设定两个集合 , X{}已确定顶点的集合 , Y{}未确定顶点的集合.

其次 , 假设图中的顶点为 a,b,c,d,e,f,g,h,i.放入Y{}中.

然后 , 任取一个顶点放入X{}中 . 在Y{}中选择一个与该顶点相连权值最小的边 , 加入最小生成树中.

如此重复 , 直到最小生成树的边数达到顶点数-1为止.

代码示例:

/**
     * 普里姆算法实现
     * @param minTree
     * @param chV 图中顶点的起点
     * @return
     */
    public int prime(GraphOfMatrix minTree,char chV) {
        int srcIndex = getIndexOfV(chV);
        //存储已确定的顶点
        Set<Integer> setX = new HashSet<>();
        setX.add(srcIndex);
        //初始化未确定的点
        Set<Integer> setY = new HashSet<>();
        int n = arrayV.length;
        for (int i = 0; i < n; i++) {
            if (i != srcIndex){
                setY.add(i);
            }
        }
        //定义一个优先级队列
        PriorityQueue<Edge> minQ = new PriorityQueue<>(new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        //遍历srcIndex连接出去的边,并放入优先级队列中排序
        for (int i = 0; i < n; i++) {
            if (Matrix[srcIndex][i] != Integer.MIN_VALUE){
                minQ.offer(new Edge(srcIndex,i,Matrix[srcIndex][i]));
            }
        }
        int size = 0;
        int totalWeight = 0;
        while (!minQ.isEmpty()){
            Edge min = minQ.poll();
            int srcI = min.srcIndex;
            int destI = min.destIndex;
            if (setX.contains(destI)){
                //此时会构成环
            }else {
                minTree.addEdgeUseIndex(srcI,destI,Matrix[srcI][destI]);
                System.out.println("起点"+arrayV[srcI]+" -> "+"终点"+arrayV[destI]+Matrix[srcI][destI]);
                size++;
                totalWeight+=min.weight;
                if (size == n-1){
                    return totalWeight;
                }
                //更新两个集合
                setX.add(destI);
                setY.remove(destI);
                //把dest连出去的所有边也放到优先级队列中
                for (int i = 0; i < n; i++) {
                    if (Matrix[destI][i] != Integer.MIN_VALUE && !setX.contains(i)){
                        minQ.offer(new Edge(destI,i,Matrix[destI][i]));
                    }
                }
            }
        }
       throw new RuntimeException("没有最小生成树");
    }
    //测试普里姆算法
    public static void main3(String[] args) {
            String str = "abcdefghi";
            char[] array =str.toCharArray();
            GraphOfMatrix g = new GraphOfMatrix(str.length(),false);
            g.initArray(array);
            g.addEdge('a', 'b', 4);
            g.addEdge('a', 'h', 8);
//g.addEdge('a', 'h', 9);
            g.addEdge('b', 'c', 8);
            g.addEdge('b', 'h', 11);
            g.addEdge('c', 'i', 2);
            g.addEdge('c', 'f', 4);
            g.addEdge('c', 'd', 7);
            g.addEdge('d', 'f', 14);
            g.addEdge('d', 'e', 9);
            g.addEdge('e', 'f', 10);
            g.addEdge('f', 'g', 2);
            g.addEdge('g', 'h', 1);
            g.addEdge('g', 'i', 6);
            g.addEdge('h', 'i', 7);
            GraphOfMatrix primTree = new GraphOfMatrix(str.length(),false);
            System.out.println(g.prime(primTree,'a'));
            primTree.printGraph();
    }

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

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

相关文章

计算机毕设Python+Vue校园社团信息管理系统(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Teams app LukcyDraw 的升级之路

我已经有很长一段时间没有更新我的 Teams App&#xff1a;LuckyDraw 了&#xff0c;有很多用户反馈给我&#xff0c;因为快到圣诞&#xff0c;新年和春节了&#xff0c;很多公司都开始要使用LuckyDraw来搞抽奖活动&#xff0c;希望LuckyDraw能支持大用户量的抽奖&#xff0c;所…

当打造一款极速湖分析产品时,我们在想些什么

作者&#xff1a;王有卓&#xff0c;StarRocks Contributor 随着开源数据湖技术的快速发展以及湖仓一体全新架构的提出&#xff0c;传统数据湖在事务处理、流式计算以及数据科学场景的限制逐渐得以优化解决。 为了满足用户对数据湖探索分析的需求&#xff0c;StarRocks 在 2.…

jsp+ssm计算机毕业设计ssm实验教学资源管理系统【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

【linux】linux实操篇之进程管理

目录前言进程介绍和查询进程基本介绍显示系统执行的进程终止进程服务管理监控服务动态监控进程监控网络状态结语前言 本篇博客总结linux中的进程管理相关知识&#xff0c;主要有进程介绍&#xff0c;终止进程&#xff0c;服务管理以及监控服务&#xff0c;一起来看看吧&#x…

模拟电路设计(40)---你真的懂“接地”吗?

概念 接地是指将一个电路、设备乃至分系统与一个基准“地”电位连接的电气要求&#xff0c;目的在于提供一个等电位点或等电位面。接地可以接真正的大地&#xff0c;也可以不接&#xff0c;例如飞机上的电子电气设备接飞机机壳就是接地。 接地必须有接地导体和接地平面才能够…

ChatGPT和InstructGPT 对比,ChatGPT将改变世界,影响力不亚于2007年新一代iPhone智能手机的发布

ChatGPT ChatGPT 的模型&#xff0c;它以对话方式进行交互。对话格式使 ChatGPT 可以回答后续问题、承认错误、挑战不正确的前提并拒绝不适当的请求。ChatGPT 是InstructGPT的兄弟模型&#xff0c;它经过训练可以按照提示中的说明进行操作并提供详细的响应。 ChatGPT 网址&am…

vue打包优化一

webpack.dll.config.js配置 相关文章 https://www.cnblogs.com/echoyya/p/16413591.html 步骤一&#xff1a;创建webpack.dll.config.js&#xff08;不一定要是这个名字&#xff0c;只要执行指令的时候路径正确就行&#xff09; // webpack.dll.config.js const path requi…

FIX:FusionCharts Suite XT 3.19.x

FusionCharts Suite XT&#xff1a;探索 100 多张图表和 2000 多张地图 FusionCharts 提供了 100 多张图表和 2000 多张地图。凭借广泛的文档、一致的 API 和一系列自定义选项 - FusionCharts 是最全面的 JavaScript 图表库&#xff0c;受到全球 750,000 名开发人员的喜爱。Fus…

JAVA实训第四天

目录 异常 什么是异常&#xff1f; 为什么要进行异常处理&#xff1f; 方法的调用堆栈 方法调用堆栈中异常对象的传递 Java中的异常类 常见的异常类 常见的异常类及出现此异常的原因 •1、java.lang.NullpointerException(空指针异常) •2、 java.lang.ClassNotFoundExcept…

rocketmq源码-broker接收消息

前言 这篇笔记&#xff0c;主要记录producer在通过netty发送了请求之后&#xff0c;在broker这边是如何处理的消息的 org.apache.rocketmq.remoting.netty.NettyRemotingServer.NettyServerHandler#channelRead0 这里是broker的nettyServer端接收客户端发送消息的入口&#x…

Android中GRPC的使用-4种通信模式

GRPC的通信模式 GRPC四种基础通信模式&#xff1a;一元RPC、服务器端流RPC、客户端流RPC以及双向流RPC。下面分别四种模式进行介绍&#xff0c;并在Android环境中来实现服务和客户端。 一元RPC 一元RPC模式也被称为简单RPC模式。在该模式中&#xff0c;当客户端调用服务端的远程…

破记录!国产数据库KunDB 单节点TPC-C事务性能超180万tpmC

近日&#xff0c;星环科技KunDB在TPC-C事务性能测试中&#xff0c;采用常规国产服务器&#xff0c;实现了单节点tpmC超180万&#xff0c;体现其世界级领先的事务处理能力。 TPC-C是全球 OLTP 数据库最权威的性能测试基准&#xff0c;由TPC组织&#xff08;国际事务性能委员会&…

【数字IC基础】TestBench功能

文章目录 一、TestBench的目的?二、TestBench的功能?三、TestBench(验证)的四要素?一、TestBench的目的? 对使用硬件描述语言(HDL)设计的电路(DUT)进行仿真验证,测试设计电路的功能、部分性能是否符合预期二、TestBench的功能? TestBench和DUT的关系是一个马蹄形结…

React - 项目初始化设置

React - 项目初始化设置一. 页面零边距二. 路径别名配置三. 安装使用 scss四. 安装 router一. 页面零边距 可以手写 css 重置页面样式&#xff0c;也可使用 reset-css 自动配置 手写样式不多说&#xff0c;这里使用 reset-css 安装依赖 yarn add reset-css src/App.js 文件中引…

阿里技术人分享的三本书豆瓣评分8.5分,让你的架构思维略窥门径

又逢“金九银十”&#xff0c;年轻的毕业生们满怀希望与忐忑&#xff0c;去寻找、竞争一个工作机会。已经在职的开发同学&#xff0c;也想通过社会招聘或者内推的时机争取到更好的待遇、更大的平台。 然而&#xff0c;面试人群众多&#xff0c;技术市场却相对冷淡&#xff0c;…

ssm+Vue计算机毕业设计校园疫情管理系统(程序+LW文档)

ssmVue计算机毕业设计校园疫情管理系统&#xff08;程序LW文档&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

我用了几行代码就实现了界面变灰效果

前言 前段时间,各个大厂的 App 首页都变成了灰色,网上还有不少人问界面变灰怎么做到的。有人说是后台换了图片,这个回答显然是不懂技术了,对于个性化推荐系统来说,使用的图片那么多张,怎么可能一一替换。还有一种说法是说后台将图片处理后再返回给前端的,这个显然也不太…

$ORACLE_BASE和$ORACLE_HOME下xml文件误删

问题描述&#xff1a; 某项目安装环境grid管理的oracle&#xff0c;环境已经搭建好许久&#xff0c;执行上线检查PSU版本时发现opatch lsinventory报错 但实例的sqlpatch显示已经应用成功且oracle client版本也显示为19.13 怀疑是Central Inventory&#xff08;/oracle/oraInv…

【知识图谱】(task4)知识图谱的抽取和构建

note CRF条件随机场是全局最优&#xff08;判别式模型&#xff09;&#xff0c;HMM是局部最优&#xff08;生成式模型&#xff09;实体关系抽取方法概览&#xff1a; 事件抽取主要分为事件的发现和分类和事件要素抽取两部分&#xff0c;又可以细分为触发词识别与事件分类和要素…