[图] 4.1 最小生成树-普利姆算法Prim O(n^2)稠密图-C语言实现-gif图演示

普利姆算法

思想

  1. 取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w
  2. 在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,
  3. 并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。
  4. 之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。

性能

O(n^2),适合稠密图(边多的图)
另一个【克鲁斯卡尔算法】O(eloge):适合稀疏图(边少的图)
博客:https://blog.csdn.net/summer_dew/article/details/81660723

举例

  1. 蓝色的顶点:还未考虑的顶点
  2. 黄色的顶点:已经考虑完的顶点
  3. 蓝色的线:未考虑的边
  4. 紫色的线:考虑范围内的边
  5. 红色的线:生成树的边(最短的边)

这里写图片描述

将a纳入考虑的顶点,变成黄色
第一步:考虑黄色顶点【a】

  1. 考虑与a相连的所有边(紫色的边),取出最短的边:18
  2. 将最短边,纳入生成树的边(变红色)
  3. 将顶点b纳入已考虑的顶点(变黄色)

第二步:考虑黄色的顶点【a,b】

  1. 考虑与a,b相连的所有边(紫色的边),取出最短的边8
  2. 将最短边,纳入生成树的边(变红色)
  3. 将顶点c纳入已考虑的顶点(变黄色)

第三步:继续考虑黄色的顶点【a,b,c】

  1. 考虑与a,b,c相连的所有边(紫色的边),取出最短的边20
  2. 将最短边,纳入生成树的边(变红色)
  3. 将顶点d纳入已考虑的顶点(变黄色)

实现

记:

  1. 黄色的顶点,为顶点集【U】,即已落在生成树上的顶点
  2. 蓝色的顶点,为顶点集【V-U】,即尚未落在生成树上的顶点

设置一个辅助数组

  1. 下标:顶点v
  2. lowcost:记录【黄色的点们】到【v】的最短边
  3. adjvex:记录【黄色的点集】中哪一个顶点,到v最短

例如:下图,最初始时

  1. 下标1:表示顶点b
  2. lowcost[1]记录的是当前【黄色点集】到b的最短路径为18。
  3. 这个最短路径是从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 }; 
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/summer_dew/article/details/81660483