最小生成树——Prim算法以及输出邻接矩阵
看了b站懒猫老师的视频,整理了最小生成树Prim算法
集合V为图中所有点集合,集合U为已经在最小生成树里的点集合,V-U为还没放入的点
MGraph:MGraph有arc[N][N]域和vertexNum域,分别存储点与点之间边的权值(图的邻接矩阵),总结点数
MGraph为图的结构体,存储图中结点之间的关系,0~vertexNum-1代表结点下标
shortEdge[N]:shortEdge类型有adjvex域和lowcost域
这个数组代表存储当前U里某点到V-U里点的最短边信息 ,其中adjVex代表shortEdge[i]最短边的始点(在U中),lowCost代表这条最短边的值,i为最短边的终点 (这里的终点始点只是为了方便描述,无向图中不分)
1.确定起始点,将shortEdge数组初始化为起始点对应邻接信息,即adjVex全为起始点 ,lowCost为Marc[起始点][i]
判断是否加入U中,看lowcost是否为0,此时起始点已加入U中。
2.循环vertexNum-1次,找出最小生成树
1)在shortEdge中找出最小lowcost,确定下标k
2)输出最小生成树的一部分 ,输出:(adjvex,k)lowcost
3) 将k加入U,即lowcost置为0
4)更新shortEdge数组,将原shortEdge数组和新加入的U中k元素对比,更新为最小lowcost,以及更新对应adjVex
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MAX 0x3f3f3f3f //用0x3f3f3f3f代表无穷大 #define N 50 //默认最多50个结点 typedef struct{ int arc[N][N];//邻接矩阵 int vertexNum;//一共多少点 }MGraph; typedef struct{ int adjvex;//最短边连接的U中的点 int lowcost;//最短边的权值 }shortEdge; shortEdge shortest[N];//最短边数组,用于查找要加入U中的点 void prim(MGraph g,int start); void outPrim(int k,shortEdge sEdge); int findMin(shortEdge shortest[],int num); int main(){ int start,i,j; int edgeNum,vNum; int x,y,v; MGraph g={{},N}; printf("请输入顶点数和边的个数\n"); scanf("%d %d",&vNum,&edgeNum); for(i=0;i<vNum;i++) { memset(g.arc+i,MAX,sizeof(int)*vNum);//将结点全部初始化为无穷大 g.arc[i][i]=0;//将结点自己到自己设为0 } g.vertexNum=vNum; //输入并设置点与点之间的权值 for(i=0;i<edgeNum;i++){ printf("请输入边依附的两个顶点编号(0~%d)和权值\n",g.vertexNum-1); scanf("%d %d %d",&x,&y,&v); g.arc[x][y]=v; g.arc[y][x]=v; } printf("请输入prim算法的起始结点\n"); scanf("%d",&start); //输出邻接矩阵 printf("输出邻接矩阵信息:\n"); for(i=0;i<vNum;i++){ for(j=0;j<vNum;j++){ if(g.arc[i][j]==0x3f3f3f3f)printf("∞ ");//将无穷大输出替换为符号 else printf("%d ",g.arc[i][j]); } printf("\n"); } prim(g,start); } //Prim最小生成树算法 void prim(MGraph g,int start){ int i,p; //将最短边数组初始化为起始点邻接信息 for(i=0;i<g.vertexNum;i++){ shortest[i].lowcost=g.arc[start][i]; shortest[i].adjvex=start; } printf("输出最小生成树的每条边的信息\n"); //循环找出最小生成树 int k,j; for(i=0;i<g.vertexNum-1;i++){ k=findMin(shortest,g.vertexNum);//找到最短边 outPrim(k,shortest[k]);//输出 shortest[k].lowcost=0;//将k加入集合U中 for(j=0;j<g.vertexNum;j++){ //更新最短边数组 if(g.arc[k][j]<shortest[j].lowcost)shortest[j].lowcost=g.arc[k][j],shortest[j].adjvex=k; } } } //找到shortEdge数组中最小的lowcost下标,用于就加入最小生成树结点集合中 int findMin(shortEdge shortest[] ,int num){ int temp=MAX; int c,i,index=0; for(i=0;i<num;i++){ c=shortest[i].lowcost; if(c!=0&&c<temp) { temp=c; index=i; } } return index; } //输出最小生成树的一条边的两端结点以及权值 void outPrim(int k,shortEdge sEdge){ printf("(%d,%d)%d\n",sEdge.adjvex,k,sEdge.lowcost); }
测试数据
输入:
6 9
0 1 34
0 2 46
0 5 19
1 4 12
2 3 17
2 5 25
3 5 25
3 4 38
4 5 26
3
输出:
输出邻接矩阵信息:
0 34 46 ∞ ∞ 19
34 0 ∞ ∞ 12 ∞
46 ∞ 0 17 ∞ 25
∞ ∞ 17 0 38 25
∞ 12 ∞ 38 0 26
19 ∞ 25 25 26 0
输出最小生成树的每条边的信息:
(3,2)17
(3,5)25
(5,0)19
(5,4)26
(4,1)12
posted on 2020-12-29 23:06 wang_dahua 阅读(444) 评论(0) 收藏 举报