最小生成树——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)    收藏  举报

导航