#include<stdio.h>
#define MNUM 10
#define Arcnum_2 11
typedef struct
{
int vexs[MNUM]; //这里把数字作为顶点的代表 如果是字母可以为char vexs[MNUM];
int arcs[MNUM][MNUM];
int vexnum, arcnum;
}Graph;
typedef struct
{
int head;
int tail;
int lowcost;
}Edge;
Edge edge[Arcnum_2], temp;
int Vexset[MNUM]; /*标识各个顶点的连通分量, 对于每一个顶点vi属于V,
在辅助数组中存一个相应元素Vexset[i],表示该定点所在的联通分量,初始
时,Vexset[i] = i, 表示各顶点自成一个连通分量。*/
void Creat_graph(Graph * G)
{
int i, j, m, n, q;
scanf("%d %d", &G->vexnum, &G->arcnum);
for(i = 0; i < G->vexnum; i++){
G->vexs[i] = i;
}
for(i = 0; i < G->vexnum; i++){
for(j = 0; j < G->vexnum; j++){
if(i == j)
G->arcs[i][j] = 0;
else
G->arcs[i][j] = 99;
}
}
for(i = 0; i < G->arcnum; i++){
scanf("%d %d %d", &m, &n, &q);
G->arcs[m][n] = q;
G->arcs[n][m] = q; //建立无向图
edge[i].head = m;
edge[i].tail = n;
edge[i].lowcost = q;
}
}
void Sort(Edge edge[])
{
int i, j, k;
for(i = 0; i < Arcnum_2; i++){
k = i;
for(j = i + 1; j < Arcnum_2; j++){
if(edge[k].lowcost > edge[j].lowcost){
k = j;
}
if(k != i){
temp = edge[i];
edge[i] = edge[k];
edge[k] = temp;
}
}
}
}
void MiniSpanTree_Kruskal(Graph G)
{
int i, j;
int v1, v2, vs1, vs2;
Sort(edge);
for(i = 0; i < G.vexnum; i++){
Vexset[i] = i; //辅存数组,表示各个顶点自成一个连通分量
}
for(i = 0; i < G.arcnum; i++){ //**1**
v1 = edge[i].head;
v2 = edge[i].tail;
vs1 = Vexset[v1];
vs2 = Vexset[v2];
if(vs1 != vs2){
printf("%d --> %d\n", v1, v2);
for(j = 0; j < G.vexnum; j++){ /* **2** 需要找遍历俩遍边,第一次**1**为了查找最小的边,第二次**2**为了,
看看最小的边所连的顶点是否已经连通*/
if(Vexset[j] == vs2)
Vexset[j] = vs1; //类似于并查集,把同一个连通分量的编号都合到一起
}
}
}
}
int main()
{
Graph G;
Creat_graph(&G);
int i, j;
for(i = 0; i < G.vexnum; i++){
for(j = 0; j < G.vexnum; j++){
if(G.arcs[i][j] < 10)
printf("%d ", G.arcs[i][j]);
else
printf("%d ", G.arcs[i][j]);
}
putchar('\n');
} //输出
MiniSpanTree_Kruskal(G);
return 0;
}
运行结果为:
两个算法的比较:
最小生成树之普里姆算法:它是对点入手,有两次遍历顶点,第一次遍历为了访问各个顶点,第二次遍历为了更新每个顶点的权值,所以复杂度为o(n^2),比较适合用于稠密图。
最小生成树之克鲁斯卡尔算法:它是对边入手,复杂度为o(eloge),比较适合边数少的稀疏图。
仅供参考,如有不妥欢迎批评指正。