最小生成树---Kruskal/Prime算法
1.Kruskal算法
图的存贮采用边集数组或邻接矩阵,权值相等的边在数组中排列次序可任意,边较多的不很实用,浪费时间,适合稀疏图。
方法:将图中边按其权值由小到大的次序顺序选取,若选边后不形成回路,则保留作为一条边,若形成回路则除去.依次选够(n-1)条边,即得最小生成树.(n为顶点数)。
Kruskal算法在图G=(V,E)上的运行时间取决于分离集合这一数据结构如何实现。采用在分离集合中描述的按行结合和通路压缩的启发式方法来实现分离集合森林的结构,这是从渐近意义上说,目前最快实现法。初始化占用时间O(V),对边排序需时间为O(E㏒E);对分离集的森林要进行O(E)次操作,共需时间为O(Ef(E,V)),其中f函数为Ackerman函数的反函数。因f(E,V)=O(㏒E),所以KruskaI全部运行时间为O(E㏒E)。
1 /*********************Kruskal算法********************/ 2 void Init_Kruskal_MST(void) 3 { 4 count=0; //边计数 5 sum_mst=0; //权值和 6 memset(MST,0,sizeof(MST)); 7 qsort(ESA,e,sizeof(ESA[0]),myComp); //按权值快速排序 8 } //注意调用方法 9 10 void Kruskal_MST(void) 11 { 12 int cn=0; 13 int u,v; 14 15 while(count < n-1) //边数判断 16 { 17 u=ESA[cn].from; 18 v=ESA[cn].to; 19 // cn++; 20 21 if(Find(u) != Find(v)) 22 { 23 MST[count].from=vertex[u]; 24 MST[count].to=vertex[v]; 25 count++; 26 sum_mst+=ESA[cn].wg; 27 Union(u,v); 28 } 29 cn++; //注意位置 30 } 31 }
2.Prime算法
方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树的边,并将集合外的那个顶点加入到集合中,表示该顶点已连通.如此下去直到全部顶点都加入到集合中,即得最小生成树.
① 置顶点集合V和边集E,它们的初始状态为空集。
② 任意选取一个顶点A加入V中。
③ 复以下过程直到V中已经包含原图的所有节点:
1、选一条权值最小的边(u,v),并使其满足u,v两节点只有一个在点集V中。
2、将两个节点中不在V的那个点加入集合V中,并将边(u,v)加入边集E中。
④ 所得的子图G’=(V,E)即为所求的最小生成树。
任意时刻的中间结果都是一棵树,每次花费最小的代价,用一条边把不在树中的结点加进来。按结点来贪,因此适用于稠密图的处理. 关键:找出当前最优得一条边,穷举每一条不在集合E中的边,找出符合条件且最优的边。邻接矩阵:O(v2) 。
1 void Init_Prime_MST(void) 2 { 3 flag=0; 4 sum_mst=0; 5 count=0; 6 for(int i=0;i<MG->n;i++) 7 { 8 vis[i]=0; 9 min_wg[i]=MG->edge[START][i]; //记录以i为终点的最小权值 10 min_from[i]=START; //记录最小权值边的起点 11 } 12 count=1; //默认第一个节点[编号0]已选【可以更改】 13 vis[START]=1; 14 min_from[START]=START; 15 } 16 17 void Prime_MST(void) 18 { 19 int min,to_index; //权值中间量,对应的到达顶点索引index 20 21 while(count < MG->n) 22 { 23 min=INF; 24 to_index=-1; 25 for(int i=0;i<MG->n;i++) 26 if(!vis[i] && (min_wg[i] < min)) 27 { 28 min=min_wg[i]; 29 to_index=i; 30 } 31 32 if(to_index != -1) //找到终点 33 { 34 vis[to_index]=1; 35 sum_mst+=min; 36 MST[count-1].from=MG->vertex[min_from[to_index]]; 37 MST[count-1].to=MG->vertex[to_index]; 38 count++; 39 40 if(count == MG->n) 41 flag=1; 42 } 43 else 44 break; 45 46 for(int j=0;j<MG->n;j++) //更新dist,使不在生成树上的点到生成树上的点的距离最小,直到所有的点都在生成树上。 47 if(!vis[j] && (min_wg[j] > MG->edge[to_index][j])) 48 { 49 min_wg[j]=MG->edge[to_index][j]; /* 更新权值信息 */ 50 min_from[j]=to_index; /* 更新最小权值边的起点 */ 51 } 52 } 53 }