最小生成树——Kruskal算法
1,问题描述
设G=(V,E)是无向连通带权图,如果G的一个子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。生成树的各边权的总和称为该生成树的耗费,求在G的所有生成树中耗费最小的最小生成树。
2,算法思想
(1)将代价树中权值非0的所有的边进行小顶堆排序,依次存入到road[]数组中,然后将road[]进行倒置,注意在进行排序时,按照road[i]的权值进行排序,然后记录这条边的起始顶点也要相对应。
(2)从最小边开始扫描各边,并检测当前所选边的加入是否会构成回路,如果不会构成回路,则将该边并入到最小生成树中。
(3)不断重复步骤2,直到所有的边都检测完为止。
其中判断当前检测边的加入是否会使原来生成树构成回路的算法思想是:
取得顶点a根结点的算法实现为:
int GetRoot(int a){
while(a!=v[a]){
}
return a;
}
3程序设计
(1)所用数据结构,图的存储结构模块(nodetype.h)
#define maxSize 20
typedef struct{
}VertexType;
typedef struct{
}MGraph;
typedef struct{
}Road;
(2)主模块(main_Kruskal.cpp)
#include
#include
#include"nodetype.h"
#include"initlize.h"
#include"roadinfor.h"
#include"heapSort.h"
#include"kruskal.h"
int main(){
}
(3)读取数据模块,图的初始化(initlize.h)
//初始化图结构,录入图的信息
void Initlize(MGraph &g){
printf("请输入各边的权值:(不相临接的两顶点权值为0)\n\n");
}
MGraph g;
Road road[maxSize];
int v[maxSize];
//读取各边的信息,并将之存入road[]中
void Roadinfor(Road road[],int e){
}
(5)将待检测边进行堆排序模块(heapSort.h)
int Sizearray(Road road[]);
void Sift(Road road[],int low,int high);
//将边对象road2的信息赋值给边对象road1
void Switch(Road &road1,Road road2);
void verse(Road road[]);
void HeapSort(Road road[],int e){ //对边的权值进行堆排序,从小到大
//只需要从新的堆顶开始调准,只有堆顶可能不满足小顶堆条件
}
void Sift(Road road[],int low,int high){
}
int Sizearray(Road road[]){
}
void Switch(Road &road1,Road road2){
}
void verse(Road road[]){
}
(6)运用贪心策略——Kruskal算法构造最小生成树(kruskal.h)
int GetRoot(int a);
//Kruskal算法,实现求最小生成树
void Kruska(MGraph &g,Road road[],int v[],int &sum){
}
//顶点a所在的连通分支号
int GetRoot(int a){
}
6,实验总结
通过实现求最小生成树的两种算法,Prim算法和Kruskal算法,一个从顶点集考虑,一个从边集考虑,分别实现了构造最小生成树,当然Prim从单个顶点出发,利用贪心策略,开始顶点不同,可能构造的最小生成树可能不同,但最终的总耗费却是唯一的。同时思考问题的角度不同,带来执行算法效率的不同,Prim的时间复杂度为O(n2)(n为图的顶点数),与图的顶点数有关,边数无关,故适合顶点数目稀少的图,即密集图,而Kruskal的时间复杂度为O(eloge)(e为图中边的数目),与图的边数有关,故适合边数较少的稀疏图。