您的位置:首页 > 其它

普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

2017-01-25 11:54 351 查看

        图是一种基础又重要的数据结构,图的生成树是图的一个极小连通子图。最小生成树是无向连通网的所有生成树中边的权值之和最小的一棵生成树。求图的最小生成树可以牵引出很多经典的题目,例如在N个城市之间建立通讯网络,问怎样最省经费(不同城市之间的联系网的费用不同,也即是边上的权值不同)。

求图的最小生成树有两种算法,普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法。下面是我对他们的简化理解。(只对Kruskal进行了简单的实现)

    ① Prim算法的主要思想就是:假设N=(V, {E})是连通网,TE是N上最小生成树边集合。
(1) U={u0}(u0属于V),   TE={ }
(2) 在所有uU,vV-U的边(u,v)E 中找一条代价最小的边(u0,v0)并入集合TE, 同时v0并入U,
(3) 如果U≠V,转(2) (直到U=V为止)

     最后:TE中必有n-1条边,则T=(V,{TE})为N的最    小生成树。
粗略的看起来似乎干涩难懂,其实方法不难,就是把顶点分成两个集合,一个是生成树顶点集合,一个是其它顶点集合,且求最小生成树的过程就是从其它顶点集合选取点加入到生成树顶点的过程。怎么选取呢,其实方法很简单,就是从其它顶点集合中选一个可以连接到生成树顶点且权最小的点,加入到生成树顶点。下面用图来说明下:













这就是Prim建立最小生成树的过程。
为实现此算法需设置辅助数组closedge ,对当前V-U中每个顶点,记录从U到V-U的代价最小的边:

struct{
VerTexType adjvex; //最小边在U中的那个顶点
ArcType lowcost;	    //最小边上的权值
}closedge[MVNum];


    ②Kruskal算法,我认为这个可能更简单,具体的方法也实现起来也容易,先构造一个只含 n 个顶点的子图 SG,然后从权值最小的边开始,若它的添加不使SG 中产生回路,则在 SG 上加上这条边,如此重复,直至加上 n-1 条边为止。还是用图来说明比较好理解:



下面就来Kruskal来简单实现以下:



#include<iostream>
using namespace std;

typedef struct
{
int cost;
char v1,v2;
}Edge;

char temp[100];
int flag=0;
int check(char k,int m)
{
int i;
for(i=0;i<m;i++)
{
if(temp[i]==k)
return 1;
}
return 0;
}

int main()
{
int i,j,n,m;
Edge edges[100],t;

cout<<"输入顶点数和边数:";
cin>>m>>n;
cout<<"依次输入多组v1 v2 cost:"<<endl;
for(i=0;i<n;i++)
{
cin>>edges[i].v1>>edges[i].v2>>edges[i].cost;
}

for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(edges[i].cost>edges[j].cost)
{
t=edges[i];
edges[i]=edges[j];
edges[j]=t;
}
}
}

for(i=0;i<n;i++)
{
if(check(edges[i].v1,m)==0 || check(edges[i].v2,m)==0)
{
cout<<edges[i].v1<<"---"<<edges[i].v2<<" "<<edges[i].cost<<endl;
if(check(edges[i].v1,m)==0)
{
temp[flag]=edges[i].v1;
flag++;
}
if(check(edges[i].v2,m)==0)
{
temp[flag]=edges[i].v2;
flag++;
}
}
}

return 0;
}




                                                                     谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息