【数据结构】最小生成树(Prim算法、Kruskal算法)解析+完整代码

5.1 最小生成树

  • 定义

    对一个带权连通无向图 G = ( V , E ) G=(V,E) G=(V,E),生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。

    设R为G的所有生成树的集合,若T为R中边的权值之和最小的生成树,则T称为G的最小生成树(MST)。

  • 性质

    1.最小生成树可能有多个,但边的权值之和总是唯一且最小的;

    2.最小生成树的边数=顶点数-1。砍掉一条则不连通,增加一条会出现回路;

    3.如果一个连通图本身就是一棵树,则其最小生成树就是它本身;

    4.只有连通图才有最小生成树,非连通图只有生成森林。

5.1.1 Prim算法
  • 定义

    从某一个顶点开始构建生成树;

    每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。

    在这里插入图片描述

    • 即选最小权值的结点
  • 时间复杂度

    O ( ∣ V ∣ 2 ) O(|V|^2) O(V2),适用于稠密图(|E|大的)。

  • 算法的实现思想

    • 思路:

      V 0 V_0 V0开始,总共需要n-1轮处理。

      第一轮处理:循环遍历所有个结点,找到lowCast最低的,且还没加入树的顶点。

      再次循环遍历,更新还没加入的各个顶点的lowCast值。

    • 代码步骤:

      1.创建isJoin数组,初始为false,判断结点是否加入树。

      2.创建lowCost数组,用于存储到该结点的最短距离。

      3.从 v 0 v_0 v0开始,将与其连接的权值加入到lowCost数组中。

      4.遍历lowCast数组,找到最小值,将其加入树中,并继续遍历与其相连的边。

5.1.2 Kruskal算法
  • 定义

    每次选则一条权值最小的边,使这条边的两头连通(原本已经连通的不选),直到所有结点都连通。

    • 即每次选最小的边
  • 时间复杂度

    O ( ∣ E ∣ l o g 2 ∣ E ∣ ) O(|E|log_2|E|) O(Elog2E),适用于边稀疏图。

  • 算法的实现思想

    • 思路:

      初始:将各条边按权值排序。

      共执行e轮,每轮判断两个顶点是否属于同一集合,需要 O ( l o g 2 e ) O(log_2e) O(log2e)

5.1.3 最小生成树代码
A.邻接矩阵
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>#define V 5 // 图的顶点数// 找到距离集合最近的顶点
int min_key(int key[], bool mst_set[]) {int min = INT_MAX, min_index;for (int v = 0; v < V; v++) {if (mst_set[v] == false && key[v] < min) {min = key[v];min_index = v;}}return min_index;
}// 打印最小生成树
void print_mst(int parent[], int graph[V][V]) {printf("Edge   Weight\n");for (int i = 1; i < V; i++)printf("%d - %d    %d \n", parent[i], i, graph[i][parent[i]]);
}// Prim算法
void prim_mst(int graph[V][V]) {int parent[V]; // 存放最小生成树的父节点int lowCost[V];    // 用于存放顶点到最小生成树的最小权重bool isJoin[V]; // 记录顶点是否已经加入最小生成树for (int i = 0; i < V; i++) {lowCost[i] = INT_MAX;isJoin[i] = false;}lowCost[0] = 0; // 初始点为0parent[0] = -1; // 根节点没有父节点for (int count = 0; count < V - 1; count++) {int u = min_key(lowCost, isJoin);isJoin[u] = true;for (int v = 0; v < V; v++) {if (graph[u][v] && !isJoin[v] && graph[u][v] < lowCost[v]) {parent[v] = u;lowCost[v] = graph[u][v];}}}print_mst(parent, graph);
}// Kruskal算法// 结构体用于表示边
struct Edge {int src, dest, weight;
};// 比较函数,用于排序
int compare(const void* a, const void* b) {return ((struct Edge*)a)->weight - ((struct Edge*)b)->weight;
}// 查找函数,用于查找集合的根节点
int find(int parent[], int i) {if (parent[i] == -1)return i;return find(parent, parent[i]);
}// 合并函数,用于合并两个集合
void Union(int parent[], int x, int y) {int xset = find(parent, x);int yset = find(parent, y);parent[xset] = yset;
}// Kruskal算法
void kruskal_mst(int graph[V][V]) {struct Edge result[V]; // 用于存放最小生成树的边int e = 0; // 表示result数组中的边数int i = 0; // 表示当前考虑的边// 边集合struct Edge edges[V*V];for (int u = 0; u < V; u++) {for (int v = u + 1; v < V; v++) {if (graph[u][v] != 0) {edges[e].src = u;edges[e].dest = v;edges[e].weight = graph[u][v];e++;}}}// 根据权重对边进行排序qsort(edges, e, sizeof(edges[0]), compare);int parent[V]; // 用于记录每个顶点的父节点for (int v = 0; v < V; v++)parent[v] = -1;// 最小生成树的边数小于V-1时继续while (i < V - 1 && e > 0) {struct Edge next_edge = edges[--e];// 检查是否会产生环int x = find(parent, next_edge.src);int y = find(parent, next_edge.dest);if (x != y) {result[i++] = next_edge;Union(parent, x, y);}}printf("Edge   Weight\n");for (int i = 0; i < V - 1; i++)printf("%d - %d    %d \n", result[i].src, result[i].dest, result[i].weight);
}// 测试主函数
int main() {int graph[V][V] = {{0, 2, 0, 6, 0},{2, 0, 3, 8, 5},{0, 3, 0, 0, 7},{6, 8, 0, 0, 9},{0, 5, 7, 9, 0}};printf("Prim's Minimum Spanning Tree:\n");prim_mst(graph);printf("\nKruskal's Minimum Spanning Tree:\n");kruskal_mst(graph);return 0;
}

在这里插入图片描述

B.邻接表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>#define MaxVertexNum 100
#define INF 9999typedef struct ArcNode {int adjvex;int weight;struct ArcNode *next;
} ArcNode;typedef struct VNode {int data;ArcNode *first;
} VNode, AdjList[MaxVertexNum];typedef struct {AdjList vertices;int vexnum, arcnum;
} ALGraph;void InitALGraph(ALGraph *G, int vexnum, int arcnum) {G->vexnum = vexnum;G->arcnum = arcnum;for (int i = 0; i < vexnum; i++) {G->vertices[i].data = i;G->vertices[i].first = NULL;}
}void AddEdgeUndirectedALGraph(ALGraph *G, int v1, int v2, int weight) {ArcNode *arcNode1 = (ArcNode *)malloc(sizeof(ArcNode));arcNode1->adjvex = v2;arcNode1->weight = weight;arcNode1->next = G->vertices[v1].first;G->vertices[v1].first = arcNode1;ArcNode *arcNode2 = (ArcNode *)malloc(sizeof(ArcNode));arcNode2->adjvex = v1;arcNode2->weight = weight;arcNode2->next = G->vertices[v2].first;G->vertices[v2].first = arcNode2;
}void PrintALGraph(ALGraph G) {for (int i = 0; i < G.vexnum; i++) {printf("%d -> ", G.vertices[i].data);ArcNode *p = G.vertices[i].first;while (p != NULL) {printf("(%d, %d) ", p->adjvex, p->weight);p = p->next;}printf("\n");}
}// Prim算法
void Prim(ALGraph G) {int lowCost[G.vexnum], parent[G.vexnum];bool inMST[G.vexnum];for (int i = 0; i < G.vexnum; i++) {lowCost[i] = INF;parent[i] = -1;inMST[i] = false;}lowCost[0] = 0;for (int i = 0; i < G.vexnum - 1; i++) {int minIndex, minCost = INF;for (int j = 0; j < G.vexnum; j++) {if (!inMST[j] && lowCost[j] < minCost) {minCost = lowCost[j];minIndex = j;}}inMST[minIndex] = true;ArcNode *p = G.vertices[minIndex].first;while (p != NULL) {if (!inMST[p->adjvex] && p->weight < lowCost[p->adjvex]) {lowCost[p->adjvex] = p->weight;parent[p->adjvex] = minIndex;}p = p->next;}}printf("Edge   Weight\n");for (int i = 1; i < G.vexnum; i++) {printf("%d - %d    %d\n", parent[i], i, lowCost[i]);}
}// Kruskal算法
typedef struct {int src, dest, weight;
} Edge;int find(int parent[], int i) {if (parent[i] == -1)return i;return find(parent, parent[i]);
}void Union(int parent[], int x, int y) {int xset = find(parent, x);int yset = find(parent, y);parent[xset] = yset;
}int compare(const void *a, const void *b) {return ((Edge *)a)->weight - ((Edge *)b)->weight;
}void Kruskal(ALGraph G) {Edge result[G.arcnum];Edge edges[G.arcnum];int parent[G.vexnum];int e = 0;for (int i = 0; i < G.vexnum; i++) {ArcNode *p = G.vertices[i].first;while (p != NULL) {if (i < p->adjvex) {edges[e].src = i;edges[e].dest = p->adjvex;edges[e].weight = p->weight;e++;}p = p->next;}}qsort(edges, G.arcnum, sizeof(Edge), compare);for (int i = 0; i < G.vexnum; i++)parent[i] = -1;int i = 0, j = 0;while (i < G.vexnum - 1 && j < G.arcnum) {Edge next_edge = edges[j++];int x = find(parent, next_edge.src);int y = find(parent, next_edge.dest);if (x != y) {result[i++] = next_edge;Union(parent, x, y);}}printf("Edge   Weight\n");for (int i = 0; i < G.vexnum - 1; i++) {printf("%d - %d    %d\n", result[i].src, result[i].dest, result[i].weight);}
}int main() {ALGraph G;InitALGraph(&G, 5, 7);AddEdgeUndirectedALGraph(&G, 0, 1, 2);AddEdgeUndirectedALGraph(&G, 0, 3, 6);AddEdgeUndirectedALGraph(&G, 1, 2, 3);AddEdgeUndirectedALGraph(&G, 1, 3, 8);AddEdgeUndirectedALGraph(&G, 1, 4, 5);AddEdgeUndirectedALGraph(&G, 2, 4, 7);AddEdgeUndirectedALGraph(&G, 3, 4, 9);PrintALGraph(G);printf("Prim's Minimum Spanning Tree:\n");Prim(G);printf("\nKruskal's Minimum Spanning Tree:\n");Kruskal(G);return 0;
}

在这里插入图片描述

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

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

相关文章

3. uniapp开发工具的一些事

前言 新的一天&#xff0c;又要开始卷起来了&#xff0c;开发程序开发当前离不开开发工具&#xff0c;一个好的开发工具办事起来那必然是事倍功半的...本文主要分享了关于uniapp里开发工具的一些事~ 概述 阅读时间&#xff1a;约5&#xff5e;7分钟&#xff1b; 本文重点&am…

Visual Studio Code基础:打开一个编辑器(文件)时,覆盖了原编辑器

相关阅读 VS codehttps://blog.csdn.net/weixin_45791458/category_12658212.html?spm1001.2014.3001.5482 在使用vscode时&#xff0c;偶尔会出现这样的问题&#xff1a;打开了某个编辑器&#xff08;文件&#xff0c;下面统称文件&#xff09;后&#xff0c;再打开其他文件…

清理Mac电脑中的垃圾文件,让Mac电脑像新的一样好

CleanMyMac是一款流行的Mac系统优化工具&#xff0c;它可以帮助用户清理Mac电脑中的垃圾文件、优化系统性能、管理应用程序、保护隐私和提升电脑运行速度。下面是CleanMyMac的一些主要功能&#xff1a; 系统清理&#xff1a;清除系统缓存、日志文件、语言文件等&#xff0c;释放…

Hotcoin Academy 市场洞察-2024年4月15日-21日

加密货币市场表现 BTC ETF在本周出现净流出&#xff0c;大盘有较大跌幅&#xff0c;BTC一度跌破60000美金&#xff0c;ETH一度跌破2800美金&#xff0c;整体以横盘为主&#xff0c;行情在周末有略微回升趋势。BTC市占率创21年4月来新高&#xff0c;目前市值1.28万亿&#xff0c…

图片浏览工具-Honeyview

一、软件特点 轻量而快速 可以显示包括 GPS 信息在内的 JPEG 格式的 EXIF 信息 对图像格式进行批量转换和调整大小 支持显示 GIF 和 WebP 动图 无需解压即可直接查看压缩包中的图像 二、支持的格式 图像格式: BMP, JPG, GIF, PNG, PSD, DDS, JXR, WebP, J2K, JP2, TGA, TIFF, …

沉浸式翻译 chrome 插件 Immersive Translate - Translate Website PDF

免费翻译网站&#xff0c;翻译PDF和Epub电子书&#xff0c;双语翻译视频字幕 &#x1f4e3; 网络上口碑爆炸的网站翻译扩展工具【沉浸式翻译】⭐⭐⭐⭐⭐ &#x1f4bb; 功能特点如下&#xff1a; &#x1f4f0; 网站翻译 &#x1f680; 提供双语网站翻译&#xff0c;智能识…

web自动化系列-selenium的基本方法介绍

web自动化 &#xff0c;一个老生常谈的话题 &#xff0c;很多人的自动化之路就是从它开始 。它学起来简单 &#xff0c;但做起来又比较难以驾驭 &#xff1b;它的执行效率慢 、但又是最接近于用户的操作场景 &#xff1b; 1.web自动化中的三大亮点技术 我们先聊聊 &#xff0…

登录rabbitMQ管理界面时浏览器显示要求进行身份验证,与此站点连接不安全解决办法

问题描述 最近在黑马学习rabbitMQ的过程中&#xff0c;在使用docker部署好rabbitMQ后&#xff0c;使用账号为&#xff1a;itcast&#xff0c;密码为&#xff1a;123321 登录的时候浏览器显示了这个问题&#xff0c;如图所示&#xff1a; 当时以为自己需要输入自己的浏览…

Spring Web MVC入门(3)——响应

目录 一、返回静态页面 RestController 和 Controller之间的关联和区别 二、返回数据ResponseBody ResponseBody作用在类和方法的情况 三、返回HTML代码片段 响应中的Content-Type常见的取值&#xff1a; 四、返回JSON 五、设置状态码 六、设置Header 1、设置Content…

【C++】---STL容器适配器之底层deque浅析

【C】---STL容器适配器之底层deque浅析 一、deque的使用二、deque的原理1、deque的结构2、deque的底层结构&#xff08;1&#xff09;deque的底层空间&#xff08;2&#xff09;deque如何支持随机访问、deque迭代器 3、deque的优缺点&#xff08;1&#xff09;deque的优势&…

java基础之java容器-Collection,Map

java容器 java容器分类一. Collection1. List①. ArrayList② . LinkedList③ . Vector 2. Queue队列①. LinkedList②. PriorityQueue 3. Set集合①. HashSet②. TreeSet 二. Map1. HashMap2.TreeMap3. Hashtable java容器分类 java容器分为两大类&#xff0c;分别是Collecti…

探索区块链世界:赋能创新,揭示区块链媒体发稿的影响力-世媒讯

区块链&#xff0c;这个由“区块”和“链”组成的概念&#xff0c;可能在您眼中充满神秘和复杂&#xff0c;但其实甚至无所不在&#xff0c;它正静悄悄地改变着我们日常生活的方方面面&#xff0c;从金融到媒体&#xff0c;从医疗到教育。 我们来揭开区块链的神秘面纱。区块链…

VRRP基础

1.基本概念 VRRP(Virtual Router Redundancy protocol,虚拟路由冗余协议&#xff09; VRRP能够在不改变组网的情况下&#xff0c;将多台路由器虚拟成一个虚拟路由器&#xff0c;通过配置虚拟路由器的IP地址为默认网关&#xff0c;实现网关的备份。 VRRP协议版本为VRRPv2&…

Java多线程基础

Java多线程 文章目录 Java多线程一、线程介绍及相关概念二、创建和启动线程2.1 Thread类的常用结构2.2 创建线程法1&#xff1a;继承Thread类&#xff08;分配线程对象&#xff09;2.3 创建线程法2&#xff1a;实现Runnable接口&#xff08;创建线程的目标对象&#xff09;2.4 …

揭示C++设计模式中的实现结构及应用——行为型设计模式

简介 行为型模式&#xff08;Behavioral Pattern&#xff09;是对在不同的对象之间划分责任和算法的抽象化。 行为型模式不仅仅关注类和对象的结构&#xff0c;而且重点关注它们之间的相互作用。 通过行为型模式&#xff0c;可以更加清晰地划分类与对象的职责&#xff0c;并…

易错知识点(学习过程中不断记录)

快捷键专区&#xff1a; 注释&#xff1a;ctrl/ ctrlshift/ 保存&#xff1a;ctrls 调试&#xff1a; 知识点专区&#xff1a; 1基本数据类型 基本数据类型有四类&#xff1a;整型、浮点型、字符型、布尔型&#xff08;Boolean&#xff09;&#xff0c; 分为八种&#xff…

AI图书推荐:《企业AI转型:如何在企业中部署ChatGPT?》

Jay R. Enterprise AI in the Cloud. A Practical Guide...ChatGPT Solutions &#xff08;《企业AI转型&#xff1a;如何在企业中部署ChatGPT&#xff1f;》&#xff09;是一本由Rabi Jay撰写、于2024年由John Wiley & Sons出版的书籍&#xff0c;主要为企业提供实施AI转型…

2024.4.28

有以下类&#xff0c;完成特殊成员函数 #include <iostream>using namespace std; class Person{string name;int* age; public:Person():name("zhangsan"),age(new int(18)){}Person(string name,int* age):name(name),age(new int(*age)){}~Person(){delete…

接口测试-笔记

Date 2024年4月23日21:19:51 Author KarrySmile 1. 前言 因为想更加规范地开发接口&#xff0c;同时让自己测试接口的时候更加高效&#xff0c;更好地写好接口文档。所以学习黑马的《接口自动化测试》课程。链接&#xff1a;黑马程序员软件测试接口自动化测试全套视频教程&a…

Redis运维篇-快速面试笔记(速成版)

文章目录 1. Redis的持久化1.1 RDB&#xff08;快照模式&#xff09;1.2 AOF 模式 2. Redis主从模型&#xff08;高可用&#xff09;2.1 Redis的主从复制2.2 Redis拓扑结构 3. Redis集群模式&#xff08;高并发&#xff09;3.1 Redis的Slots3.2 集群模式的常用命令3.3 多主多从…