无向图的最小代价生成树之克鲁斯卡尔算法

【克鲁斯卡尔算法基本思想】每次找出候选边中权值最小的边,就将该边并入生成树。重复此过程,直到所有边都被检测完成为止。

【克鲁斯卡尔算法执行过程】将图中边按照权值从小到大排序,然后从最小边开始扫描各边,并检测当前边是否是候选边,即是否该边加入到最小生成树中会产生回路。如果不构成回路,则将该边并入当前生成树中,直到所有边都被检测完成为止。

【并查集在克鲁斯卡尔算法中的应用】并查集中保存了一棵或者几棵树,这些树的特点为:通过树中的一个结点,可以找到其双亲结点,进而找到根结点(其实就是树的双亲存储结构)。这种特性有一下两个优点:第一,可以快速地将两个含有很多元素的集合合并为一个集合。两个集合就是并查集中的两棵树,只需找到其中一棵树的根,然后将其作为另一棵树中任何一个结点的孩子结点即可。第二,可以方便的判断两个元素是否属于同一个集合。通过这两个元素所在的结点找到他们的根结点,如果具有相同的根,则说明他们属于同一个集合,否则不属于同一个集合。并查集可以简单地用一维数组表示。

【克鲁斯卡尔算法的时间复杂度分析】克鲁斯卡尔算法的时间复杂度主要由排序函数决定。排序函数所处理数据的规模由图的边数e决定,与顶点数无关,因此克鲁斯卡尔算法适用于稀疏图(边相对于顶点来说,少)。

【克鲁斯卡尔算法伪代码】

typedef struct{
	int a,b;	//a和b为一条边所连接的两个顶点
	int w;	//边的权值
}Road;

Road road[maxsize];
int v[maxsize];		//定义并查集

int getRoot(int a){		//在并查集中查找根结点的函数
	while(a != v[a]}
		a = v[a];
	return a;
}

void Kruskal(MGraph g,int sum,Road road[]){
	int i;
	int N,E,a,b;
	N = g.n;
	E = g.e;
	sum = 0;
	for(int i=0;i<=N;++i)
		v[i] = i;
	sort(road,E);	//对road数组中的E条边按权值按从小到大排序
	for(i=1;i<=E;++i){
		a = getRoot(road[i].a);
		b = getRoot(road[i].b);
		if(a != b){
			v[a] = b;
			sum += raod[i].w;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_36378917/article/details/80564363