最小生成树问题-prim算法
prim适合稠密图,权值不可为负,不能有回路(保证不重复收录节点即可)
具体图标演示看这个:https://www.cnblogs.com/ssyfj/p/9488723.html
知识点: 1)以其中某一顶点为起点,逐步寻找各个顶点上最小权值的边来构建最小生成树。其中运用到了回溯,贪心的思想。
(一)使用邻接矩阵结构
邻接矩阵定义
1 typedef struct{ 2 VertexType vertex[MaxNum]; //顶点一维数组 3 EdgeType edge[MaxNum][MaxNum];//路径权值二维数组 4 int vexNum,arcNum; //顶点数,弧数 5 }MGraph;
记忆算法过程
void prim(MGraph G) { 定义顶点下标数组a; 定义相关顶点的边权值数组b; 初始化第一个顶点权值为0 ;(权值的元素为0,代表该下标对应的顶点已加入生成树) 初始化顶点数组a首元素为0(顶点v0); 循环操作 将a数组首元素0(顶点v0)的所有边权值放入数组b并初始化顶点数组元 素全部为0 开始进行主旋律 1层循环: (1)循环操作找出目前权值数组b中不为0的最小的那条边 并记录下标为k(此下标代表顶点Vk); 数组b中k位置设为0,即把该条边加入生成树; (2)将第k个顶点的权值与数组b中权值顺序依次比较,如果b中值为0跳过,如果小于b中该顶点(j)权值,则替换权值b【j】=G.arc【k】【j】,并将顶点数组a【j】=k 2层循环 (1)找出目前权值数组b中不为0最小的那条边 并记录下标k1(此下标代表顶点Vk1); 数组b中k1位置设为0,即将该条边加入生成树; (2)将第k1个顶点的权值与数组b中权值顺序依次比较,如果b中值为0跳过,如果小于b中该顶点(j1)权值,则替换权值b【j1】=G.arc【k1】【j1】,并将顶点数组a【j1】=k1 3层循环 (1)找出目前权值数组b中不为0最小的那条边 并记录下标k2(此下标为顶点) 数组b中k2位置设为0,即将该条边加入生成树,根据顶点数组a【k2】输出改点 (2)将第k2个顶点的权值与数组b中权值顺序依次比较,如果b中值为0跳过,如果小于b中该顶点(j2)权值,则替换权值b【j1】=G.arc【k2】【j2】,并将顶点数组a【j2】=k2 。。。。。。。 }
算法实现代码(与迪杰斯特拉算法有异曲同工之妙)
void prim(MGraph G) { int min, i, j, k; int adjvex[MAXV]; //保存相关顶点下标 int lowcost[MAXV]; //保存相关顶点间边的权值 lowcost[0] = 0; //初始化第一个权值为0,即将v0加入生成树 //lowcost的值为0表示此下标的顶点已经加入生成树 adjvex[0] = 0; //初始化第一个顶点下标为0 for (i = 1; i < G.Vnum;i++) { lowcost[i] = G.arc[0][i]; //将v0顶点与之有关的边的权值都存放入权值数组 adjvex[i] = 0; //初始化都为v0的下标 } for (i = 1; i < G.Vnum;i++) { min = 65535; j = 1; min_index = 0; while (j<G.Vnum)//找最小值 并记录节点下标为k { if (lowcost[j]!=0&&lowcost[j]<min) { //如果权值不为0且权值小于min min = lowcost[j]; //则让当前权值成为最小值 min_index = j; //将当前最小值的下标存放k } j++; } printf("(%d,%d)", adjvex[min_index], min_index); //打印当前顶点边中权值最小边 lowcost[min_index] = 0;//将当前顶点的权值置为0,表示此顶点已经完成任务 //更新权值数组 for (j = 1; j < G.Vnum;j++) //循环所有顶点,因为我们已经确认第一个放入的0,所有我们循环可以省去0 { if (lowcost[j] != 0 && G.arc[min_index][j]<lowcost[j]) { /* 如果下标为min_index顶点各边权值小于此前这些顶点未被加入生成树权值 */ lowcost[j] = G.arc[min_index][j]; //将较小权值存入lowcost adjvex[j] = min_index; //将下标为min_index的顶点存入adjvex } } } }
(二)使用邻接表结构
准备:
#define MAX_NUM 100 typedef char node_type; typedef struct arc_node { int pos; int distance; struct arc_node * next; } Arc_node;//保存Node节点的相邻节点信息 typedef struct node { node_type info; Arc_node * next; } Node;//保存节点信息 typedef struct graph { Node vertexs[MAX_NUM]; int vertex, arc; } Graph;//邻接表
实现:
static void init_prim(Graph * graph, Graph * prim_tree); void g_prim(Graph * graph, Graph * prim_tree) { bool visited[graph->vertexs]; int i, j, k; int power, pos; Arc_node * tmp; for ( i = 0; i < graph->vertexs; i++ ) visited[i] = false; init_prim(graph, prim_tree); visited[0] = true; for ( i = 0; i < graph->vertexs; i++ ) { power = INT_MAX;//limits.h for ( j = 0; j < graph->vertexs; j++ ) { if ( visited[j] ) { tmp = graph->adjlist[j].next; while ( tmp != NULL ) { if ( power > tmp->distance && !visited[tmp->pos] ) { power = tmp->distance; pos = tmp->pos; k = j; } tmp = tmp->next; } } } if ( !visited[pos] ) { if ( prim_tree->adjlist[k].next == NULL ) { prim_tree->adjlist[k].next = make_node(pos, power); } else { tmp = prim_tree->adjlist[k].next; while ( tmp->next != NULL ) tmp = tmp->next; tmp->next = make_node(pos, power); } visited[pos] = true; } } } static void init_prim(Graph * graph, Graph * prim_tree) { int i; for ( i = 0; i < graph->vertexs; i++ ) { prim_tree->adjlist[i].info = graph->adjlist[i].info; prim_tree->adjlist[i].next = NULL; } prim_tree->vertexs = graph->vertexs; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?