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实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2