具体的思路这里就不细讲了,网上有好多,我是看过 算法导论之后,因为其伪代码给的过于简单,想自己实现一下,参考了一篇博客,并对其进行了简单的改进,原博客比较简单好理解,一会儿附上链接,我将其中的排序改为了,快排,并讲并查集的操作写成了独立的函数
原文链接 最小生成树的Kruskal算法
代码保留了原博客的代码 (注释比较好理解)
#include<stdio.h>
#include <stdlib.h>
#define MAXSIZE 30
#define MAXCOST 32767
typedef struct
{
int u;//边的起始顶点
int v;//边的起始终点
int w;//边的权值
}Edge;
void Bubblesort(Edge R[],int e)//冒泡排序,对数组R中的e条边按权值递增排序
{
Edge temp;
int i,j,swap;
for(i=0;i<e-1;j++)//进行e-1趟排序
{
swap=0;
for(j=0;j<e-i-1;j++)
if(R[j].w>R[j+1].w)
{
temp=R[j];R[j]=R[j+1];R[j+1]=temp;//交换R[j]和R[j+1]
swap=1;//置有交换标志
}
if(swap==0) break;//本趟比较中未出现交换则结束排序
}
}
void Kruskal(int gm[][6],int n)//在顶点为n的连接图中构造最小的生成树,gm为连通网的邻接矩阵
{
int i, j, u1, v1, sn1, sn2, k;
int vest[MAXSIZE];//数组vest用于判断两顶点之间是否连通
Edge E[MAXSIZE];//MAXSIZE为可存放边数的最大常量值
k = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (i < j && gm[i][j] != MAXCOST)//MAXCOST为一个极大的常量值
{
E[k].u = i;
E[k].v = j;
E[k].w = gm[i][j];
k++;
}
}
}
Bubblesort(E,k);//采用冒泡排序对数组E中的k条边按权值递增排序
for(i=0;i<n;i++)//初始化辅助数组
vest[i]=i;//给每个顶点置不同连通分量编号,即初始时有n个连通分量
k=1;//k表示当前构造生成树的第n条边,初始值为1
j=0;//j为数组E中元素的下标,初值为0
while(k<n)//产生最小生成树的n-1条边
{
u1=E[j].u;v1=E[j].v;//取一条边的头尾顶点
sn1=vest[u1];
sn2=vest[v1];//分别得到这两个顶点所属的集合编号
if(sn1!=sn2)//两顶点分属于不同集合则该边为最小生成树的一条边
{
printf("Edge:(%d,%d),Wight:%d\n",u1,v1,E[j].w);
k++;//生成的边数增1
for(i=0;i<n;i++)//两个集合统一编号
if(vest[i]==sn2)//集合编号为sn2的第i号边其边号改为sn1
vest[i]=sn1;
}
j++;//扫描下一条边
}
}
// optimize sort function
/**
*
<stdlib.h> void qsort(void * base,size_t nmemb,size_t size ,int(*compar)(const void *,const void *))
参数说明:
base,要排序的数组
nmemb,数组中元素的数目
size,每个数组元素占用的内存空间,可使用sizeof函数获得
compar,指向函数的指针也即函数指针。这个函数用来比较两个数组元素,第一个参数大于,等于,小于第二个参数时,分别显示正值,零,负值。
*/
int compare(const void * a,const void * b){
Edge* n = (Edge*)a;
Edge* m = (Edge*)b;
return n->w>m->w?1:-1;
}
void quick_sort(Edge e[],int k){ // k is the number of edge
qsort(e,k,sizeof(Edge),compare); /// ;
}
int init_Edge(Edge e[],int n,int gm[][6]){
int i,j,k=0;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (i < j && gm[i][j] != MAXCOST)//MAXCOST为一个极大的常量值
{
e[k].u = i;
e[k].v = j;
e[k].w = gm[i][j];
k++;
}
}
}
return k;
}
/// union find find father
int find(int vest[],int i){
if(vest[i] == i){
return i;
}
else{
vest[i] = find(vest,vest[i]);
}
return vest[i];
}
void merge(int vest[],int i,int j){
vest[j] = vest[i];
}
// optimize Kruskal algorithm
/// use linked list save the graphic
/// or use the (ling jie biao)
/// or use std input to init Edge
int Kruskal_two(int g[][6],int n){ //n is the number or vertex
Edge e[MAXSIZE];
int k = init_Edge(e,n,g); ///k is the number of edge
int vest[MAXSIZE];
for(int i=0;i<n;i++){ //init union array ( bing cha ji)
vest[i] = i;
}
quick_sort(e,k);
k=1; /// present the number of mst's edge
int u1,v1,uf,vf;
int j=0; /// itrate e
while(k<n){
u1 = e[j].u;
v1 = e[j].v;
uf = find(vest,u1);
vf = find(vest,v1);
if(uf!=vf){
printf("Edge:(%d,%d),weight:%d\n",u1,v1,e[j].w);
k++;
merge(vest,uf,vf);
}
j++;
}
return 0;
}
void main()
{
int g[6][6]={{100,6,1,5,100,100},{6,100,5,100,3,100},{1,5,100,5,6,4},
{5,100,5,100,100,2},{100,3,6,100,100,6},{100,100,4,2,6,100}};
Kruskal_two(g,6);//生成最小生成树
printf("*****************************\n");
Kruskal(g,6);
}
/**
* result
* Edge:(0,2),weight:1
Edge:(3,5),weight:2
Edge:(1,4),weight:3
Edge:(2,5),weight:4
Edge:(1,2),weight:5
*/