目的:领会克鲁斯卡尔算法求带权连通图中最小生成树的过程和相关算法设计。
内容:编写一个程序exp8-7.cpp,实现求带权连通图最小生成树的克鲁斯卡尔算法。对于如图8.55所示的带权连通图G,输出从顶点0出发的一颗最小生成树。
[ 数据结构教程(第5版)李春葆 主编 ] 第8章上机练习实验题6
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
struct MatGraph
{
int edges[100][100];
int n;
};
typedef struct
{
int u,v;
int w;
}Edge;
bool cmp (Edge a,Edge b)
{
return a.w<b.w;
}
void Kruskal(MatGraph g)//Kruskal算法
{
int i,j,k,u1,v1,sn1,sn2;
int vset[1000];
Edge E[1000];//存放图中的所有边
k=0;//e数组的下标从0开始计
for(i=0;i<g.n;i++)//由g产生边集E,不重复选取同一条边
for(j=0;j<=i;j++)
{
if(g.edges[i][j]!=0&&g.edges[i][j]!=INF)
{
E[k].u=i;E[k].v=j;
E[k].w=g.edges[i][j];
k++;
}
}
sort(E,E+k,cmp);
for(i=0;i<g.n;i++)//初始化辅助数组
vset[i]=i;
k=1;//k表示当前构造生成树的第几条边,初值为1
j=0;//E中边的下标,初值为0
while(k<g.n)//生成的边数小于n时循环
{
u1=E[j].u;v1=E[j].v;//取一条边的两个顶点
sn1=vset[u1];
sn2=vset[v1];//分别得到两个边所属的集合编号
if(sn1!=sn2)//两顶点属于不同的集合,该边是最小生成树的一条边
{
printf("边(%d,%d)权为:%d\n",u1,v1,E[j].w);//输出最小生成树的一条边
k++;//生成边数增1
for(i=0;i<g.n;i++)//两个集合统一编号
if(vset[i]==sn2)//集合编号为sn2的改为sn1
vset[i]=sn1;
}
j++;//扫描下一条边
}
}
int main()
{
int i,j;
MatGraph g;
g.n=6;
for(i=0;i<=5;i++)
for(j=0;j<=5;j++){
if(i==j) g.edges[i][j]=0;
else g.edges[i][j]=INF;
}
g.edges[0][1]=g.edges[1][0]=5;
g.edges[0][2]=g.edges[2][0]=8;
g.edges[0][3]=g.edges[3][0]=7;
g.edges[0][5]=g.edges[5][0]=3;
g.edges[1][2]=g.edges[2][1]=4;
g.edges[2][3]=g.edges[3][2]=5;
g.edges[2][5]=g.edges[5][2]=9;
g.edges[3][4]=g.edges[4][3]=5;
g.edges[3][5]=g.edges[5][3]=6;
g.edges[4][5]=g.edges[5][4]=1;
printf("克鲁斯卡尔算法所求的最小生成树为:\n");
Kruskal(g);
return 0;
}
运行结果如下: