普利姆算法
思想
- 取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w
- 在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,
- 并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。
- 之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。
性能
O(n^2),适合稠密图(边多的图)
另一个【克鲁斯卡尔算法】O(eloge):适合稀疏图(边少的图)
博客:https://blog.csdn.net/summer_dew/article/details/81660723
举例
- 蓝色的顶点:还未考虑的顶点
- 黄色的顶点:已经考虑完的顶点
- 蓝色的线:未考虑的边
- 紫色的线:考虑范围内的边
- 红色的线:生成树的边(最短的边)
将a纳入考虑的顶点,变成黄色
第一步:考虑黄色顶点【a】
- 考虑与a相连的所有边(紫色的边),取出最短的边:18
- 将最短边,纳入生成树的边(变红色)
- 将顶点b纳入已考虑的顶点(变黄色)
第二步:考虑黄色的顶点【a,b】
- 考虑与a,b相连的所有边(紫色的边),取出最短的边8
- 将最短边,纳入生成树的边(变红色)
- 将顶点c纳入已考虑的顶点(变黄色)
第三步:继续考虑黄色的顶点【a,b,c】
- 考虑与a,b,c相连的所有边(紫色的边),取出最短的边20
- 将最短边,纳入生成树的边(变红色)
- 将顶点d纳入已考虑的顶点(变黄色)
实现
记:
- 黄色的顶点,为顶点集【U】,即已落在生成树上的顶点
- 蓝色的顶点,为顶点集【V-U】,即尚未落在生成树上的顶点
设置一个辅助数组
- 下标:顶点v
- lowcost:记录【黄色的点们】到【v】的最短边
- adjvex:记录【黄色的点集】中哪一个顶点,到v最短
例如:下图,最初始时
- 下标1:表示顶点b
- lowcost[1]记录的是当前【黄色点集】到b的最短路径为18。
- 这个最短路径是从a(adjvex[1])到b的
// 记录从顶点集U到V-U的代价最小的边的辅助数组定义
struct {
VertexType adjvex; // U集中的顶点序号
VRType lowcost; // 边的权值
} closedge[MAX_VERTEX_NUM];
// 普利姆算法
// 从第u个顶点出发构造网G的最小生成树T,输出T的各条边
void MiniSpanTree_P(MGraph G, VertexType u) {
k = LocateVex ( G, u );
for ( j=0; j<G.vexnum; ++j ) {// 辅助数组初始化
if (j!=k) {
closedge[j] = { u, G.arcs[k][j].adj };
}
}
closedge[k].lowcost = 0; // 初始,U={u}
for (i=0; i<G.vexnum; ++i) {
k = minimum(closedge); // 求出加入生成树的下一个顶点(k)
// 此时 closedge[k].lowcost = MIN{closedge[Vi].lowcost | closedge[Vi].lowcost >0, Vi∈V-U}
printf(closedge[k].adjvex, G.vexs[k]); // 输出生成树上一条边
closedge[k].lowcost = 0; // 第k顶点并入U集
for (j=0; j<G.vexnum; ++j) {//修改其它顶点的最小边
if (G.arcs[k][j].adj < closedge[j].lowcost) {
closedge[j] = { G.vexs[k], G.arcs[k][j].adj };
}
}
}
}