1.解析

Prim算法和Dijkstra算法非常类似,他们的伪码几乎相近,只是他们优先队列所排序的键值不同而已。Prim算法的键值为节点与集合S中顶点间的最轻边的权重,而在Dijkstra算法中,键值为由起始点到某节点的完整路径长度。

在后面的博客中会说明最小生成树MST与最短路径的区别。

2.代码实例

 #include<iostream>    

#include<malloc.h>    

#include<queue>  

#include <algorithm>    

#include<stdlib.h>  

#include<functional>

using namespace std;    

 

#define maxNum 100 //定义邻接举证的最大定点数  

#define maxWeight 1000000 //边权最大值  

int cost[maxNum];//用户存储节点与最小生成树MST之间的权重,初始状态cost[i]=maxWeight

int prev_Elem[maxNum];//该数组用户存储结点的前序,比如prev[v]=u,则表示u是v的前序

int set[maxNum];//集合S,一开始为空,初始化的时候确定一个顶点,后续顶点都是通过prim算法找到的。set[i]=1表示顶点i属于集合s

//顶点信息

typedef struct

{

int id;//顶点编号

int cost;//用于保存该顶点到MST的最小权值

}node;

//图的邻接矩阵表示结构    

typedef struct    

{    

   //char v[maxNum];//图的顶点信息  

node v[maxNum];

   int e[maxNum][maxNum];//图的顶点信息    

   int vNum;//顶点个数    

   int eNum;//边的个数    

}graph;

//函数声明  

void createGraph(graph *g);//创建图g  

void Prim(graph *g)  ;//核心算法,是BFS的改版,只是将普通队列改成了优先队列。

int cmp(node a,node b);//定义优先队列以升序还是降序排列  

int cmp(node a,node b)

{

return a.cost<b.cost;//升序

}

//prim算法

void Prim(graph *g)  

{  

node Q[maxNum]; //定义结构体数组  

   int front;//队列头    

   int rear;//队列尾    

   int count;//队列计数    

   front=rear=count=0;//表示队列为空  

   int k,i,j;    

   //初始化cost的值  

   for(i=1;i<=g->vNum;i++)    

   {  

       g->v[i].cost=maxWeight;  //cost为最大值  

       g->v[i].id=i;  

 prev_Elem[i]=-1;

 set[i]=0;

   }  

   g->v[1].cost=0;//1作为MST第一个顶点,初始化其cost为0  

//初始化优先队列

for(i=1;i<=g->vNum;i++)  

{

 Q[++rear]=g->v[i];  

 count++;//顶点进入队列Q  

}  

   

while(count>0)//队列不空 ,一直循环,也可是front<rear,也表示队列不空,count=rear-front  

   {  

 sort(Q+front+1,Q+rear+1,cmp);//对队列Q进行排序,按cost的升序排列。  

       //以下两行是队列的出队操作  

       node n1=Q[++front]; //取出当前非s集合中离s距离最近的点

       count--;//出队列操作

       k=n1.id;//

 cout<<k<<endl;

 set[k]=1;//将上述从队列中取出的顶点加入到集合s中去

 for(j=1;j<=g->vNum;j++)  

 {  

  if(g->e[k][j]!=maxWeight&&set[j]==0)//i->j之间有边,并且顶点j不属于集合s的时候  

  {  

   //如果顶点j到集合s的距离权值大于集合中一点k到j的距离,那么更新(update)j点距离权值

   //并令该j的前序为k

   if((g->v[j].cost>g->e[k][j]))  

   //if((g->v[j].cost>g->e[k][j]))

   {

    g->v[j].cost=g->e[k][j];

    prev_Elem[j]=k;

   }

  }  

 }  

 //更新队列

 for(i=1;i<=g->vNum;i++)  

 {

  Q[i]=g->v[i];  

 }  

 cout<<"更新cost后各顶点的cost值"<<endl;

 for(i=1;i<=g->vNum;i++)

  cout<<g->v[i].cost<<" ";

 cout<<endl;

   }  

}  

void createGraph(graph *g)//创建图g    

{    

   cout<<"正在创建无向图..."<<endl;    

   cout<<"请输入顶点个数vNum:";    

   cin>>g->vNum;      

   int i,j;  

   //构造邻接矩阵,顶点到自身的距离是无穷大的。  

   cout<<"输入邻接矩阵权值:"<<endl;  

for(i=1;i<=g->vNum;i++)

 for(j=1;j<=g->vNum;j++)

 {

  cin>>g->e[i][j];

  if(g->e[i][j]==0)

   g->e[i][j]=maxWeight;

 }

}    

   

int main()    

{    

int i;

   graph *g;    

   g=(graph*)malloc(sizeof(graph));    

   createGraph(g);    

   Prim(g);  

 

//for(int k=1; k<=g->vNum; k++)

//{

// cout<<g->v[k].cost<<" ";

//}

/*cout<<endl;*/

cout<<"输出MST的各条边"<<endl;

for(i=1;i<=g->vNum;i++)

{

 //cout<<prev_Elem[i]<<" ";

 if(prev_Elem[i]!=-1)

  cout<<"存在边:"<<prev_Elem[i]<<"->"<<i<<",权值为:"<<g->e[prev_Elem[i]][i]<<endl;

}

//cout<<endl;

   system("pause");  

   return 0;    

}    

/*

正在创建无向图...

请输入顶点个数vNum:6

输入邻接矩阵权值:

0 5 6 4 0 0

5 0 1 2 0 0

6 1 0 2 5 3

4 2 2 0 0 4

0 0 5 0 0 4

0 0 3 4 4 0

输出MST的各条边

存在边:3->2,权值为:1

存在边:4->3,权值为:2

存在边:1->4,权值为:4

存在边:6->5,权值为:4

存在边:3->6,权值为:3

请按任意键继续. . .

*/