上机实验四 图的最小生成树算法设计 西安石油大学数据结构

实验名称:图的最小生成树算法设计

(1)实验目的:

掌握最小生成树算法,利用kruskal算法求解最小生成树。

(2)主要内容:

利用kruskal算法求一个图的最小生成树,设计Kruskal算法求解邻接矩阵存储结构下图的最小生成树的函数,并以下图为例设计一个主函数进行测试,要求输出最小生成树的各顶点及各边的权值。
在这里插入图片描述

边a-e的权值为1
边a-b的权值为3
边e-b的权值为4
边e-c的权值为6
边e-d的权值为7
边b-c的权值为5
边c-d的权值为2

知识储备

最小生成树(Minimum Spanning Tree,MST)是一种常见的图论算法,用于在一个加权连通图中寻找一棵生成树,使得树的所有边的权值之和最小。其中,Kruskal算法和Prim算法是两种常用的最小生成树算法。

  1. Kruskal算法

    • Kruskal算法是一种贪心算法,它通过将图中的所有边按权值从小到大进行排序,然后逐个考虑这些边,如果加入某条边不会构成环,则将其加入最小生成树中。这样直到最小生成树中包含了图中的所有顶点为止。
    • Kruskal算法适合于稀疏图,即顶点较多而边较少的图。
  2. Prim算法

    • Prim算法也是一种贪心算法,它从一个初始顶点开始,逐步长出最小生成树。在每一步中,选择与当前最小生成树相邻且权值最小的边所连接的顶点,并将该顶点加入最小生成树中。
    • Prim算法适合于稠密图,即顶点较少而边较多的图。

这两种算法都可以求解最小生成树,选择哪种算法取决于具体的应用场景和图的特点。在实际应用中,可以根据图的规模、边的数量、以及算法实现的难易程度等因素来选取合适的算法。

下面是使用C语言实现Kruskal算法来求解最小生成树的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义边的数据结构
struct Edge {int src, dest, weight;
};// 定义图的数据结构
struct Graph {int V, E; // 顶点数和边数struct Edge* edge; // 边的数组
};// 创建一个图
struct Graph* createGraph(int V, int E) {struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph));graph->V = V;graph->E = E;graph->edge = (struct Edge*)malloc(graph->E * sizeof(struct Edge));return graph;
}// 查找包含顶点v的子集的根节点
int find(int parent[], int v) {if (parent[v] == -1)return v;return find(parent, parent[v]);
}// 将两个子集进行合并
void Union(int parent[], int x, int y) {int xroot = find(parent, x);int yroot = find(parent, y);parent[xroot] = yroot;
}// 实现Kruskal算法
void kruskalMST(struct Graph* graph) {int V = graph->V;struct Edge result[V]; // 存储最小生成树的结果int e = 0; // 用于结果数组的索引int i = 0; // 用于排序边的索引// 按权重对所有边进行排序qsort(graph->edge, graph->E, sizeof(graph->edge[0]), [](const void* a, const void* b) {struct Edge* a1 = (struct Edge*)a;struct Edge* b1 = (struct Edge*)b;return a1->weight > b1->weight;});int *parent = (int*)malloc(V * sizeof(int));memset(parent, -1, V * sizeof(int));// 将边加入最小生成树中,直到最小生成树中有V-1条边while (e < V - 1 && i < graph->E) {struct Edge next_edge = graph->edge[i++];int x = find(parent, next_edge.src);int y = find(parent, next_edge.dest);if (x != y) {result[e++] = next_edge;Union(parent, x, y);}}// 打印最小生成树的边及权重printf("Edge \tWeight\n");for (i = 0; i < e; i++)printf("%d - %d \t%d \n", result[i].src, result[i].dest, result[i].weight);
}int main() {int V = 4; // 顶点数int E = 5; // 边数struct Graph* graph = createGraph(V, E);// 添加边的权重信息graph->edge[0].src = 0;graph->edge[0].dest = 1;graph->edge[0].weight = 10;graph->edge[1].src = 0;graph->edge[1].dest = 2;graph->edge[1].weight = 6;graph->edge[2].src = 0;graph->edge[2].dest = 3;graph->edge[2].weight = 5;graph->edge[3].src = 1;graph->edge[3].dest = 3;graph->edge[3].weight = 15;graph->edge[4].src = 2;graph->edge[4].dest = 3;graph->edge[4].weight = 4;// 使用Kruskal算法求解最小生成树kruskalMST(graph);return 0;
}

在这个示例中,我们定义了结构体Edge来表示边,并使用结构体Graph来表示图。在main函数中,我们创建了一个包含四个顶点和五条边的图,并使用Kruskal算法来求解最小生成树,然后打印出最小生成树的边及权重。

  • 这段C语言代码实现了Kruskal算法来求解最小生成树。让我来解释一下主要的步骤和代码逻辑:
    1. 首先定义了表示边的结构体Edge,包括边的起点、终点和权重;定义了表示图的结构体Graph,包括顶点数、边数和边的数组。
    1. 创建图的函数createGraph用于动态分配内存并初始化一个图的结构体。
    1. 实现了find函数和Union函数来进行并查集操作,用于判断两个顶点是否连通以及合并不同的连通分量。
    1. kruskalMST函数实现了Kruskal算法的核心逻辑。首先对所有边按照权重进行排序,然后遍历排序后的边数组,依次加入到最小生成树中,直到最小生成树中有V-1条边为止。在加入边的过程中,使用并查集来判断是否形成环路,从而保证最小生成树的连通性。
    1. main函数中创建一个包含四个顶点和五条边的图,并手动设置每条边的起点、终点和权重。然后调用kruskalMST函数求解最小生成树,并打印出最小生成树的边及权重。
      -总体来说,这段代码通过实现Kruskal算法的关键步骤,使用并查集来维护最小生成树的连通性,以及对边进行排序和筛选,最终得到了输入图的最小生成树。希望以上解释能够帮助你理解这段代码的实现原理。

以下是基于邻接矩阵存储结构的 Kruskal 算法的 C 语言代码,用于找到图的最小生成树。在这个例子中,我将使用您提供的图来测试最小生成树的算法。

问题描述

  1. 将图中的所有边按照权值从小到大进行排序。
  2. 依次遍历排序后的边,如果当前考虑的边连接的两个顶点不在同一个连通分量中,则将该边加入最小生成树中,并合并这两个顶点所在的连通分量。
  3. 重复步骤2,直到最小生成树中有n-1条边为止(n为顶点数)。

基本要求

  1. 输入:从标准输入或文件中读取图的顶点数、边数以及各条边的起点、终点和权值。
  2. 输出:将最小生成树的每条边及其权值输出到标准输出或文件中。
    正确性:确保程序能够正确地找到给定图的最小生成树。
  3. 效率:保证算法的时间复杂度在合理范围内,尽量提高程序的执行效率。

算法思想

Kruskal算法是一种用来寻找最小生成树的贪心算法。最小生成树是指在一个连通的无向图中找到一棵包含图中所有顶点的生成树,并且使得这棵树的边的权重之和尽可能小。

Kruskal算法的主要思想是通过不断地选择图中权重最小的边,并且保证不形成环路,逐步构建最小生成树。具体来说,算法按照边的权重从小到大的顺序进行处理,每次选择一条权重最小的边,如果这条边连接了两个不在同一个连通分量中的顶点,那么就将这条边加入最小生成树中,并且合并这两个连通分量,直到最小生成树中包含了图中所有的顶点为止。

模块划分

这段代码可以划分为几个功能模块:

  1. 数据结构定义模块:

    • 定义了表示图中边的数据结构 Edge;
    • 定义了表示整个图的数据结构 Graph。
  2. 并查集相关函数模块:

    • makeSet(int x):初始化并查集,将顶点x作为一个单独的集合;
    • findSet(int x):查找顶点x所在集合的根节点,采用路径压缩;
    • unionSet(int x, int y):合并包含顶点x和顶点y的两个集合。
  3. 辅助函数模块:

    • swap(Edge* a, Edge* b):交换两条边的函数;
    • sortEdges(Graph* graph):对图中的边按权重进行排序。
  4. Kruskal算法实现模块:

    • kruskal(Graph* graph):使用Kruskal算法寻找最小生成树。

在文件组织结构上,可以将这些函数放在同一个源文件中,比如 kruskal.c,然后在主程序文件中调用这些函数即可。当然,也可以根据需要将这些函数分别放在不同的文件中,并通过头文件来进行声明和引用。例如,可以创建 graph.hgraph.c 来存放数据结构定义和相关操作函数,以及 kruskal.hkruskal.c 来存放Kruskal算法实现相关的函数。

数据结构

边的数据结构 Edge:

用于表示图中的一条边,包括这条边连接的两个顶点(u, v)以及边的权重。
在代码中被定义为一个结构体,包括三个整型成员 u、v 和 weight。
图的数据结构 Graph:

用于表示整个图,包括图中顶点数 n、边数 m,以及边的具体信息。
在代码中被定义为一个结构体,包括两个整型成员 n 和 m,以及一个 Edge 类型的数组 edges。

#include <stdio.h>
#include <stdlib.h>#define MAX_EDGES 100
#define MAX_VERTICES 100// 表示图中的一条边
typedef struct {int u, v, weight;  // 边的两个顶点及权重
} Edge;// 表示整个图
typedef struct {int n, m;  // 图中顶点数和边数Edge edges[MAX_EDGES];  // 图中的边
} Graph;int parent[MAX_VERTICES];  // 并查集的父节点数组// 初始化并查集,将顶点x作为一个单独的集合
void makeSet(int x) {parent[x] = x;
}// 查找顶点x所在集合的根节点,采用路径压缩
int findSet(int x) {while (x != parent[x]) {x = parent[x];}return x;
}// 合并包含顶点x和顶点y的两个集合
void unionSet(int x, int y) {int rootX = findSet(x);int rootY = findSet(y);parent[rootX] = rootY;
}// 交换两条边的函数
void swap(Edge* a, Edge* b) {Edge t = *a;*a = *b;*b = t;
}// 对图中的边按权重进行排序
void sortEdges(Graph* graph) {int i, j;for (i = 0; i < graph->m - 1; i++) {for (j = 0; j < graph->m - i - 1; j++) {if (graph->edges[j].weight > graph->edges[j + 1].weight) {swap(&graph->edges[j], &graph->edges[j + 1]);}}}
}// 使用Kruskal算法寻找最小生成树
void kruskal(Graph* graph) {int i, totalWeight = 0;for (i = 0; i < graph->n; i++) {makeSet(i);  // 初始化每个顶点为一个单独的集合}sortEdges(graph);  // 对边按权重进行排序printf("Minimum Spanning Tree:\n");for (i = 0; i < graph->m; i++) {int rootU = findSet(graph->edges[i].u);  // 查找边的两个顶点所在集合的根节点int rootV = findSet(graph->edges[i].v);if (rootU != rootV) {  // 如果两个顶点不在同一个集合中,说明加入这条边不会形成环路printf("Edge %c-%c: %d\n", 'a' + graph->edges[i].u, 'a' + graph->edges[i].v, graph->edges[i].weight);  // 输出该边totalWeight += graph->edges[i].weight;  // 累加总权重unionSet(rootU, rootV);  // 将这两个顶点所在集合合并}}printf("Total Weight: %d\n", totalWeight);  // 输出最小生成树的总权重
}int main() {// 创建一个包含5个顶点和7条边的图Graph graph = {5, 7, {{0, 4, 1}, {0, 1, 3}, {4, 1, 4}, {4, 2, 6}, {4, 3, 7}, {1, 2, 5}, {2, 3, 2}}};kruskal(&graph);  // 寻找最小生成树return 0;
}

存在的问题和建议

可能存在的问题:

代码中未进行输入校验,如果输入的图不符合预期格式,可能会导致程序出错。
如果图中存在负权边,Kruskal 算法可能无法得到正确的最小生成树。代码中未对此进行处理。

建议:

可以添加输入校验的部分,确保输入的图符合预期格式。
对于负权边的情况,可以在算法中进行处理,或者在输入时进行限制。

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

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

相关文章

Xilinx Artix7-100T低端FPGA解码MIPI视频,基于MIPI CSI-2 RX Subsystem架构实现,提供工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 MIPI 编解码方案3、本 MIPI CSI2 模块性能及其优缺点4、详细设计方案设计原理框图OV5640及其配置权电阻硬件方案MIPI CSI-2 RX SubsystemSensor Demosaic图像格式转换Gammer LUT伽马校正VDMA图像缓存AXI4-Stream toVideo OutHDMI输出 5、…

数据校验:Spring Validation

Spring Validation概述 在开发中&#xff0c;我们经常遇到参数校验的需求&#xff0c;比如用户注册的时候&#xff0c;要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式&#xff0c;我们会把校验的代码和真正的业务处理逻辑耦…

K8S篇之etcd数据备份与恢复

一、etcd备份与恢复 基本了解&#xff1a; 1、k8s 使用etcd数据库实时存储集群中的数据&#xff0c;安全起见&#xff0c;一定要备份。 2、备份只需要在一个节点上备份就可以了&#xff0c;每个节点上的数据是同步的&#xff1b;但是数据恢复是需要在每个节点上进行。 3、etcd…

系统韧性研究(4)| 系统韧性的技术分类

系统韧性技术是任何提高系统韧性的架构、设计或实现技术。这些技术&#xff08;例如缓解措施&#xff0c;如冗余、保障措施和网络安全对策&#xff09;或被动地抵御逆境或主动检测逆境&#xff0c;并对其做出反应&#xff0c;亦或者从它们造成的伤害中恢复过来。系统韧性技术是…

ArcGIS实现矢量区域内所有要素的统计计算

1、任务需求&#xff1a;统计全球各国所有一级行政区相关属性的总和。 &#xff08;1&#xff09;有一个全球一级行政区的矢量图&#xff0c;包含以下属性&#xff08;洪灾相关属性 province.shp&#xff09; &#xff08;2&#xff09;需要按照国家来统计各个国家各属性的总值…

突然消失的桌面文件如何恢复?详细教程让你轻松解决问题!

桌面文件突然消失&#xff0c;对于很多人来说&#xff0c;可能是个令人头疼的问题。这些文件可能包含重要的信息&#xff0c;也可能是数日甚至数周的努力成果。那么&#xff0c;当这种情况发生时&#xff0c;我们如何恢复丢失的文件呢&#xff1f;本文将提供一些实用的建议。 1…

【ArcGIS Pro微课1000例】0031:las点云提取(根据范围裁剪点云)

本文讲解ArcGIS Pro3.0中,las点云数据的提取(根据范围裁剪点云)方法。 文章目录 一、加载数据二、工具介绍三、点云裁剪一、加载数据 打开ArcGIS Pro,新建地图,加载配套实验数据包中的0031.rar中的点云数据point.las与范围bound.shp,如下图所示: 二、工具介绍 名称:提…

一张图搞懂什么是BCD8421编码

如图所示 BCD8421编码的意义是 用四位二进制数表达一位的十进制数 因此十进制下的0&#xff5e;9在BCD8421编码下与其二进制表达是一样的 而多位的十进制数 比如说“10” 则需要将它拆分成两个单独的数“1”和“0” 分别用BCD8421编码表示这两个数 十进制“1” -> 0001 十进…

内衣洗衣机和手洗哪个干净?好用的内衣洗衣机推荐

在日常生活中&#xff0c;我们的衣服不可避免地会沾染上各种细菌、毛发和污渍&#xff0c;将它们与贴身衣物混合清洗&#xff0c;很容易发生交叉感染&#xff0c;而被感染后&#xff0c;贴身衣物也有可能导致我们人体引起皮肤病。这也是为什么大部分人都喜欢用手洗的原因&#…

@CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思

@CacheInvalidate 注解是 JetCache 框架提供的注解,它是由阿里巴巴开源的组织 Alibaba Group 开发和维护的。JetCache 是一款基于注解的缓存框架,提供了丰富的缓存功能和灵活的配置选项,可用于增强应用程序的性能和可扩展性。JetCache 支持多种缓存后端,包括内存缓存、Redi…

矩阵的除法

B/A 如果矩阵A可逆&#xff0c;那么 证明&#xff1a; A/AB 如果矩阵A和B都可逆&#xff0c;那么 证明&#xff1a;

基于回溯搜索算法优化概率神经网络PNN的分类预测 - 附代码

基于回溯搜索算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于回溯搜索算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于回溯搜索优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

优雅的Java编程:将接口对象作为方法参数

theme: smartblue 目录 概述 在Java编程中&#xff0c;方法的参数传递方式通常是通过基本类型、对象引用或者集合等方式。然而&#xff0c;一种更加优雅且灵活的设计模式是将接口对象作为方法的参数。这种方式为我们带来了许多好处&#xff0c;包括降低耦合性、实现多态性和可…

Jenkins 构建CICD

GitLab GitLab安装 https://gitlab.cn/install/?versionce CentOS 下安装 1. 安装和配置必须的依赖项 在 CentOS 7上&#xff0c;下面的命令也会在系统防火墙中打开 HTTP、HTTPS 和 SSH 访问。这是一个可选步骤&#xff0c;如果您打算仅从本地网络访问极狐GitLab&#xf…

【现场问题】datax中write部分为Oracle的时候插入clolb类型字段,插入的数据为string且长度过场问题

datax的Oraclewriter 报错显示查询报错展示查找datax中的数据插入模块 报错显示 occurred during batching: ORA-01704: string literal too long 查询报错展示 基本上查到的都是这样的&#xff0c;所以锁定是clob的字段类型的问题&#xff0c;而且是只有Oracle出问题&#…

觉非科技发布【轻地图高速NOA智驾方案】|地平线,觉非科技,MobileDrive超捷生态协作实现技术落地

11月10日&#xff0c;2023世界新汽车技术合作生态展期间&#xff0c;觉非科技正式发布了基于地平线征程系列以及MobileDrive超捷规控系统的【轻地图高速NOA智驾解决方案】。该方案首次实现了从芯片能力输出、到数据闭环建设、再到规控部署的产业生态链协作与打通&#xff0c;为…

微信小程序漏洞之accesskey泄露

更新时间&#xff1a;2023年09月08日09:42:52 1. Accesskey泄露漏洞 这篇文章里面都是以我个人的视角来进行的&#xff0c;因为一些原因&#xff0c;中间删了一些东西&#xff0c;肯定有很多不正确的地方&#xff0c;希望大家能理解&#xff0c;也能指正其中的错误。 在以前…

VCR库代码示例

1. 首先&#xff0c;我们需要在代码中添加对VCR库的引用&#xff1a; ruby require vcr require rest-client 2. 然后&#xff0c;我们需要创建一个VCR录制器&#xff0c;以便我们可以记录实际的HTTP请求和响应&#xff1a; ruby VCR.use_cassette(download_video, record:…

虚拟机CentOS 8 重启后不能上网

情况说明&#xff1a;原本虚拟机是可以上网的&#xff0c;然后嘚一下&#xff0c;重启后&#xff0c;连接不上网络&#xff0c;完了&#xff0c;上网查找一堆质料&#xff0c;我的连接方式是桥接模式&#xff08;复制物理网络连接状态&#xff09;。 好&#xff0c;有人说是vmn…

通配符SSL证书

通配符SSL证书是一种特殊的数字证书&#xff0c;用于在互联网上建立安全的连接&#xff0c;其特点是可以保护多个子域名&#xff0c;并且具有很高的兼容性和扩展性。本文将详细介绍通配符SSL证书的相关概念、优点和应用等。 首先&#xff0c;我们需要了解什么是SSL证书。 SSL证…