之前粗略总结过普里姆算法,很多关键的点没有总结到位
因此重新将该算法补全
完整代码:
#include <stdio.h>
#include <limits.h>
#define MVNum 100 //定义最大顶点数
typedef int VerTexType; //表示顶点的数据类型
typedef int ArcType; //表示边权值的数据类型
typedef struct {
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵,可看作边表
int vexnum, arcnum; //顶点数、边数
} AMGraph;
typedef struct {
VerTexType adjvex;
ArcType lowcost;
} Closedge;
int locateVex(AMGraph G, VerTexType u) {
/*
返回顶点 u 在图中的位置
*/
for (int i = 0; i < G.vexnum; i++) {
if (G.vexs[i] == u) {
return i;
}
}
return -1; //未找到返回-1
}
int Min(Closedge closedge[], int n) {
/*
寻找 closedeg 数组中未访问节点中权值最小的节点
*/
int min = INT_MAX;
int min_index;
for (int i = 0; i < n; i++) {
if (closedge[i].lowcost != 0 && closedge[i].lowcost < min) {
min = closedge[i].lowcost;
min_index = i;
}
}
return min_index;
}
void MiniSpanTree_Prim(AMGraph G, VerTexType u) {
int i, j, k;
k = locateVex(G, u);
Closedge closedeg[MVNum];
for (j = 0; j < G.vexnum; j++) {
if (j != k) {
closedeg[j].adjvex = G.vexs[k];
closedeg[j].lowcost = G.arcs[k][j];//该程序未连接的点默认赋值为0
}
}
closedeg[k].lowcost = 0;
VerTexType u0, v0;
for (i = 1; i < G.vexnum; i++) {
k = Min(closedeg, G.vexnum);
u0 = closedeg[k].adjvex;
v0 = G.vexs[k];
printf("%d %d\n", u0, v0);
closedeg[k].lowcost = 0;
for (j = 0; j < G.vexnum; j++) {
//if (G.arcs[k][j] < closedeg[j].lowcost||G.arcs[k][j]>0&& closedeg[j].lowcost==0)
if (G.arcs[k][j] < closedeg[j].lowcost) //需要被替换
{
closedeg[j].adjvex = G.vexs[k];
closedeg[j].lowcost = G.arcs[k][j];
}
}
}
}
int main() {
//创建图的邻接矩阵
AMGraph G;
G.vexnum = 6;
G.arcnum = 9;
G.vexs[0] = 0;
G.vexs[1] = 1;
G.vexs[2] = 2;
G.vexs[3] = 3;
G.vexs[4] = 4;
G.vexs[5] = 5;
G.arcs[0][1] = 6;
G.arcs[0][2] = 1;
G.arcs[0][3] = 5;
G.arcs[1][0] = 6;
G.arcs[1][2] = 5;
G.arcs[1][4] = 3;
G.arcs[2][0] = 1;
G.arcs[2][1] = 5;
G.arcs[2][3] = 5;
G.arcs[2][4] = 6;
G.arcs[2][5] = 4;
G.arcs[3][0] = 5;
G.arcs[3][2] = 5;
G.arcs[3][5] = 2;
G.arcs[4][1] = 3;
G.arcs[4][2] = 6;
G.arcs[4][5] = 6;
G.arcs[5][2] = 4;
G.arcs[5][3] = 2;
G.arcs[5][4] = 6;
//运行 Prim 算法
MiniSpanTree_Prim(G, 0);
return 0;
}
算法解析:
以上代码通过邻接矩阵来表示图,使用数组
vexs
来储存各个顶点,使用arcs
数组来储存边及其权值。在MiniSpanTree_Prim
函数中,我们创建一个数组closedeg
来存储每个节点与当前最小生成树的距离和其对应的父节点,并将除起点外的其他节点初始化为{u, G.arcs[k][j]}
。然后,从第二个节点开始进行循环,在未访问节点中找到权值最小的节点,输出该节点与其父节点的信息,并将其标记为已访问。接着,更新所有与该节点相邻且未被访问的节点的 key 值和父节点信息。最后,输出得到的最小生成树的边集。
在主函数里 G.arcs[i][j]若没有被赋值,则默认赋值为0
在 void MiniSpanTree_Prim(AMGraph G, VerTexType u)里,该句if (G.arcs[k][j] < closedeg[j].lowcost)是错误的 需要被替换成if (G.arcs[k][j] < closedeg[j].lowcost||G.arcs[k][j]>0&& closedeg[j].lowcost==0),原因是在 Prim 算法中,如果节点 j
尚未连接到最小生成树,应该将当前从节点 k
到节点 j
的边加入到最小生成树中,而不仅仅是当 G.arcs[k][j] < closedeg[j].lowcost
时。因此 需要扩充判断条件
注:若在主函数里 G.arcs[i][j]若没有被赋值,则赋值为“无穷”的话 则不需要更改条件!