#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAX 100
#define NO INT_MAX//NO表示没有边,相当于INF
typedef struct Graph
{
int arcnum;
int vexnum;
char vextex[MAX][20];
int martrix[MAX][MAX];
}Graph;
//邻接矩阵打印输出图
void print_graph(Graph* g)
{
for (int i = 0; i < g->vexnum; i++)
{
printf("\t%s", g->vextex[i]);
}
printf("\n");
for (int i = 0; i < g->vexnum; i++)
{
printf("%s\t", g->vextex[i]);
for (int j = 0; j < g->vexnum; j++)
{
if (g->martrix[i][j] == INT_MAX)
{
printf("∞\t");
}
else
{
printf("%d\t", g->martrix[i][j]);
}
}
printf("\n");
}
}
//定义最小生成树的边结构
typedef struct Arc
{
int begin;
int end;
}Arc;
//打印最小生成树
void print_tree(Graph* g, Arc* arc, int count)
{
printf("最小生成树:\n");
for (int i = 0; i < count; i++)
{
printf("%s--->%s\n", g->vextex[arc[i].begin], g->vextex[arc[i].end]);
}
}
// 普里姆算法
void graph_prim(Graph* g)
{
int lowcost[MAX];//顶点的与其他顶点的权值
int closest[MAX];//存储其前驱/父母结点
//创建一个名为arc的指针,指向一个Arc类型的数组,数组的大小为g->arcnum。
Arc* arc = (Arc*)malloc(sizeof(Arc) * g->arcnum);
assert(arc);
int count=0;//count用于控制存储数据进入arc数组
//0作为最小生成树的起点
for (int i = 0; i < g->vexnum; i++)
{
lowcost[i] = g->martrix[0][i];//lowcost数组用于存该点其它所有边的权值,无边则为INT_MAX
closest[i] = 0;//先将所有顶点的前驱结点都设为第一个顶点0
}
printf("最小生成树的形成过程:\n");
for (int i = 1; i < g->vexnum; i++)//注意i从1开始因为第一个顶点已经被处理了
{
int minweight = INT_MAX;
int k = -1;//k用于存储邻接最小权值边的顶点下标
for (int j = 0; j < g->vexnum; j++)
{
if (lowcost[j] > 0 && lowcost[j] < minweight)
//如果边存在且顶点未被加入最小生成树顶点或不是指向自身的话(因为一般指向自身是设为0的,这里统一都设成了INT_MAX)且小于minweight
{
minweight = lowcost[j];//将最小权值置为该边权值
k = j;//记录与该边邻接的顶点下标
}
}
if (k != -1)
{
printf("边<%s,%s>权为:%d\n",g->vextex[closest[k]],g->vextex[k],minweight);
//将这两个点存到边结构中(其实还可以做一个将权值也弄进去这个结构体的操作,但这里没有,只是存顶点)
(arc + count)->begin = closest[k];
(arc + count)->end = k;
count++;
//将lowcost数组中有关这两个权值都置为-1,表示已经加入到最小生成树权值中了(类似已访问)
lowcost[closest[k]] = -1;
lowcost[k] = -1;
//更新lowcost和closest数组(找到并置好邻接更小的权值,且置好其前驱节点)
for (int j = 0; j < g->vexnum; j++)
{
if (lowcost[j] != -1 && g->martrix[k][j] < lowcost[j])
//检查当前顶点 k 到其他顶点 j 的边的权重是否小于已知的最小权重 lowcost[j]
{
lowcost[j] = g->martrix[k][j];//将lowcost[j] 更新为当前顶点 k 到顶点 j 的边的权重(即置好小的权值再进入下一次循环查找)
closest[j] = k;//将 closest[j] 更新为当前顶点 k,表示顶点 j 最近的顶点是 k(相当于将k置为其前驱/parent结点)
}
}
}
}
print_tree(g, arc, count);
free(arc);
arc = NULL;
}
int main()
{
Graph g = { 10,7,{"A","B","C","D","E","F","G"},
{
{NO,50,60,NO,NO,NO,NO},
{50,NO,NO,65,40,NO,NO},
{60,NO,NO,52,NO,NO,45},
{NO,65,52,NO,50,30,42},
{NO,40,NO,50,NO,70,NO},
{NO,NO,NO,30,70,NO,NO},
{NO,NO,45,42,NO,NO,NO}
} };
print_graph(&g);
graph_prim(&g);
return 0;
}