大话数据结构——最小生成树~Prim算法~O(n^2)~2020.7.15

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 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值