最小生成树算法之Prim算法

来源:互联网 发布:vscode npm install 编辑:程序博客网 时间:2024/05/10 02:41

一、最小生成树

生成树是一个连通图(图中任意两个顶点都有路径相连)的极小连通子图,它含有图中所有顶点,但只有足以构成一棵树的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 numbertypedef 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 vertexAdjMatrix arcs;                            //adjacent matrixint 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算法,将各个过程拆解开,分析的非常详细,而且代码风格相当好,地址:http://blog.csdn.net/feixiaoxing/article/details/6937338

点击打开链接

0 0
原创粉丝点击