数据结构与算法:最小生成树算法Krustal(C/C++)

一、算法描述

    1.遍历图结构并初始化边集合

    2.初始化连通分支集合。每个连通分支集合初始化标志元素指向自己

    3.对边集合从小到大排序

    4.遍历边集合,判断节点所属连通分支是否相同。

    5.如果4中判断的连通分支不相同,输出这条边。执行4

 

    说明:这里采用邻接矩阵方法储存图结构。


二、算法实现

void calculate_in_kruskal(MatGraph*gf)//Calculate minimum spanning tree 
{
	printf("\nKruskal:\n");
	ENode edge[MAXMUM];//Edge set to selete the minimun edge
	int ver[MAXMUM];//Vertex set pointing to the precurser
	int k=0;
	for(int i=0;in;i++)//Go through all the elements in matgraph
		for (int j = 0; j < gf->n; j++)
		{
			if (gf->edge[i][j] != -1)//Initialise all the edges in the graph
			{
				edge[k].n1 = i;
				edge[k].n2 = j;
				edge[k++].weight = gf->edge[i][j];
			}
		}
	quicksort(edge,0,k);//Sort the edge set to select the minimum edge
	for (int i = 0; i < gf->n; i++)//Initialise the vertex set and point it to itself
		ver[i] = i;
	int n1,n2;
	for (int k = 0; k < 2*gf->e; k++)//Select the minimum edge in sequence
	{
		n1 = edge[k].n1;//n1 is the precurser of the kth edge
		while (ver[n1] != n1)
			n1 = ver[n1];
		n2 = edge[k].n2;//n2 is the next vertex of the kth edge
		while (ver[n2] != n2)
			n2 = ver[n2];
		if (n1 != n2)//If the kth edge has different vertexs
		{
			ver[n1] = n2;
			printf("<%d,%d,%d>", edge[k].n1, edge[k].n2,edge[k].weight);
		}
	}
}

 

三、算法分析

 

 

   首先分析Krustal算法的基本思路。算法采用贪心法的设计思想,从最小的边开始,逐步依次选取更大的边,直到遍历完成所有的边。每选一条边,都要判断边的两个邻接点是否属于同一个连通分支,换一句话说,判断这条边是否具有切分性质。如果属于一个连通分支,那么舍弃这条边。算法的实现中采用并查集的策略判断不同节点的集合标志是否一样。(算法正确性证明略去)

   下面分析Krustal算法的时间复杂度。由算法描述可知,遍历邻接矩阵需要花费O(n^2)的渐进时间复杂度,把这一时间复杂度当做初始化过程不加以考虑。下面对边集合的排序使用快速排序算法,轴点构造选用三者取中法,因此平均意义下时间复杂度为O(e*loge)。当然,在这里的排序算法是任意的,更常用的算法取的是堆排序,因为堆排序更不容易退化为O(n^2)的最坏时间复杂度。下面我们遍历边集合,需要O(e)的时间复杂度。因此,算法的时间复杂度为O(e*loge).是一个复杂度仅与边的数量有关的算法,适合于稀疏图。

参考文献

[1]曲婉玲等,算法设计与分析(第2版),2016.2

[2]李春葆,数据结构教程(第5版),2017.5

 

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