kruskal算法形成最小生成树
prim是以顶点为中心,而kruskal算法是以边为中心。每次找到不会形成环路的最小的边。
具体实现:
#include <stdlib.h>
#include <stdio.h>
#define INFINITY 100
typedef struct
{
int vexs[9];
int arc[9][9];
int numVertexes,numEdges;
}MGragh;
typedef struct
{
int begin ;
int end;
int weight;
}Edge;
Edge edge[15];// edge不能在sort函数内部定义,因为是局部变量,返回时,edge[]会销毁,得到内容为随机数,必须是全局变量,或者从main函数中传入。
void CreateGragh(MGragh *G)
{
int i,j,k,w;
printf("input the vex and edges:");
scanf("%d%d",&G->numVertexes,&G->numEdges);
for (i=0; i<G->numVertexes; i++)
G->vexs[i]=i;
for (i=0; i<G->numVertexes; i++)
for (j=0; j<G->numVertexes; j++)
{
G->arc[i][j]=INFINITY;
G->arc[i][i]=0;
}
printf("input the (i,j)edge's value:\n");
for(k=0; k<G->numEdges;k++)
{
scanf("%d%d%d",&i,&j,&w);
G->arc[i][j]=w;
G->arc[j][i]=G->arc[i][j];
}
}
Edge* sort(MGragh *G)
{
int min,k=0,tmpbegin,tmpend,tmpvalue;
int i=0,j=0;
// 将邻接矩阵转换为edge[]数组
for(i=0; i<G->numVertexes; i++)
for(j=i+1; j<G->numVertexes;j++)
{
if(G->arc[i][j]!=INFINITY)
{
edge[k].begin=i;
edge[k].end=j;
edge[k].weight=G->arc[i][j];
k++;
//printf("(%d,%d)%d \n",edge[i].begin,edge[i].end,edge[i].weight);
}
}
//对边集数组edge[]按权值从小到大排序
for(i=0; i<G->numEdges-1; i++)
{
min=edge[i].weight;
k=i;
for(j=i+1; j<G->numEdges; j++)
{
if(edge[j].weight<min)
{
k=j;
min=edge[j].weight;
}
}
tmpbegin=edge[k].begin;
edge[k].begin=edge[i].begin;
edge[i].begin=tmpbegin;
tmpend=edge[k].end;
edge[k].end=edge[i].end;
edge[i].end=tmpend;
tmpvalue=edge[k].weight;
edge[k].weight=edge[i].weight;
edge[i].weight=tmpvalue;
}
//for(i=0; i<G->numEdges; i++)
//printf("%d,(%d,%d)%d \n",i,edge[i].begin,edge[i].end,edge[i].weight);
return edge;
}
int find(int *parent, int f)
{
while(parent[f]>0)
f=parent[f];
return f;
}
void MiniTree_Kruskal(MGragh *G)
{
Edge *edge;
int i,n,m;
int parent[9];
edge=sort(G);
//准备工作完成,开始进行
for(i=0; i<G->numVertexes; i++)
parent[i]=-1; // 初始状态,只有n个顶点的无边非连通图,写0也可以,但是因为有顶点0,所以,避免扰乱,改为-1
for(i=0; i<G->numEdges; i++)
{
n=find(parent,edge[i].begin);
m=find(parent,edge[i].end);
if(n!=m)
{
parent[n]=m;
printf("(%d,%d) %d",edge[i].begin,edge[i].end,edge[i].weight);
}
}
}
void main()
{
MGragh *gragh;
gragh=(MGragh *)malloc(sizeof(MGragh));
CreateGragh(gragh);
MiniTree_Kruskal(gragh);
system("pause");
}
输入:9 15
0 1 10
0 5 11
1 2 18
1 6 16
1 8 12
2 3 22
2 8 8
3 4 20
3 6 24
3 7 16
3 8 21
4 5 26
4 7 7
5 6 17
6 7 19
输出:(4,7) 7 (2,8) 8 (0,1) 10 (0,5) 11 (1,8) 12 (1,6) 16 (3,7) 16 (6,7) 19
kruskal算法中有个重要的数组parent[MAXVEX],用来判断是否会形成回路。
最重要的是弄清楚parent[i]数组表示的意义。该数组的内容i表示顶点,该数组的值表示与该顶点i直接或者间接相连。如parent[0]=1,表示v0v1顶点(直接或者通过中间结点)相连形成边。
那么它是如何判断回路呢?
以对边集定义的数据结构出发:
typedef struct
{
int begin;
int end;
int weight;
}Edge;
首先,将邻接矩阵对应的边集转换为按升序排列的Edge类型的数组 edges[MAXEDGE],从某条边的begin点,一步步找到从begin点已经连接的点,直到某个点不再与其他点连接,记该点为parent[k]=0,等于说以begin点为起始点,向已经连接的点寻找,该线路断与k点。
同理,以end点为起始的点,一步步向已经连接的点寻找,若也有parent[k]=0;则按照以begin/end为起点的点不断向上查找,可以找到从begin到end点之间存在通路,然而,以begin和end两点之间本身就是一条边。因而会形成环路。
for(i=0; i<G.numVertexes; i++)
parent[i]=0; //初始化,没有边关系。
for(i=0; i<G.numEdges; i++)
{
n=find(parent,edges[i].begin);
m=find(parent,edges[i].end);
if(m != n)
{
parent[n]=m;
printf("(%d,%d) %d",edges[i].begin, edges[i].end, edges[i].weight);
}
}
int find(int *parent,int f)
{
while(parent[f]>0)
f=parent[f];
return f;
}