克鲁斯卡尔算法&普里姆算法

克鲁斯卡尔算法  
假设  WN=(V,{E})  是一个含有  n  个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含  n  个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有  n  棵树的一个森林。之后,从网的边集  E  中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有  n-1条边为止。

普里姆算法  
假设  WN=(V,{E})  是一个含有  n  个顶点的连通网,TV  是  WN  上最小生成树中顶点的集合,TE  是最小生成树中边的集合。显然,在算法执行结束时,TV=V,而  TE  是  E  的一个子集。在算法开始执行时,TE  为空集,TV  中只有一个顶点,因此,按普里姆算法构造最小生成树的过程为:在所有“其一个顶点已经落在生成树上,而另一个顶点尚未落在生成树上”的边中取一条权值为最小的边,逐条加在生成树上,直至生成树中含有  n-1条边为止。  
--------------------------------------------------------------  
克鲁斯卡尔算法(1)

void kruskal (edgeset ge, int n, int e)
// ge为权按从小到大排序的边集数组
{        
	int set[MAXE], v1, v2, i, j;
    for (i=1;i<=n;i++)
		set[i]=0;	// 给set中每个元素赋初值
	i=1;// i表示获取的生成树中的边数,初值为1
	j=1;// j表示ge中的下标,初始值为1
    while (j
克鲁斯卡尔算法(2)

//kruskal  
void  MiniSpanTree_Kruskal(CGraph  gn)  
{  
//按算法构造网gn的最小生成树并输出生成树上各条边/  
   T.init(gn.vexes,null);    
   hp.init(gn)    //堆初始化,堆中元素        
   heap_sort(hp);    //为网gn的所有边          
   while(  (hp.Last>0)  &&  (T.Arcn1  )              
           heap_sift(hp,1,hp.Last);//求下一条最小代价边      
   }  
   if(  T.Arcn


------------------------------------------------------------------------------  

 普里姆算法

//prim  

#include    
#include    
 
#define  MAXVEX  30  
#define  MAXCOST  1000  
 
/*每一步扫描数组lowcost,在V-U中找出离U最近的顶点,令其为k,并打印边(k,closest[k])*/  
/*然后修改lowcost和closest,标记k已经假如U  。c表示图邻接矩阵,弱不存在边(i,j),则c[i][j]的值为一个大于任何权而小于无限打的阐述,这里用MAXCOST表示*/  
void  prim  (int  c[MAXVEX][MAXVEX],  int  n)/*一直图的顶点为{1,2,...,n},c[i][j]为(i,j)的权,打印最小生成树的每条边*/  
{  
           int  i,j,k,min,lowcost[MAXVEX],closest[MAXVEX];  
           for  (i=2;i<=n;i++)  /*从顶点1开始*/  
           {  
                       lowcost[i]=c[1][i];  
                       closest[i]=1;  
           }  
           closest[1]=0;  
           for  (i=2;i<=n;i++)  /*从U之外求离U中某一顶点最近的顶点*/  
           {  
                       min=MAXCOST;  
                       j=1;  
                       k=i;  
                       while  (j<=n)  
                       {  
                                   if  (lowcost[j]

/****************************************************************************************/

我们这里讨论的是无向图的最小生成树,有向图的最小生成树算法比较复杂,如果感兴趣可以参看清华大学的《信息学奥林匹克竞赛指导-图论的算法与程序设计》。

所谓最小生成树,就是给定一个无向图,挑选若干条边,连成一个树行图(无圈),使得所选边的权至和最小。

一下算法中,n是点数,e是边数。

1.Prime

初始时任选一点s为树根,每次选出一条权最小的边[i,j],使得点i在树中,点j不在树中,将j和[i,j]加入树中,重复n-1次求出最小生成树。

我们用二叉堆来提高效率。二叉堆中存储边,初始时二叉堆中存储与s关联的边,每次取出一个权最小的边[i,j],删除[i,j],同时将与j关联的边放入二叉堆中,注意判重。

因为所有边只放入和取出二叉堆一次,所以算法复杂度是(eloge)。

2.Kruskal

从所有边中找到一个最小的边,且将改变放入后不会生成圈,重复n-1次后求出最小生成树。

我们首先将所有边排序,然后从小到大判断,如果不产生圈就加入树中,当加入n-1条边时停止。

为了判断是否组成圈,我们要用到并查集,相关知识可以在本站或任一本竞赛书中找到,这里不赘述。

算法复杂度是(eloge+eα),α是做一次并查集的复杂度,可以认为是常数。

两种算法同样优秀。


你可能感兴趣的:(算法分析)