前言
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
这里主要讲解普利姆算法的思路及其实现过程。
一、最小生成树是什么?
在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得联通所有结点的的 w(T) 最小,则此 T 为 G 的最小生成树。
二、普利姆算法的思想
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
三、耿国华老师的具体实现步骤
为了实现这个算法设置一个辅助数组closedge[],记录从U到V-U具有最小代价的边。
closedge[v]包括两个域,adjvex和lowcost,其中lowcost记录最小边的权值,adjvex记录最小边在U中的顶点。
struct {
int adjvex;
int lowcost;
}closedge[MAX];
3.1 算法思想
1.首先将初始v0加入U中,并对其余的每个顶点i,将closedge[i]均初始化为i到v0的边的信息。
2.由于v0自己不用完成搜索,因此再循环n-1次,做如下处理。
3.从各组最小边closedge[]中选择最小的最小边closedge[v]。
4.将v加入U中,这里的加入就是closedge[v].lowcost=0;
5.更新剩余的每个最小边信息closedge[i]
6.对于以i为中心的那组边,如果新边的权值比closedge[i].lowcost小,则将closedge[i].lowcost更新为新边的权值。
3.2 个人在实现时遇到的问题
耿老师将v纳入U后将closedge[v].lowcost=0,但是在新边搜索时应当把closedge[i].lowcost=0的边踢出去,否则会是死循环。
3.3 具体代码
#define INFINITY 65535
struct {
int adjvex;
int lowcost;
}closedge[MAX];//辅助数组
void PrimMiniSpanTree(AdjMatrix g, int v0) {
closedge[v0].lowcost = 0;
for (int i = 0; i < g.vexnum; i++) {
if (i != v0) {
closedge[i].adjvex = v0;//初始将所有顶点的邻点设为v0
closedge[i].lowcost = g.arcs[v0][i].adj;
}
}
for (int i = 0; i < g.vexnum - 1; i++) {
//v0已经完成任务,因此循环n-1次
int min = INFINITY;//保存最小边的权值
int index = 0;//保存最小边的下标
for (int j = 0; j < g.vexnum; j++) {
if (closedge[j].lowcost != 0 && closedge[j].lowcost < min) {
min = closedge[j].lowcost;
index = j;
}
}
printf("(%c,%c) ", g.vertex[closedge[index].adjvex], g.vertex[index]);//输出最小边的信息
closedge[index].lowcost = 0;//closedge[].lowcost=0表示该顶点已经完成任务,下一次以该顶点的邻边进行搜寻。
for (int j = 0; j < g.vexnum; j++) {
if (closedge[j].lowcost != 0 && g.arcs[index][j].adj < closedge[j].lowcost) {
closedge[j].lowcost = g.arcs[index][j].adj;
closedge[j].adjvex = index;
}
}
}
}
3.4 测试结果
这里采用的图及其权值如下图
这里以A为顶点,显然是对滴。
再以G为顶点
显然也是对滴。
总结
把握思想,就能实现!