欢迎光临散文网 会员登陆 & 注册

数据结构学习小记5之最小生成树

2019-08-21 23:03 作者:弃疗的中二病拱卒者  | 我要投稿

连通图的生成树:一个极小连通子图,它含有图中全部顶点,但只有足以构成一棵树的n-1条边,这样的连通子图称为连通图的生成树。

无向图以及其生成树(图源:百度百科)

在一个连通图的所有生成树中,各边的代价之和(即各边的权值最小)的那棵生成树称为该连通网的最小生成树。

普里姆(Prim)算法

(1)构造过程

假设N=(V,E)是连通网,TE是N上最小生成树中边的集合

  1. U={u0}(u0∈V),TE={}(U中是在生成过程中将点纳入的集合)

  2. 在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE,同时v0并入U中

  3. 重复2,直至U=V为止。

    此时TE中必有n-1条边,则T=(V,TE)为N的最小生成树的例子。可以看出Prim算法逐步增加U中的顶点,可称为"加点法"。


Prim算法过程

(2)算法实现

struct 

{

VetTexType  adjvex;//最小边在U中的那个顶点

 ArcType lowcost;//最小边上的权值

}closedge[MVNum];

//这是辅助数组,用来记录从顶点集U到V-U的权值的边


具体过程

void MiniSpanTree_Prim(AMGraph G,VerTexType u)

{//无向网G以邻接矩阵形式存储,从顶点u出发构造G的最小生成树T,输出T的各条边

k=LocateVex(G,u);//k为顶点u的下标

for(j=0;j<G.vexnum;++j)//对每一个顶点vj,初始化closedge[j]

    if(j!=k) closedge[j]={u,G.arcs[k][j]};

closedge[k].lowcost=0;  //lowcost存储最小边上的权值

for(i=1;i<G.vexnum;++i)

{//选择其余n-1个顶点,生成n-1条边(n=G.vexnum)

k=Min(closedge);

//求出T的下一个结点:第k个顶点,closedge[k]中存有当前最小边

u0=closedge[k].adjvex; //u0为最小边的一个顶点,u0∈U

v0=G.vexs[k];  //v0为最小边的另一个顶点,v0∈V-U

cout<<u0<<v0;//输出当前的最小边(u0,v0)

closedge[k].lowcost=0;

for(j=0;j<G.vexnum;++j)

    if(G.arcs[k][j]<closedge[j].lowcost)

        closedge[j]={G.vexs[k],G.arcs[k][j]};//选出最小的权值得到最小边将新顶点并入U

}

}

【算法分析】

算法的时间复杂度为O(n^2),与网中的边数无关,因此适用于求稠密图网的最小生成树。

克鲁斯卡尔算法

(1)构造过程

假设连通网N=(V,E),将N中的边按权值从小到大的顺序排列

  1. 初始状态是只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量

  2. 在E中选择权值最小的边,若该边依附的顶点落在T中不同的连通分量上(即不形成回路),则将此边加入到T中,否则舍去此边而选择下一条权值最小的边。

  3. 重复2,直至T中所有顶点都在同一连通分量上为止

克鲁斯卡尔算法生成最小生成树

(2)算法实现

struct

{

VerTexType Head;//边的始点

VerTexType Tail;//边的终点

ArcType lowcost;//边上的权值

}Edge[arcnum];

//以上为结构体数组Edge:存储边的信息

int Vexset[MVNum];

//该数组用于标记各个顶点所属的连通分量

具体过程

void MiniSpanTree_Kruskal(AMGraph G)

{

Sort(Edge);//权值从小到大排序

for(i=0;i<G.vexnum;++i)

    Vexset[i]=i;

for(i=0;i<G.arcnum;++i)

{

v1=LocateVex(G,Edge[i].Head);

v2=LocateVex(G,Edge[i].Tail);

vs1= Vexset[v1];//获取边的始点所在的连通分量vs1

vs2= Vexset[v2];//获取边的终点所在的连通分量vs2

if(vs1!=vs2)

{

  cout<<Edge[i].Head<<Edge[i].Tail;//输出此边

 for(j=0;j<G.vexnum;++j)//合并vs1和vs2两个分量,两个集合统一编号

if(Vexset[j]==vs2)

Vexset[j]=vs1;

}

}

【算法分析】

该算法的时间复杂度为O(elog2e),与网中的边数有关,与普里姆算法相比,克鲁斯卡尔算法更适合求稀疏图的最小生成树。

数据结构学习小记5之最小生成树的评论 (共 条)

分享到微博请遵守国家法律