Prim算法,时间复杂度O(n ^ 2),用于生成最小生成树。以下直接放出代码,注释中详细解释了代码的思想及需要注意的地方。
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXVEX 105
#define INFINITY 65535
using namespace std;
typedef char VertexType;//顶点类型
typedef int EdgeType;//边的类型
typedef struct{
VertexType vexs[MAXVEX]; //存储顶点的数组
EdgeType arc[MAXVEX][MAXVEX]; //存储边信息的数组
int numVertexes,numEdges; //顶点数与边数
}MGraph;
void CreateMGraph(MGraph *G){
cout<<"请输入顶点数与边数:";
cin>>G->numVertexes>>G->numEdges;
// cout<<"请输入"<<G->numVertexes<<"个顶点的信息:";
// for(int i=0;i<G->numVertexes;i++){
// cin>>G->vexs[i];//输入顶点信息(注:存储顶点的数组的下标就可以表示顶点)
// }
for(int i=0;i<G->numVertexes;i++){
for(int j=0;j<G->numVertexes;j++){
if(i==j) G->arc[i][j] = 0;
G->arc[i][j] = INFINITY;
}
}
for(int k=0;k<G->numEdges;k++){
int i,j,w;
cout<<"输入边(vi,vj)上的下标i,j及权值w:";
cin>>i>>j>>w;
G->arc[i][j]=w;
G->arc[j][i]=G->arc[i][j];
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
}
void MiniSpanTree_Prim(MGraph G){
int adjvex[MAXVEX],lowcost[MAXVEX];
lowcost[0] = 0;
adjvex[0] = 0;/*这两行赋值操作是将顶点0加入生成树,当然选择
任意一个顶点作为起点加入生成树均可。*/
for(int i=1;i<G.numVertexes;i++){
lowcost[i] = G.arc[0][i];
adjvex[i] = 0;
}
/*以上为Prim算法的初始化操作,以下为Prim算法生成最小生成树
的操作*/
for(int i=1;i<G.numVertexes;i++){
int j=1,k=0,min=INFINITY;
while(j<G.numVertexes){/*遍历所有除0外的顶点(因为0是
起点)*/
if(lowcost[j]!=0&&lowcost[j]<min){/*若lowcost[j]为
0,则意味着这个点已经加入了最小生成树,第一次循环尚
不能体现出来。*/
min = lowcost[j];/*储存最短距离*/
k=j;/*储存即将加入的顶点下标*/
}
j++;/*不要忘记,否则死循环*/
}
cout<<'('<<adjvex[k]<<','<<k<<')'<<endl;/*打印新建立的
最小生成树的顶点,举个例子,倘若此时找到的两个顶点为0和
5,则将0->5加入最小生成树,并打印(0,5)。(注:也可以
是其他操作,如有的题目让你求最小生成树中所有边的权值,
此时应为累加操作)*/
lowcost[k] = 0;/*将当前顶点的权值设置为0,表示该顶点已经
完成任务,即已经加入了最小生成树。*/
for(j=1;j<G.numVertexes;j++){/*再次循环所有顶点*/
if(lowcost[j]!=0&&G.arc[k][j]<lowcost[j]){/*此时k作
顶点*/
lowcost[j] = G.arc[k][j];
adjvex[j] = k;/*将下标为k的顶点存入adjvex数组中*/
}
}/*其实通过上面的操作,不难发现lowcost数组与adjvex数组是
一体的,即他们的下标对应的是同一个顶点进行操作。举个例子
,若找到了一个lowcost的值,如上所述,记起下标为k,到了打
印操作,打印的是adjvex[k]和k的值,而adjvex[k]的值是从最后
一个循环得到的,可以这样理解,lowcost数组存储的是边的可能
最小权值,adjvex数组存储的是这些边的起点下标。寻找lowcost
的最小值的while循环中的循环变量j,循环的即是lowcost的终点
下标。*/
}
}
int main()
{
MGraph M;
CreateMGraph(&M);
MiniSpanTree_Prim(M);
return 0;
}
此处需要特别注意:
for(int k=0;k<G->numEdges;k++){
int i,j,w;
cout<<"输入边(vi,vj)上的下标i,j及权值w:";
cin>>i>>j>>w;
G->arc[i][j]=w;
G->arc[j][i]=G->arc[i][j];
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
画叹号注释的上一句,一定要给arc[j][i]
赋值而不是给arc[i][j]
赋值,因为arc[i][j]
有值而arc[j][i]
无值,若赋值顺序错误的话,已经赋的值会被覆盖,导致输出结果全为0 。