【数据结构】图论——Prim算法和Kruskal算法

目录

  • Prim算法和Kruskal算法
    • Prim算法的原理
      • 数据结构
      • 算法步骤解释
      • 算法实现
      • 代码示例
    • Kruskal 算法
      • Kruskal算法的原理和步骤
      • Kruskal算法的实现
        • 数据结构
        • 并查集操作
        • Kruskal算法

Prim算法和Kruskal算法

文章: 【数据结构】图论(图的储存方式,图的遍历算法DFS和BFS、图的遍历算法的应用、图的连通性问题)

Prim算法的原理

  1. 初始化:从图中的一个起始顶点开始,逐步将权值最小的边添加到生成树中。
  2. 扩展生成树:在每一步中,选择当前生成树中所有顶点到生成树外所有顶点中权值最小的一条边,并将该边和对应的顶点加入生成树。
  3. 重复上述步骤:直到所有顶点都包含在生成树中。

数据结构

图采用邻接矩阵邻接表存放均可。下面以邻接矩阵为例实现Prim算法:

  • 图的表示:用一个二维数组arcs表示图的邻接矩阵,arcs[i][j]表示顶点i到顶点j之间的边的权值。vexnum表示图的顶点数,arcnum表示边的数量。
  • 边的类型EdgeType结构体用于存放每个顶点到生成树中顶点的最小权值边的信息。adjvex表示这条边连接的另一个顶点,lowcost表示这条边的权值。
#define MAX 100
#define MAXEDGE 1000000typedef struct {int arcs[MAX][MAX];int vexnum, arcnum;
} AGraphs;typedef struct {int adjvex; // 与生成树中的点连接的最好情况,记录的是与生成树中的哪个点(记录的是点的位置)int lowcost; // 记录的是该最好情况的弧的权重
} EdgeType;EdgeType closedge[MAX]; // 采用一维数组closedge[MAX]存放图中每个顶点与生成树中顶点相连的最好情况

算法步骤解释

  1. 初始化closedge数组
void prim(AGraphs G, int u) {int i, j, k;EdgeType closedge[MAX];for (j = 0; j < G.vexnum; j++) {closedge[j].adjvex = u; // 此次选中的与生成树中连接情况最好的点的位置closedge[j].lowcost = G.arcs[u][j]; // 记录下来这个数值的大小}closedge[u].lowcost = 0; // 如果顶点已经包含在生成树中,则lowcost设为0。
  1. 逐步扩展生成树
    for (i = 1; i < G.vexnum; i++) {k = minclosedge(closedge);printf("(%d,%d)\n", closedge[k].adjvex, k);closedge[k].lowcost = 0;for (j = 0; j < G.vexnum; j++) {if (G.arcs[k][j] < closedge[j].lowcost) {closedge[j].lowcost = G.arcs[k][j];//选中closedge[j].adjvex = k; //选中}}}
}
  1. 找最小权值边
int minclosedge(EdgeType closedge[]) {int min = MAXEDGE, j, k = -1;for (j = 0; j < G.vexnum; j++) {if (closedge[j].lowcost != 0 && closedge[j].lowcost < min) {min = closedge[j].lowcost; //选中k = j;}}return k;
}

算法实现

每一步只保留不在生成树中的点和生成树相连的最好情况

实现算法时,在每一步我们只保留不在生成树中的点生成树相连的最好情况,而不是考察不在生成树中的点和生成树相连的所有情况。
每次加入一个顶点和一条边进入生成树后,我们都考察一下不在生成树中的点和生成树中的点相连的最好情况是否被新加入的点更新。

代码示例

#define MAX 100
#define MAXEDGE 1000000typedef struct {int arcs[MAX][MAX];int vexnum, arcnum;
} AGraphs;typedef struct {int adjvex;int lowcost;
} EdgeType;// 采用一维数组closedge[MAX]存放图中每个顶点与生成树中顶点相连的最好情况/*
当顶点v尚未加入生成树时,closedge[v]存放的是v与生成树中的顶点相连的最好情况:
v与生成树中的顶点的所有连边中权值最小的那条边;
closedge[v].adjvex存放的这条权值最小的边的另一个顶点,
closedge[v].lowcost存放的这条权值最小的边的权值。如何区分生成树中的顶点和不在生成树中的顶点呢?closedge[w].lowcost==0表示w已经加入生成树
*/void prim(AGraphs G, int u) {int i, j, k;EdgeType closedge[MAX];for (j = 0; j < G.vexnum; j++) {closedge[j].adjvex = u; // 此次选中的与生成树中连接情况最好的点的位置closedge[j].lowcost = G.arcs[u][j]; // 记录下来这个数值的大小}closedge[u].lowcost = 0; // 如果顶点已经包含在生成树中,则lowcost设为0。for (i = 1; i < G.vexnum; i++) {k = minclosedge(closedge);printf("(%d,%d)\n", closedge[k].adjvex, k);closedge[k].lowcost = 0;for (j = 0; j < G.vexnum; j++) {if (G.arcs[k][j] < closedge[j].lowcost) {closedge[j].lowcost = G.arcs[k][j];closedge[j].adjvex = k;}}}
}int minclosedge(EdgeType closedge[]) {int min = MAXEDGE, j, k = -1;for (j = 0; j < G.vexnum; j++) {if (closedge[j].lowcost != 0 && closedge[j].lowcost < min) {min = closedge[j].lowcost;k = j;}}return k;
}// 时间复杂度:O(n^2) Prim算法适合于稠密图

画图求解:

在这里插入图片描述
时间复杂度: O ( n 2 ) O(n^2) O(n2)
Prim算法适合于稠密图

问法
最小生成树的求解过程
文字叙述 画表 求解过程
伪码描述(上述程序)

Kruskal 算法

先排序,对所有边按照权值升序排序
从小开始加,只要不产生回路,最后加到 n − 1 n-1 n1
需要 排序(适合于吸收图)

Kruscal算法适合稀疏图,时间复杂度为O(eloge),e为图的边数,因为该算法要对边按照权值排序,(堆、快速。归并)排序算法的平均时间复杂度O(eloge)

Kruskal算法是一种用于查找加权无向图的最小生成树(MST)的贪心算法。它通过逐步选择权值最小的边并确保不会形成环来构建最小生成树。下面详细描述Kruskal算法的实现过程:

Kruskal算法的原理和步骤

  1. 初始化

    • 创建一个包含所有图中顶点的集合,每个顶点初始时在不同的集合中。
    • 初始化最小生成树为空。
  2. 排序

    • 将图中的所有边按权值从小到大排序。
  3. 逐步构建生成树

    • 依次检查排序后的每一条边,如果该边连接的两个顶点位于不同的集合中,则将这条边加入最小生成树,并合并这两个顶点所在的集合。
    • 如果该边连接的两个顶点已经在同一集合中,则跳过这条边,以避免形成环。
  4. 终止条件

    • 当最小生成树包含的边数等于图中顶点数减一时,算法终止。

Kruskal算法的实现

为了实现Kruskal算法,需要使用**并查集(Disjoint Set Union, DSU)**数据结构来管理和合并顶点集合,并检查是否会形成环。

以下是Kruskal算法的详细实现步骤和代码示例:

数据结构
#define MAX 100
#define MAXEDGE 1000000typedef struct {int u, v;  // 边的两个顶点int weight;  // 边的权值
} Edge;typedef struct {Edge edges[MAXEDGE];  // 图中的所有边int vexnum, edgenum;  // 顶点数和边数
} Graph;int parent[MAX];  // 并查集数组
int rank[MAX];    // 并查集的秩数组(用于路径压缩优化)
并查集操作
// 查找操作,带路径压缩
int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];
}// 合并操作,带按秩合并
void unionSet(int x, int y) {int rootX = find(x);int rootY = find(y);if (rootX != rootY) {if (rank[rootX] > rank[rootY]) {parent[rootY] = rootX;} else if (rank[rootX] < rank[rootY]) {parent[rootX] = rootY;} else {parent[rootY] = rootX;rank[rootX]++;}}
}
Kruskal算法
// 边的比较函数,用于排序
int cmp(const void* a, const void* b) {Edge* edgeA = (Edge*)a;Edge* edgeB = (Edge*)b;return edgeA->weight - edgeB->weight;
}// Kruskal算法
void kruskal(Graph G) {int i;Edge result[MAX];  // 用于存储最小生成树中的边int e = 0;  // 最小生成树中的边数// 初始化并查集for (i = 0; i < G.vexnum; i++) {parent[i] = i;rank[i] = 0;}// 按边的权值排序qsort(G.edges, G.edgenum, sizeof(Edge), cmp);for (i = 0; i < G.edgenum; i++) {Edge nextEdge = G.edges[i];int x = find(nextEdge.u);int y = find(nextEdge.v);// 如果这条边不会形成环if (x != y) {result[e++] = nextEdge;  // 将边加入结果中unionSet(x, y);  // 合并两个顶点的集合}}// 打印最小生成树printf("Following are the edges in the constructed MST:\n");for (i = 0; i < e; i++) {printf("%d -- %d == %d\n", result[i].u, result[i].v, result[i].weight);}
}
  1. 数据结构:定义了图结构体和边结构体,用于存储图中的所有边。并查集用于管理顶点集合。
  2. 并查集操作:定义了并查集的查找和合并操作,用于判断是否会形成环。
  3. 排序:对所有边按权值进行排序。
  4. 构建最小生成树:依次检查每条边,使用并查集判断是否会形成环。如果不会,则将边加入最小生成树,并合并顶点集合。
  5. 输出结果:打印最小生成树中的所有边。

Kruskal算法通过边的排序和并查集的使用,实现了高效的最小生成树构建过程。该算法适用于稀疏图,因为它主要操作的是边而不是顶点。

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

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

相关文章

Linux.用户

使用su - 切换用户 切换root时要输入密码&#xff0c;但是看不到 创建用户组 groupadd用户组名&#xff0c;用getent查看有哪些组 getent group 创建用户 在root身份中使用gentent passwd 可以查当前的用户信息 使用getent group查看有哪些组 使用chmod修改权限 快捷方法…

【算法速查】万字图解带你快速入门八大排序(下)

君兮_的个人主页 即使走的再远&#xff0c;也勿忘启程时的初心 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;首先在这里祝大家中秋国庆双节同乐&#xff01;&#xff01;抓住假期的小尾巴&#xff0c;今天来把算法速查的八大排序的后续写完&#xff0c;当…

【网络技术】【Kali Linux】Wireshark嗅探(十六)TLS(传输层安全协议)报文捕获及分析

往期 Kali Linux 上的 Wireshark 嗅探实验见博客&#xff1a; 【网络技术】【Kali Linux】Wireshark嗅探&#xff08;一&#xff09;ping 和 ICMP 【网络技术】【Kali Linux】Wireshark嗅探&#xff08;二&#xff09;TCP 协议 【网络技术】【Kali Linux】Wireshark嗅探&…

Android下HWC以及drm_hwcomposer普法(下)

Android下HWC以及drm_hwcomposer普法(下) 引言 不容易啊&#xff0c;写到这里。经过前面的普法(上)&#xff0c;我相信童鞋们对HWC和drm_hwcomposer已经有了一定的认知了。谷歌出品&#xff0c;必须精品。我们前面的篇章见分析到啥来了&#xff0c;对了分析到了HwcDisplay::in…

K-POP女团X:IN现身韩K联赛 中场表演令人眼前一亮

本月1日&#xff0c;韩国K-POP女团X:IN参加了在韩国京畿道金浦Solteo足球场举办的金浦FC和全南天龙(Jeonnam Dragons)的韩亚银行K联赛2&#xff08;2024第16轮&#xff09;比赛&#xff0c;并带来了精彩的祝贺表演令人眼前一亮。 女团X:IN在比赛中场休息期间&#xff0c;通过《…

Linux配置定时任务crontab

场景 要求每个小时 定时到/home/threeinf 目录下执行 sh run.sh restart 命令 配置 1. crontab -e 编辑定时任务列表&#xff08;相当于vi /etc/crontab, 就是编辑crontab文件&#xff09; crontab -e 在文件中添加 0 * * * * cd /home/threeinf && sh run.sh re…

特征工程技巧——字符串编码成数字序列

这段时间在参加比赛&#xff0c;发现有一些比赛上公开的代码&#xff0c;其中的数据预处理步骤值得我们参考。 平常我们见到的都是数据预处理&#xff0c;现在我们来讲一下特征工程跟数据预处理的区别。 数据预处理是指对原始数据进行清洗、转换、缩放等操作&#xff0c;以便为…

扩散变压器:开创图像生成新纪元

在深度学习领域&#xff0c;变换器&#xff08;Transformer&#xff09;架构已经成为自然语言处理、视觉识别等多个领域的核心技术。最近&#xff0c;一项新的研究探索了基于变换器的一类新型扩散模型——扩散变压器&#xff08;Diffusion Transformers&#xff0c;简称DiTs&am…

VMware Workstation Pro 免费正版安装指南(非常详细)零基础入门到精通,收藏这一篇就够了

随着博通公司在2023年11月对VMware的收购和产品策略的调整&#xff0c;VMware宣布取消“永久许可证”并转向订阅制&#xff0c;这一改变引发了用户的不满。然而&#xff0c;在2024年5月14日&#xff0c;VMware发布了一个令人振奋的消息&#xff0c;宣布为个人用户免费提供两款桌…

Java编程常见问题汇总二

系列文章目录 文章目录 系列文章目录前言一、请使用XML解析器二、请使用JDom组装XML三、XML编码陷阱四、未指定字符编码五、未对数据流进行缓存 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击…

跨平台,不需要下载的串口调试助手

在线串口调试助手是BBAIoT旗下的首款物联网工具&#xff0c;web端显示&#xff0c;不需要下载任何软件到电脑&#xff0c;方便快捷。 在线串口调试 链接地址&#xff1a;在线串口调试在线串口调试助手 Online serial port debugging assistanthttps://www.bbaiot.com/ 软件界…

重新定义你的上网体验,微软WowTab助你一臂之力!

大家好&#xff0c;我是 Java陈序员。 浏览器是我们日常生活工作中必备的工具软件&#xff0c;使用非常频繁。 目前很多浏览器的新标签页虽然说功能齐全&#xff0c;但是充斥着广告和各种无效的信息&#xff0c;十分影响体验&#xff01; 今天&#xff0c;给大家安利一个浏览…

常用ai模型和一些术语的科普

本文是早年浏览easyai.tech后留下的笔记。 文章目录 神经网络CNNRNNGANKNNCPU和GPU/TPUNLPNo free lunch theoremtransformer注意力机制自动编码器&#xff0c;自编码器GNN推荐系统附录NFL的两个例子 神经网络 水流&#xff0c;水龙头&#xff0c;流量阀。 可以回想CNN分类MNI…

软件磁盘阵列与LVM

一、软件磁盘阵列 磁盘阵列&#xff08;RAID&#xff09;是通过硬件或软件技术将多个较小的磁盘整合成为一个较大的磁盘设备&#xff0c;而这个较大的磁盘除了存储还具备数据保护功能。 RAID分不同的级别&#xff0c;不同级别具有不同功能&#xff1a; 1、RAID 0&#xff1a;…

调用阿里云智能云实现垃圾分类

目录 1. 作者介绍2. API3. 阿里云API垃圾分类业务4. 实验过程4.1 接入阿里云4.2 创建并获取AccessKey ID和Secret4.3 登录阿里云官网&#xff0c;搜索垃圾分类技术文档4.4 配置环境变量4.5 代码部分 1. 作者介绍 孙作正&#xff0c;男&#xff0c;西安工程大学电子信息学院&am…

初中英语优秀作文分析-003My Favorite Movie Type-我最喜欢的电影类型

PDF格式公众号回复关键字:SHCZYF003 记忆树 1 I’d like to share my favorite movie type with you. 翻译 我想和你分享我最喜欢的电影类型。 简化记忆 电影类型 句子结构 I 主语 我&#xff0c;would 情态动词 愿意做某事&#xff0c;like 谓语 喜欢&#xff0c;to sha…

docker部署skywalking

skywalking版本下载 1&#xff1a;拉取skywalking的oap镜像(可以选择自己的版本&#xff0c;最好与ui&#xff0c;agent版本一致) docker pull apache/skywalking-oap-server:9.5.02&#xff1a;启动oap docker run -d -p 11800:11800 -p 12800:12800 --name sw_oap apache/…

蓝桥杯物联网竞赛_STM32L071_19_输出方波信号(PWM)

国赛考了一个方波&#xff0c;第一次考这个&#xff0c;连个示波器都没有 CUBMX配置&#xff1a; 按上述配置刚好是32MHZ / 32 / 100 1KHZ 理论&#xff1a; 频率&#xff1a;就是一秒钟能产生多少个脉冲&#xff0c;如下图: 这算是一个脉冲&#xff0c;1KHZ说明一秒钟产生1…

STM32使用HAL库UART接收不定长数据-1

使用STM32的HAL库实现UART串口不定长数据的接收 使用STM32的UART接收数据的时候&#xff0c;经常会遇到接收长度不固定的数据&#xff0c;比如一帧数据可能是10个字节&#xff0c;也可能是12个字节。这种数据称为不定长数据。 现有的很多通信协议是不定长的&#xff0c;比如mo…

Docker大学生看了都会系列(一、Docker介绍)

系列文章目录 第一章 Docker介绍 第二章 2.1 Mac通过Homebrew安装Docker 第二章 2.2 CentOS安装Docker 文章目录 前言Docker容器简介什么是Docker容器为什么要用Docker容器Docker容器的特性Docker容器对比VM(虚拟机)Docker容器三大组成要素镜像容器镜像仓库 Docker容器运行流程…