#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 100 //最大顶点数
typedef char VertexType; //顶点
typedef int EdgeType; //权值
#define INFINITY 65535 /*用65535来代表∞*/
#define UNVISITED -1 //标记未访问
#define VISITED 1 //标记未访问
//Dist的存储结构
typedef struct
{
int index; //顶点的索引值
int length; //当前最短路径长度
int pre; //路径最后经过的顶点
}Dist;
typedef struct
{
int from; //边的始点
int to; //边的终点
EdgeType weight; //权重
}Edge; //边的结构
//图的结构
typedef struct
{
int numVertex; //顶点个数
int numEdge; //边的个数
VertexType vexs[MAXVEX]; /*顶点表*/
int Indegree[MAXVEX]; //顶点入度
int Mark[MAXVEX]; //标记是否被访问过
EdgeType arc[MAXVEX][MAXVEX]; //边表
Dist D[MAXVEX];
Edge MST[MAXVEX]; //数组MST用于保存最小生成树的边
}Graph;
//初始化图(初始化Mark数组,D数组)
void InitGraph(Graph * G,int s,int numVert,int numEd ) //传入顶点个数,边数,s为源点
{
G->numVertex=numVert;
G->numEdge=numEd;
for(int i=0;i<numVert;i++)
{
G->Mark[i]=UNVISITED;
G->D[i].index=i;
G->D[i].length=INFINITY;
G->D[i].pre=s;
G->Indegree[i]=0;
for(int j=0;j<numVert;j++)
{
G->arc[i][j]=INFINITY;
if(i==j)
{
G->arc[i][j]=0;
}
}
}
G->D[s].length=0;
G->Mark[s]=VISITED; //开始源点标记为VISITED
return ;
}
//判断是否为边
bool IsEdge(Edge oneEdge)
{
if(oneEdge.weight>0 && oneEdge.weight!=INFINITY && oneEdge.to>=0)
{
return true;
}
else
{
return false;
}
}
//建立无向图的邻接矩阵
void CreatGraph(Graph * G)
{
int i,j,k,w;
printf("请输入%d个顶点元素:\n",G->numVertex);
for(i=0;i<G->numVertex;i++)
{
scanf(" %c",&G->vexs[i]);
}
for(k=0;k<G->numEdge;k++)
{
printf("请输入边(Vi,Vj)的下标Vi,Vj,和权重w:\n");
scanf("%d%d%d",&i,&j,&w);
G->Indegree[i]++;
G->Indegree[j]++;
G->arc[i][j]=w;
G->arc[j][i]=G->arc[i][j];
}
}
//返回顶点个数
int VerticesNum(Graph * G)
{
return G->numVertex;
}
//返回依附于顶点的第一条边
Edge FirstEdge(Graph * G,int oneVertex)
{
Edge firstEdge;
firstEdge.from=oneVertex;
for(int i=0;i<G->numVertex;i++)
{
if(G->arc[oneVertex][i]!=0 && G->arc[oneVertex][i]!=INFINITY)
{
firstEdge.to=i;
firstEdge.weight=G->arc[oneVertex][i];
break;
}
}
return firstEdge;
}
//返回oneEdge的终点
int ToVertex(Edge oneEdge)
{
return oneEdge.to;
}
//返回与preEdge有相同顶点的下一条边
Edge NextEdge(Graph * G,Edge preEdge)
{
Edge myEdge;
myEdge.from=preEdge.from; //边的始点与preEdge的始点相同
if(preEdge.to<G->numVertex) //如果preEdge.to+1>=G->numVertex;将不存在下一条边
for(int i=preEdge.to+1;i<G->numVertex;i++) //找下一个arc[oneVertex][i]
{ //不为0的i
if(G->arc[preEdge.from][i]!=0 && G->arc[preEdge.from][i]!=INFINITY)
{
myEdge.to=i;
myEdge.weight=G->arc[preEdge.from][i];
break;
}
}
return myEdge;
}
int minVertex(Graph * G)
{
int i,v;
for(i=0;i<G->numVertex;i++)
{
if(G->Mark[i]==UNVISITED)
{
v=i;
break;
}
}
for(i=0;i<G->numVertex;i++)
{
if(G->Mark[i]==UNVISITED && (G->D[i].length<G->D[v].length))
{
v=i;
}
}
return v;
}
//设置一条边
Edge Setedge(int from,int to,int weight)
{
Edge edge;
edge.from=from;
edge.to=to;
edge.weight=weight;
return edge;
}
void Edge_to_MST(Graph * G,Edge e,int num)
{
G->MST[num]=e;
}
//打印出MST数组
void Print_MST(Graph * G,int n)
{
for(int i=0;i<n;i++)
{
printf("elem:%c->%c Edge:(%d,%d) length:%d\n",G->vexs[G->MST[i].from],G->vexs[G->MST[i].to],G->MST[i].from,G->MST[i].to,G->MST[i].weight);
}
printf("\n");
}
void Prim(Graph * G,int s)
{
int MSTtag=0; //最小生成树的边计数
int v=s; //保存源点
for(int i=0;i<G->numVertex-1;i++)
{
if(G->D[v].length==INFINITY) //非连通,有不可到达的点
return ;
//因为v的加入,需要刷新与v相等邻接的顶点的D值
for(Edge e=FirstEdge(G,v);IsEdge(e);e=NextEdge(G,e))
{
if(G->Mark[ToVertex(e)]!=VISITED && G->D[ToVertex(e)].length>e.weight)
{
G->D[ToVertex(e)].length=e.weight;
G->D[ToVertex(e)].pre=v;
}
}
v=minVertex(G); //找出最小的边
G->Mark[v]=VISITED;
Edge edge=Setedge(G->D[v].pre,G->D[v].index,G->D[v].length);
Edge_to_MST(G,edge,MSTtag++); //最小生成树的边数+1
}
Print_MST(G,MSTtag); //输出结果
}
int main()
{
Graph G;
int numVert,numEd;
printf("请输入顶点数和边数:\n");
scanf("%d%d",&numVert,&numEd);
InitGraph(&G,0,numVert,numEd ); //设置0为源点
CreatGraph(&G);
Prim(&G,0); //设置0为源点
return 0;
}