Kruskal算法是一种按权值的递增次序选择合适的边来构造最小生成树的方法。通常Kruskal算法用于求解稀疏图的最小生成树
- Kruskal算法的过程:
(1)置U的初值等于V(即包含图G中的全部顶点),置TE(最小生成树的边集)的初值为空集
(2)将图G中的边按权值从小到大的顺序依次选取:
① 若选取的边未使生成树T形成回路,则加入TE中
②否则舍弃,直到TE中包含(n-1)条边为止 - 具体过程如下图所示:
- Kruakal算法的设计:
(1)图采用哪种存储结构更合适?答:邻接矩阵
(2)边的排序问题怎么解决?答:设计一种排序方法,这里采用冒泡排序法
(3)如何解决加入一条边后是否出现回路?答:采用连通分量编号或顶点集合编号 - Kruakal算法代码实现:
#include <iostream>
#include<math.h>
#define MAXV 100
typedef struct
{
int n; //顶点信息
}VertexType;
typedef struct
{
int edges[MAXV][MAXV]; //邻接矩阵
int n, e; //顶点数、边数
VertexType vexs[MAXV]; //存放顶点信息
}MGraph;
typedef struct
{
int u; //边的起点
int v; //边的终点
int w; //边的权值
}Edge;
void InsertSort(Edge E[], int n)
{
int i, j;
Edge tmp;
for (i = 0; i < n - 1; i++)
{
for(j=n-1;j>i;j--)
if (E[j].w < E[j - 1].w)
{
tmp = E[j];
E[j] = E[j - 1];
E[j - 1] = tmp;
}
}
}
void Kruskal(MGraph g)
{
int i, j;
int u1=0, v1=0; //一条边的头尾顶点
int sn1=0, sn2=0; //边对应辅助数组的位置
int vset[MAXV]; //用于判断加入一条边后会不会出现回路
Edge E[MAXV]; //存放所有的边
int k=0; //E中的边的数目
for(int i=0;i<g.n;i++)
for(int j=i;j<g.n;j++)
if (g.edges[i][j] != 0)
{
E[k].u = i;
E[k].v = j;
E[k].w = g.edges[i][j];
k++;
} //将图中所有的边的信息都保存到E结构体
InsertSort(E, g.e);
for (i = 0; i < g.n; i++)
vset[i] = i;
k = 1; //开始构建最小生成树的第一条边
j = 0; //E中的下标
while (k < g.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++;
for (i = 0;i < g.n; i++)
{
if (vset[i] == sn2)
vset[i] = sn1;
}
}
j++;
}
}
int main()
{
MGraph G;
for (int i=0; i < 7; i++)
for (int j = 0; j < 7; j++)
G.edges[i][j] = 0;
G.edges[0][1] = G.edges[1][0] = 28;
G.edges[0][5] = G.edges[5][0] = 10;
G.edges[1][2] = G.edges[2][1] = 16;
G.edges[1][6] = G.edges[6][1] = 14;
G.edges[2][3] = G.edges[3][2] = 12;
G.edges[3][4] = G.edges[4][3] = 22;
G.edges[3][6] = G.edges[6][3] = 18;
G.edges[4][5] = G.edges[5][4] = 25;
G.edges[4][6] = G.edges[6][4] = 24;
G.n = 7;
G.e = 9;
/*for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 7; j++)
printf("%d ", G.edges[i][j]);
printf("\n");
}*/
Kruskal(G);
}
- 输出结果: