您的位置:首页 > 其它

最小生成树算法之Prim算法

2015-01-29 23:56 309 查看
一、最小生成树

生成树是一个连通图(图中任意两个顶点都有路径相连)的极小连通子图,它含有图中所有顶点,但只有足以构成一棵树的n-1条边。最小生成树就是生成树中权值之和最小的生成树。最小生成树算法有Prim算法和 kruskal算法。

二、Prim算法

假设N=(V,{E})是连通图,V是顶点集合,{E}是边集,TE是N上最小生成树中边的集合。假设从顶点V0,(v0在V上)开始生成最小生成树,TE刚开始为空集。重复执行下述操作:在所有u(u属于已访问过的顶点,即是已在最小生成树内),v(在V-U内)的边(v,u)中找一条代价最小的边(u0,v0)并入集合TE,同时u0并入U,直到U=V为止,此时TE中必有n-1条边,则T=(V,{TE})为最小生成树。

根据算法的描述,该算法最要的两步是:

1.在所有u(u属于已访问过的顶点,即是已在最小生成树内),v(在V-U内)的边(v,u)中找一条代价最小的边(u0,v0)并入集合TE;

2.u0并入U;

图例分析:



根据Prim算法得到(假设从A开始)

1.(A,C),2(C,D),3(C,B),得到的最小生成树如下:



代码如下:

#define INFINITY INT_MAX        //maximum
#define MAX_VERTEX_NUM 20  //the maximum of vertex number
typedef struct ArcCell{
int adj;    //while the graph is unweighted ,adj is equal to 1 or 0.while the graph is weighted
//,adj is equal to the weight of the arc.
int *info; //the pointer of information about the arc
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct {
char vexs[MAX_VERTEX_NUM];  //the vector of vertex
AdjMatrix arcs;                            //adjacent matrix
int vexnum,arcnum;
}MGraph;
//用于prim最小生成树算法的辅助数组,clodedge[i-1].lowcost=Min{cost(u,vi)|u属于已经为最小生成树中的顶点}
struct {
char adjvex;
int lowcost;
}closedge[MAX_VERTEX_NUM];


//****************邻接矩阵表示*****************
//*********************************************
void CreatGraph2(MGraph *G);//邻接矩阵表示图
int LocateVex(MGraph G,char v);//确定顶点v在顶点向量中的位置
void MiniSpanTree_PRIM(MGraph *G,char v);//prim最小生成树算法


int LocateVex(MGraph *G,char v)
{
int k=0;
for(int i=0;i<G->vexnum;i++)
{
if(v==G->vexs[i])
k=i;
}
return k;
}
void CreateGraph2(MGraph *G)
{
cout<<"请输入图的顶点数(顶点个数最大值为20):"<<endl;
cin>>G->vexnum;
cout<<"请输入图的弧的个数:"<<endl;
cin>>G->arcnum;
cout<<"请输入顶点编号构造顶点向量:"<<endl;
for(int i=0;i<G->vexnum;i++)
cin>>G->vexs[i];
cout<<"顶点向量构造完成!"<<endl;
for(int i=0;i<G->vexnum;i++)
for(int j=0;j<G->vexnum;j++)
{
//初始化邻接矩阵
G->arcs[i][j].adj=INFINITY;
G->arcs[i][j].info=NULL;
}
cout<<"开始构造邻接矩阵!"<<endl;
for (int i=0;i<G->arcnum;i++)
{
char v1,v2;//顶点编号
int k1,k2,w;
cout<<"请输入该边的两个顶点v1、v2:"<<endl;
cin>>v1>>v2;
//确定v1,v2的位置
k1=LocateVex(G,v1);
k2=LocateVex(G,v2);
cout<<"输入该边的权值:"<<endl;
cin>>w;
G->arcs[k1][k2].adj=w;
G->arcs[k2][k1].adj=G->arcs[k1][k2].adj;
}
cout<<"邻接矩阵构造完毕!"<<endl;
}


void MiniSpanTree_PRIM(MGraph *G,char v)

{

int k ,weight=0;

k=LocateVex(G,v);

//辅助数组初始化,与顶点k连接的边赋予其权值,不相连的为无穷大

for(int i=0;i<G->vexnum;i++)

{

if(i!=k)

{

closedge[i].adjvex=v;

closedge[i].lowcost=G->arcs[k][i].adj;

}

}

closedge[k].lowcost=0; //表示从顶点v开始生成最小生成树

for(int i=1;i<G->vexnum;i++)

{

//选择最小的边(一个顶点在已访问过的顶点中,一个不在)并入最小生成树

int min=INFINITY;

for(int j=0;j<G->vexnum;j++)

{

if(closedge[j].lowcost>0&&min>closedge[j].lowcost)

{

min=closedge[j].lowcost;

k=j;

}

}

cout<<"本次运行得到最小生成树的边为:"<<"("<<closedge[k].adjvex<<","<<G->vexs[k]<<")"<<endl;

closedge[k].lowcost=0;

weight+=min;

//更新closedge数组

for(int a=0;a<G->vexnum;a++)

{

if(G->arcs[k][a].adj<closedge[a].lowcost)

{

closedge[a].lowcost=G->arcs[k][a].adj;

closedge[a].adjvex=G->vexs[k];

}

}

}

cout<<"该最小生成树的权重为:"<<weight;

}

void main()
{
char star;
MGraph G1;
CreateGraph2(&G1);
cout<<"请输入要从哪个顶点开始生成最小生成树:";
cin>>star;
MiniSpanTree_PRIM(&G1,star);

}


利用前面给出的图进行测试,结果如下:





最后,贴上CSDN内一大神写的Prim算法,将各个过程拆解开,分析的非常详细,而且代码风格相当好,地址:/article/1797676.html

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