Prim算法的C语言实现(邻接矩阵)

2024-04-06 11:48

本文主要是介绍Prim算法的C语言实现(邻接矩阵),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>#define MAX    100                 // 矩阵最大容量
#define INF    (~(0x1<<31))        // 最大值(即0X7FFFFFFF)
#define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z')))
#define LENGTH(a)   (sizeof(a)/sizeof(a[0]))// 邻接矩阵
typedef struct _graph
{char vexs[MAX];       // 顶点集合int vexnum;           // 顶点数int edgnum;           // 边数int matrix[MAX][MAX]; // 邻接矩阵
}Graph, *PGraph;/*
* 返回ch在matrix矩阵中的位置
*/
static int get_position(Graph g, char ch)
{int i;for (i = 0; i<g.vexnum; i++)if (g.vexs[i] == ch)return i;return -1;
}/*
* 读取一个输入字符
*/
static char read_char()
{char ch;do {ch = getchar();} while (!isLetter(ch));return ch;
}/*
* 创建图(自己输入)
*/
Graph* create_graph()
{char c1, c2;int v, e;int i, j, weight, p1, p2;Graph* pG;// 输入"顶点数"和"边数"printf("input vertex number: ");scanf_s("%d", &v);printf("input edge number: ");scanf_s("%d", &e);if (v < 1 || e < 1 || (e >(v * (v - 1)))){printf("input error: invalid parameters!\n");return NULL;}if ((pG = (Graph*)malloc(sizeof(Graph))) == NULL)return NULL;memset(pG, 0, sizeof(Graph));// 初始化"顶点数"和"边数"pG->vexnum = v;pG->edgnum = e;// 初始化"顶点"for (i = 0; i < pG->vexnum; i++){printf("vertex(%d): ", i);pG->vexs[i] = read_char();}// 1. 初始化"边"的权值for (i = 0; i < pG->vexnum; i++){for (j = 0; j < pG->vexnum; j++){if (i == j)pG->matrix[i][j] = 0;elsepG->matrix[i][j] = INF;}}// 2. 初始化"边"的权值: 根据用户的输入进行初始化for (i = 0; i < pG->edgnum; i++){// 读取边的起始顶点,结束顶点,权值printf("edge(%d):", i);c1 = read_char();c2 = read_char();scanf_s("%d", &weight);p1 = get_position(*pG, c1);p2 = get_position(*pG, c2);if (p1 == -1 || p2 == -1){printf("input error: invalid edge!\n");free(pG);return NULL;}pG->matrix[p1][p2] = weight;pG->matrix[p2][p1] = weight;}return pG;
}/*
* 创建图(用已提供的矩阵)
*/
Graph* create_example_graph()
{char vexs[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };int matrix[][9] = {/*A*//*B*//*C*//*D*//*E*//*F*//*G*//*A*/{ 0, 12, INF, INF, INF, 16, 14 },/*B*/{ 12, 0, 10, INF, INF, 7, INF },/*C*/{ INF, 10, 0, 3, 5, 6, INF },/*D*/{ INF, INF, 3, 0, 4, INF, INF },/*E*/{ INF, INF, 5, 4, 0, 2, 8 },/*F*/{ 16, 7, 6, INF, 2, 0, 9 },/*G*/{ 14, INF, INF, INF, 8, 9, 0 } };int vlen = LENGTH(vexs);int i, j;Graph* pG;// 输入"顶点数"和"边数"if ((pG = (Graph*)malloc(sizeof(Graph))) == NULL)return NULL;memset(pG, 0, sizeof(Graph));// 初始化"顶点数"pG->vexnum = vlen;// 初始化"顶点"for (i = 0; i < pG->vexnum; i++)pG->vexs[i] = vexs[i];// 初始化"边"for (i = 0; i < pG->vexnum; i++)for (j = 0; j < pG->vexnum; j++)pG->matrix[i][j] = matrix[i][j];// 统计边的数目for (i = 0; i < pG->vexnum; i++)for (j = 0; j < pG->vexnum; j++)if (i != j && pG->matrix[i][j] != INF)pG->edgnum++;pG->edgnum /= 2;return pG;
}/*
* 返回顶点v的第一个邻接顶点的索引,失败则返回-1
*/
static int first_vertex(Graph G, int v)
{int i;if (v<0 || v>(G.vexnum - 1))return -1;for (i = 0; i < G.vexnum; i++)if (G.matrix[v][i] != 0 && G.matrix[v][i] != INF)return i;return -1;
}/*
* 返回顶点v相对于w的下一个邻接顶点的索引,失败则返回-1
*/
static int next_vertix(Graph G, int v, int w)
{int i;if (v<0 || v>(G.vexnum - 1) || w<0 || w>(G.vexnum - 1))return -1;for (i = w + 1; i < G.vexnum; i++)if (G.matrix[v][i] != 0 && G.matrix[v][i] != INF)return i;return -1;
}/*
* 深度优先搜索遍历图的递归实现
*/
static void DFS(Graph G, int i, int *visited)
{int w;visited[i] = 1;printf("%c ", G.vexs[i]);// 遍历该顶点的所有邻接顶点。若是没有访问过,那么继续往下走for (w = first_vertex(G, i); w >= 0; w = next_vertix(G, i, w)){if (!visited[w])DFS(G, w, visited);}}/*
* 深度优先搜索遍历图
*/
void DFSTraverse(Graph G)
{int i;int visited[MAX];       // 顶点访问标记// 初始化所有顶点都没有被访问for (i = 0; i < G.vexnum; i++)visited[i] = 0;printf("DFS: ");for (i = 0; i < G.vexnum; i++){//printf("\n== LOOP(%d)\n", i);if (!visited[i])DFS(G, i, visited);}printf("\n");
}/*
* 广度优先搜索(类似于树的层次遍历)
*/
void BFS(Graph G)
{int head = 0;int rear = 0;int queue[MAX];     // 辅组队列int visited[MAX];   // 顶点访问标记int i, j, k;for (i = 0; i < G.vexnum; i++)visited[i] = 0;printf("BFS: ");for (i = 0; i < G.vexnum; i++){if (!visited[i]){visited[i] = 1;printf("%c ", G.vexs[i]);queue[rear++] = i;  // 入队列}while (head != rear){j = queue[head++];  // 出队列for (k = first_vertex(G, j); k >= 0; k = next_vertix(G, j, k)) //k是为访问的邻接顶点{if (!visited[k]){visited[k] = 1;printf("%c ", G.vexs[k]);queue[rear++] = k;}}}}printf("\n");
}/*
* 打印矩阵队列图
*/
void print_graph(Graph G)
{int i, j;printf("Martix Graph:\n");for (i = 0; i < G.vexnum; i++){for (j = 0; j < G.vexnum; j++)printf("%10d ", G.matrix[i][j]);printf("\n");}
}/*
* prim最小生成树
*
* 参数说明:
*       G -- 邻接矩阵图
*   start -- 从图中的第start个元素开始,生成最小树
*/
void prim(Graph G, int start)
{int min, i, j, k, m, n, sum;int index = 0;         // prim最小树的索引,即prims数组的索引char prims[MAX];     // prim最小树的结果数组int weights[MAX];    // 顶点间边的权值// prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。prims[index++] = G.vexs[start];// 初始化"顶点的权值数组",// 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。for (i = 0; i < G.vexnum; i++)weights[i] = G.matrix[start][i];// 将第start个顶点的权值初始化为0。// 可以理解为"第start个顶点到它自身的距离为0"。weights[start] = 0;for (i = 0; i < G.vexnum; i++){// 由于从start开始的,因此不需要再对第start个顶点进行处理。if (start == i)continue;j = 0;k = 0;min = INF;// 在未被加入到最小生成树的顶点中,找出权值最小的顶点。while (j < G.vexnum){// 若weights[j]=0,意味着"第j个节点已经被排序过"(或者说已经加入了最小生成树中)。if (weights[j] != 0 && weights[j] < min){min = weights[j];k = j;}j++;}// 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。// 将第k个顶点加入到最小生成树的结果数组中prims[index++] = G.vexs[k];// 将"第k个顶点的权值"标记为0,意味着第k个顶点已经排序过了(或者说已经加入了最小树结果中)。weights[k] = 0;// 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。for (j = 0; j < G.vexnum; j++){// 当第j个节点没有被处理,并且需要更新时才被更新。if (weights[j] != 0 && G.matrix[k][j] < weights[j])weights[j] = G.matrix[k][j];}}// 计算最小生成树的权值sum = 0;for (i = 1; i < index; i++){min = INF;// 获取prims[i]在G中的位置n = get_position(G, prims[i]);// 在vexs[0...i]中,找出到j的权值最小的顶点。for (j = 0; j < i; j++){m = get_position(G, prims[j]);if (G.matrix[m][n]<min)min = G.matrix[m][n];}sum += min;}// 打印最小生成树printf("PRIM(%c)=%d: ", G.vexs[start], sum);for (i = 0; i < index; i++)printf("%c ", prims[i]);printf("\n");
}void main()
{Graph* pG;// 自定义"图"(输入矩阵队列)//pG = create_graph();// 采用已有的"图"pG = create_example_graph();//print_graph(*pG);       // 打印图//DFSTraverse(*pG);       // 深度优先遍历//BFS(*pG);               // 广度优先遍历prim(*pG, 0);             // prim算法生成最小生成树
}
## 实验结果 ##

这里写图片描述

这篇关于Prim算法的C语言实现(邻接矩阵)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/879820

相关文章

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、