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

相关文章

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测

pytorch自动求梯度autograd的实现

《pytorch自动求梯度autograd的实现》autograd是一个自动微分引擎,它可以自动计算张量的梯度,本文主要介绍了pytorch自动求梯度autograd的实现,具有一定的参考价值,感兴趣... autograd是pytorch构建神经网络的核心。在 PyTorch 中,结合以下代码例子,当你

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

OpenCV图像形态学的实现

《OpenCV图像形态学的实现》本文主要介绍了OpenCV图像形态学的实现,包括腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算和黑帽运算,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起... 目录一、图像形态学简介二、腐蚀(Erosion)1. 原理2. OpenCV 实现三、膨胀China编程(

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT