【数据结构与算法 | 图篇】最小生成树之Prim算法

news2024/11/17 1:27:23

1. 前言

普里姆算法(Prim's Algorithm)是一种用于寻找加权无向图中的最小生成树(Minimum Spanning Tree, MST)的贪心算法。

最小生成树是指对于一个给定的无向图,连接所有顶点且边的总权重最小的生成树。

2. 算法步骤

1. 初始化:

  • 选择任意一个顶点作为起始点,这个顶点被加入到生成树中。
  • 创建一个集合用来存储已添加到生成树中的顶点。
  • 创建一个优先队列(通常使用最小堆实现),用来存放未加入生成树的顶点及其与已加入顶点之间的边的权重。


2. 迭代:

  • 在每一步中,从未加入生成树的顶点中找到与已加入顶点相连的边中权重最小的边,并将其添加到生成树中。
  • 将这条边所连接的新顶点加入到已加入生成树的顶点集合中。
  • 更新优先队列,包括新加入顶点的所有邻接顶点及其边的权重。


3. 终止条件:

  • 当所有的顶点都被加入到生成树中时,算法结束。

Prim算法的思路与前文写的迪杰斯特拉算法几乎一致。

只需要更改这部分代码:

e.linked.dist = e.weight;

3.  主要代码

顶点图:

a1d9928398a042cba7608408d0013b6e.png

public class Prim {
    public static void main(String[] args) {
        Vertex v1 = new Vertex("1");
        Vertex v2 = new Vertex("2");
        Vertex v3 = new Vertex("3");
        Vertex v4 = new Vertex("4");
        Vertex v5 = new Vertex("5");
        Vertex v6 = new Vertex("6");
        Vertex v7 = new Vertex("7");

        v1.edges = new ArrayList<>();
        v1.edges.add(new Edge(v2, 2));
        v1.edges.add(new Edge(v3, 4));
        v1.edges.add(new Edge(v4, 1));

        v2.edges = new ArrayList<>();
        v2.edges.add(new Edge(v1, 2));
        v2.edges.add(new Edge(v4, 3));
        v1.edges.add(new Edge(v5, 10));

        v3.edges = new ArrayList<>();
        v3.edges.add(new Edge(v1, 4));
        v3.edges.add(new Edge(v4, 2));
        v3.edges.add(new Edge(v6, 5));

        v4.edges = new ArrayList<>();
        v4.edges.add(new Edge(v1, 1));
        v4.edges.add(new Edge(v2, 3));
        v4.edges.add(new Edge(v3, 2));
        v4.edges.add(new Edge(v5, 7));
        v4.edges.add(new Edge(v6, 8));
        v4.edges.add(new Edge(v7, 4));

        v5.edges = new ArrayList<>();
        v5.edges.add(new Edge(v2, 10));
        v5.edges.add(new Edge(v4, 7));
        v5.edges.add(new Edge(v7, 6));

        v6.edges = new ArrayList<>();
        v6.edges.add(new Edge(v3, 5));
        v6.edges.add(new Edge(v4, 8));
        v6.edges.add(new Edge(v7, 1));

        v7.edges = new ArrayList<>();
        v7.edges.add(new Edge(v4, 4));
        v7.edges.add(new Edge(v5, 6));
        v7.edges.add(new Edge(v6, 1));

        List<Vertex> graph = new ArrayList<>();
        graph.add(v1);
        graph.add(v2);
        graph.add(v3);
        graph.add(v4);
        graph.add(v5);
        graph.add(v6);
        graph.add(v7);

        prim(graph, v1);
    }

    public static void prim(List<Vertex> list, Vertex v) {
        List<Vertex> graph = new ArrayList<>(list);
        // 将初始顶点v的dist值设置为0
        v.dist = 0;
        while (!graph.isEmpty()) {
            // 第3步:每次选择最小的临时距离的未访问节点作为当前节点
            Vertex i = ChooseMinDistVertex(graph);
            UpdateNeighboursDist(i);
            graph.remove(i);
            // 表示已经被处理完了
            i.visited = true;
        }
        // 打印最短路径中,一个顶点的前一个顶点是谁
        for (Vertex i : list) {
            System.out.println("v" + i.name + " <- " + (i.prev != null ? "v" + i.prev.name : null));
        }
    }

    private static Vertex ChooseMinDistVertex(List<Vertex> list) {
        int min = 0;
        int dist = list.get(min).dist;
        for (int i = 0; i < list.size(); i++) {
            if (dist > list.get(i).dist) {
                min = i;
                dist = list.get(i).dist;
            }
        }
        return list.get(min);
    }

    private static void UpdateNeighboursDist(Vertex v) {
        // 对于当前顶点,遍历其所有未访问的顶点
        for (Edge e : v.edges) {
            if (!e.linked.visited) {
                if (v.dist + e.weight < e.linked.dist) {
                    // 只需要更改这部分
                    e.linked.dist = e.weight;
                    e.linked.prev = v;
                }
            }
        }
    }
}

输出结果:

v1 <- null
v2 <- v1
v3 <- v4
v4 <- v1
v5 <- v4
v6 <- v3
v7 <- v4

4. 总结:

普里姆算法的时间复杂度取决于使用的数据结构。如果使用简单的数组或列表来实现优先队列,则时间复杂度为O(E * V),其中E是边的数量,V是顶点的数量。但如果使用二叉堆作为优先队列,则时间复杂度可以降低至O((V+E) * log(V)),这在稠密图中更为有效。

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

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

相关文章

Spring Boot 核心配置

一、 Spring Boot配置文件分类 SpringBoot是基于约定的&#xff0c;所以很多配置都有默认值&#xff0c;但如果想使用自己的配置替换默认配置的话&#xff0c;就可以使用application.properties或者application.yml&#xff08;application.yaml&#xff09;进行配置 applicat…

外贸市场开发【越南】

​作为“新兴之秀” 越南的经济发展可谓是突飞猛进 并在2022年&#xff0c;成为全亚洲经济增长最快速经济体 经济的增长也让越南的地位变得不一样了 一起来看看外贸人聚焦的东南亚排名前五的越南 越南社会主义共和国&#xff0c;通称越南&#xff0c;是位于东南亚的中南半岛…

谷粒商城实战笔记-213-商城业务-认证服务-整合短信验证码服务

文章目录 一&#xff0c;开通阿里云云市场短信服务1&#xff0c;阿里云开通免费短信服务并调试2&#xff0c;整合短信服务2.1 下载HttpUtils代码2.2 开发调用短信服务的组件2.3 测试 HttpUtils代码 这一节主要内容是整合短信发送服务。 一&#xff0c;开通阿里云云市场短信服务…

多输入多输出 | Matlab实现CPO-BP冠豪猪优化算法优化BP神经网络多输入多输出预测

多输入多输出 | Matlab实现CPO-BP冠豪猪优化算法优化BP神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现CPO-BP冠豪猪优化算法优化BP神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现CPO-BP冠豪猪优化…

CUDA-MODE课程笔记 第6课: 如何优化PyTorch中的优化器

我的课程笔记&#xff0c;欢迎关注&#xff1a;https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/cuda-mode CUDA-MODE课程笔记 第6课: 如何优化PyTorch中的优化器 课程内容 上面三张Slides讲述了运行时间&#xff08;runtime&#xff09;和内存使用&…

ChatGPT 3.5/4.0 新手使用手册(详细版)

1. 什么是 ChatGPT&#xff1f; ChatGPT是由 OpenAI 开发的先进人工智能语言模型&#xff0c;能够理解并生成自然语言文本。它可以帮助你进行写作、回答问题、提供建议&#xff0c;甚至参与对话。ChatGPT 3.5 和 4.0 是两个不同版本&#xff0c;它们都拥有强大的语言处理能力&…

sublime text 4 安装(含激活码)安装破解汉化 Sublime Text 4 的操作指南

sublime text 4 安装&#xff08;含激活码&#xff09; 一、下载步骤 官网地址&#xff1a;Sublime Text - the sophisticated text editor for code, markup and prosehttps://link.zhihu.com/?targethttps://www.sublimetext.com/ windows下载链接&#xff1a;Thank You -…

【数据结构算法经典题目刨析(c语言)】使用数组实现循环队列(图文详解)

&#x1f493; 博客主页&#xff1a;C-SDN花园GGbond ⏩ 文章专栏&#xff1a;数据结构经典题目刨析(c语言) 目录 一.题目描述 二.解题思路 1.循环队列的结构定义 2.队列初始化 3.判空 4.判满 5.入队列 6.出队列 7.取队首元素 8.取队尾元素 三.完整代码实…

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task03笔记 原神风格Lora尝试 ComfyUI Lora微调 补充选学内容

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task03笔记 原神风格Lora尝试 ComfyUI Lora微调 首先我们继续推进网课进度。 https://space.bilibili.com/1069874770 传送门 WorldArt锦书产品介绍&#xff1a; 我属实是没想到这个产品居然还可以用作遗迹鉴定和名家笔记仿写这样…

2.2算法的时间复杂度与空间复杂度——经典OJ

本博客的OJ标题均已插入超链接&#xff0c;点击可直接跳转~ 一、消失的数字 1、题目描述 数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗&#xff1f; 2、题目分析 &#xff08;1&#xff09;numsS…

Java流程控制之循环结构(附案例说明)超详细

循环结构&#xff1a;根据循环条件&#xff0c;重复性执行某段代码 for循环 while 循环 do-while 循环 凡是循环 就有4个要素&#xff1a; 1、初始化要素2、循环条件&#xff08;一定是boolean类型的变量或表达式&#xff09; 3、循环体 4、迭代部分 for 循环格式 for(1;2;…

阿里声音项目Qwen2-Audio的部署安装,在服务器Ubuntu22.04系统——点动科技

阿里声音项目Qwen2-Audio的部署安装&#xff0c;在服务器Ubuntu22.04系统——点动科技 一、ubuntu22.04基本环境配置1.1 更换清华Ubuntu镜像源1.2 更新包列表&#xff1a;2. 安装英伟达显卡驱动2.1 使用wget在命令行下载驱动包2.2 更新软件列表和安装必要软件、依赖2.2 卸载原有…

JAVA学习之知识补充(下)

六&#xff1a;File类与IO流&#xff1a; 这里给出三种常见的初始化方法&#xff1a; 通过文件路径初始化: File file new File("C:/example/test.txt");这种方法用于创建一个文件对象&#xff0c;该文件对象表示指定路径的文件或目录。例如&#xff1a;File fil…

Zookeeper服务注册及心跳机制详解

ZooKeeper提供了一种类似于文件目录的结构来保存key值&#xff0c;其提供了四种key类型&#xff0c;分别是持久节点&#xff0c;临时节点&#xff0c;持久有序节点&#xff0c;临时有序节点。其中临时节点的特性是当创建此节点的会话断开时&#xff0c;节点也会被删除。这一特性…

xss.function靶场(easy)

文章目录 第一关Ma Spaghet!第二关Jefff第三关Ugandan Knuckles第四关Ricardo Milos第五关Ah Thats Hawt第六关Ligma第七关Mafia第八关Ok, Boomer 网址&#xff1a;https://xss.pwnfunction.com/ 第一关Ma Spaghet! 源码 <!-- Challenge --> <h2 id"spaghet&qu…

一文掌握 Web 测试:功能、界面、兼容与安全的综合测试指南!

随着Web技术的不断演进&#xff0c;测试除了对应用的功能性、界面美观性、跨平台兼容性的基本要求外、安全性和性能的要求也逐步增高。因此&#xff0c;全面、系统的测试思维和策略成为了保证Web应用高质量的关键因素。本篇文章将从功能测试、界面测试、兼容性测试和安全测试四…

AI歌手-五月天(声音转换)

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…

JavaScript - 数组对象中实用好玩的reduce方法

JavaScript中reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行)&#xff0c;将其结果汇总为单个返回值。 语法&#xff1a; arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) 参数配置&#xff1a; 参数名描述cal…

系列:水果甜度个人手持设备检测-github等开源库和方案

系列:水果甜度个人手持设备检测 -- github等开源库和方案 概述 通常来说&#xff0c;年纪轻轻的我们一般都喜欢走捷径&#xff0c;对于智能设备和算法软件领域来说&#xff0c;GitHub应该算为数不多的的捷径之一。就算因为效果不好/知识产权/方向不同等原因不用&#xff0c;…

XML外部实体注入

1.DTD实体及引用 DTD(文档类型定义)是一种用于定义XML文档结构和元素约束的方法。它可以描述一个XML文档的元素、属性、实体、注释等&#xff0c;从而规定了文档的结构和语法规则。DTD 通常是一个单独的文件&#xff0c;可以被多个XML文档所共享。 而在DTD中&#xff0c;实体…