【克鲁斯卡尔算法基本思想】每次找出候选边中权值最小的边,就将该边并入生成树。重复此过程,直到所有边都被检测完成为止。
【克鲁斯卡尔算法执行过程】将图中边按照权值从小到大排序,然后从最小边开始扫描各边,并检测当前边是否是候选边,即是否该边加入到最小生成树中会产生回路。如果不构成回路,则将该边并入当前生成树中,直到所有边都被检测完成为止。
【并查集在克鲁斯卡尔算法中的应用】并查集中保存了一棵或者几棵树,这些树的特点为:通过树中的一个结点,可以找到其双亲结点,进而找到根结点(其实就是树的双亲存储结构)。这种特性有一下两个优点:第一,可以快速地将两个含有很多元素的集合合并为一个集合。两个集合就是并查集中的两棵树,只需找到其中一棵树的根,然后将其作为另一棵树中任何一个结点的孩子结点即可。第二,可以方便的判断两个元素是否属于同一个集合。通过这两个元素所在的结点找到他们的根结点,如果具有相同的根,则说明他们属于同一个集合,否则不属于同一个集合。并查集可以简单地用一维数组表示。
【克鲁斯卡尔算法的时间复杂度分析】克鲁斯卡尔算法的时间复杂度主要由排序函数决定。排序函数所处理数据的规模由图的边数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; } } }