Kruskal算法是在处理一个森林——树的集合。开始时将图的每个顶点看做一棵树(集合),然后采用贪婪策略,每次从所有边中依次选出(Find)权值最小的边,当改边的两个端点不在同一集合时,则将终点所在集合与起点集合合并(Union),直到依次处理完所有的边,算法终止,此时所有的顶点在一个树中,即为最小生成树。
图一:初始时刻,所有顶点在各自集合中
图二:选择最小权值边AD,将集合A与集合D合并
图三:选择边CE,将集合C与集合E合并
图四:选择边BE,将集合ABDF与集合EC合并
图五:选择边EG,将集合G与集合ABCDEF合并。完成,所有点在同一集合中
实现代码:
<span style="color:#333333;">#include <stdio.h>
#include <stdlib.h>
#define INF 0x7fffffff
struct Graph
{
int v;//顶点数
int e;//边数
int graph[][MAX];//边权重数组
};
struct Edge
{
int s;//边起点
int m;//边终点
int w;//边权值
};
//将边按权值从小到大进行堆排序
void HeapSort(struct Edge* E);
int Kruskal(Graph G,int n)
{
int i,j,sum=0;
int* vset=(int*)malloc(n*sizeof(int));//标识每个顶点所属的集合
struct Edge* E=(struct Edge*)malloc((n-1)*sizeof(Edge));//边数组
for(i=0;i<n;++i)
vset[i]=i;
for(i=0;i<n-1;++i)
for(j=0;j<n-1;++j)
{
E[i].s=i;
E[i].m=j;
E[i].w=G.graph[i][j];
}
HeapSort(E);//排序
int sv;//记录起点所属集合
int mv;//记录终点所属集合
for(i=0;i<n-1;++i)//每次按权值大小,取出一条未处理的边
{
sv=vset[E[i].s];
mv=vset[E[i].m];
//边两端点不在同一集合,且两点确实连通
if(sv!=mv && G.graph[E[i].s][E[i].m]<INF)
{
printf("%d to %d : %d /n",E[i].s,E[i].m,E[i].w);
sum+=G.graph[E[i].s][E[i]].w;
for(j=0;j<n-1;++n)//集合合并:将终点及其集合中的所有其他顶点移到起点所在集合
{
if(vset[j]==mv)
vset[j]=sv;
}
}
}
free(vset);
free(E);
return sum;
}</span>