最小生成树-克鲁斯卡尔算法(Kruskal算法)

问题出发点:

对于任意一个连通网的最小生成树来说,在要求总的权值最小的情况下,最直接的想法就是将连通网中的所有边按照权值大小进行升序排序,从小到大依次选择。

条件控制
1.任意定点之间只有一条通路,不能产生环
2.对于n个顶点的生成树只有n-1条通路即可
具体思路
1.先将边按照边的权值排序
2.从小到大依次判断边,若加入该边不形成环,则将该边加入其中,反之,继续扫描下一条边
3.判断结束条件:加入的边为n-1条
具体实现

如何判断是否成环?

//parent[i]表示i结点在已经生成树中可到达结点;
int Find(int x){
	while(parent[x]>0){
		x=parent[x];
	}	return x;
}
void Kruskal(){
	int k=0,i=0;
 	printf("The lostpath:\n");
	while(k<n-1){
		int a=Find(sortedge[i].form);  //获取已经排序边表中一端点的可到达端点a
		int b=Find(sortedge[i].to);  //获取已经排序边表中另一端点的可到达端点b
		if(a!=b){//若ab不相同,则表示不能形成换
			parent[a]=b;//将a的可到达端点设为b,以便判断下一条边是否形成环
			//输出加入生成树的边
			printf("%d %d %d\n",sortedge[i].form,sortedge[i].to,sortedge[i].weight);
			k++;
	    }
	    i++;
	}
}
算法实现源码
#include
#include
#define N 20
#define inex 1001
int c[7][7]={   //用邻接表存储图结构,inex表示两端点不可达 
{},
{inex,0,6,1,5,inex,inex},
{inex,6,0,5,inex,3,inex},
{inex,1,5,0,5,4,6},
{inex,5,inex,5,inex,inex,2},
{inex,inex,3,6,inex,0,6},
{inex,inex,inex,2,4,6,0},
};
typedef struct edge{ //构造有序图标数据结构 
	int form; //起始端点 
	int to; //目标端点 
	int weight;//两端点边的权值 
}E;
E sortedge[101],t[101];//t用于排序,将结果赋值给sortedge 
int parent[101]={};//判断是否成环的数据结构 
int n=6;//端点数 
int em(int k,int i,int j){//因为图为无相图,该函数判断是否该边已经加入变表 
    for(int z=0;z<k;z++){
    	if(sortedge[z].form==i&&sortedge[z].to==j){
    		return 0;
		}
		if(sortedge[z].form==j&&sortedge[z].to==i){
			return 0;
		}
	}
	return 1;
}
void sort(){//排序变表 
	int k=0;
	E t;
	for(int i=1;i<=n;i++){ //将所有边无重复的加入边表t中 
		for(int j=1;j<=n;j++){
			if(c[i][j]>0&&c[i][j]<inex&&em(k,i,j)==1){
				sortedge[k].form=i; 
				sortedge[k].to=j;
				sortedge[k].weight=c[i][j];
				k++;
			}
		}
	}
	for(int i=0;i<k;i++){  //选择法排序 
       int min=sortedge[i].weight;
       int minid=i;
       for(int j=i+1;j<k;j++){
       	  if(sortedge[j].weight<min){
       	  	min=sortedge[j].weight;
       	  	minid=j;
			 }
	   }
	   t=sortedge[i];
	   sortedge[i]=sortedge[minid];
	   sortedge[minid]=t;
	}
	printf("\nThe edge after sorting:\n");
	for(int i=0;i<k;i++){  //将排序结果赋值给 sortedge
		printf("%d   %d   %d\n",sortedge[i].form,sortedge[i].to,sortedge[i].weight);
	}
}
//parent[i]表示i结点在已经生成树中可到达结点;
int Find(int x){
	while(parent[x]>0){
		x=parent[x];
	}	return x;
}
void Kruskal(){
	int k=0,i=0;
 	printf("The lostpath:\n");
	while(k<n-1){
		int a=Find(sortedge[i].form);  //获取已经排序边表中一端点的可到达端点a
		int b=Find(sortedge[i].to);  //获取已经排序边表中另一端点的可到达端点b
		if(a!=b){//若ab不相同,则表示不能形成换
			parent[a]=b;//将a的可到达端点设为b,以便判断下一条边是否形成环
			//输出加入生成树的边
			printf("%d %d %d\n",sortedge[i].form,sortedge[i].to,sortedge[i].weight);
			k++;
	    }
	    i++;
	}
}

int main(){//主函数入口 
	sort();
	Kruskal();
}
运行结果

最小生成树-克鲁斯卡尔算法(Kruskal算法)_第1张图片

你可能感兴趣的:(算法)