[功能模块]
/* Kruskal算法的设计与实现 (WIN-TC调试通过)*/
#include "stdio.h"
#include "conio.h"
#define MAX 30
typedef struct
{ int v1,v2; /*每条边的两个顶点*/
int weight; /*边的权值*/
}EDGE;
typedef struct
{ int vnum; /*图的顶点数目*/
EDGE e[MAX*(MAX-1)/2]; /*图中的边*/
}Graph;
typedef struct node
{ int v; /*用链表存储同一个连通分量的顶点*/
struct node *next;
}Alist;
void heapadjust(EDGE data[],int s ,int m)
{ /*将元素序列data[s..m]调整为小根堆,堆顶元素为data[s]*/
int j;
EDGE t;
t=data[s]; /*备份元素data[s],为其找到适当位置后插入*/
for(j=2*s+1;j<=m;j=j*2+1) /*沿值较小的孩子结点向下筛选*/
{ if(j<m && data[j].weight>data[j+1].weight) j++;
if(!(t.weight>data[j].weight)) break;
data[s]=data[j];s=j; /*用s记录待插入元素的位置*/
}
data[s]=t; /*将备份元素插入由s所指出的位置*/
}
int creatgraph(Graph *p) /*输入图的顶点数和边数,创建一个图并返回图的边数*/
{ int n,m,v1,v2,w,k=0;
printf("输入图的顶点数:");
scanf("%d",&n);
if(n<1) return 0;
p->vnum=n;
printf("输入图的边数: ");
scanf("%d",&m);
while(k<m)
{ printf("输入第 %d 条边的两个顶点和权值:",k+1);
scanf("%d%d%d",&v1,&v2,&w);
/*if(v1>=0 && v1<n && v2>=0 && v2<n)*/
p->e[k].v1=v1;p->e[k].v2=v2;
p->e[k].weight=w;k++;
}
return m;
}
int kruskal(Graph G,int enumber,int tree[][3]) /*用kruskal算法求图G的最小生成树,返回其代价*/
{ int i,k,m,cost=0;
int v1,v2;
Alist *p,*q,*a[MAX];
for(i=0;i<G.vnum;i++) /*将每个连通分量的顶点存放在一个单链表中*/
{ a[i]=(Alist *)malloc(sizeof(Alist));
a[i]->v=i;a[i]->next=NULL;
}
for(i=enumber-1;i>=0;i--) /*按边上的权值建立小根堆*/
heapadjust(G.e,i,enumber-1);
k=G.vnum; /*k用于计算图中连通分量的数目*/
m=enumber-1;
i=0;
do
{ v1=G.e[0].v1;v2=G.e[0].v2;
p=a[v1];
while(p && p->v!=v2) /*判断当前所选择边的顶点是否在同一个连通分量中*/
{ q=p;p=p->next;}
if(!p) /*如果不在同一个连通分量中*/
{ p=q;
p->next=a[G.e[0].v2];
p=a[G.e[0].v1]; /*加入边(v1,v2),将两个连通分量合并为一个*/
while(p){a[p->v]=a[G.e[0].v1];p=p->next;}
k--; /*连通分量数目减少一个*/
tree[i][0]=v1; /*加入最小生成树中*/
tree[i][1]=v2;
tree[i][2]=G.e[0].weight;
cost+=G.e[0].weight;
i++;
}/*if*/
G.e[0]=G.e[m];
m--;
heapadjust(G.e,0,m); /*找下一条权值最小的边*/
}while(k>1); /*当所有的顶点不在同一个连通分量时,继续循环*/
return cost;
}
main()
{ int i,enumber,cost=0;
int tree[MAX][3];
Graph G;
enumber=creatgraph(&G);
cost=kruskal(G,enumber,tree);
printf("/n输出最小生成树的边集:/n");
for(i=0;i<G.vnum-1;i++)
printf("%d/t%d/t%d/n",tree[i][0],tree[i][1],tree[i][2]);
printf("/n最小生成树的成本为: %d" ,cost);
getch();
}
[测试方案]
假设有以下无向连通图:
用以上数据进行测试,程序的运行结果如下:
输入图的顶点数:4
输入图的边数: 6
输入第1条边的顶点和权值:1 2 10
输入第2条边的顶点和权值:1 3 75
输入第3条边的顶点和权值:1 4 20
输入第4条边的顶点和权值:2 3 85
输入第5条边的顶点和权值:2 4 40
输入第6条边的顶点和权值:3 4 35
输出最小生成树的边集:
1 2 10
1 4 20
3 4 35
最小生成树的成本为:65
由程序的运行结果可以验证所设计的算法是正确的。