最小生成树-Kruscal算法

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83033223

运行结果:

Kruscal算法:找权值最小的边,若并入后构成回路则舍弃。

设N=(V,{E})是连通图,求最小生成树。

零T={V,{}},各顶点自成一连通分量。

在E中找代价最小的边,若该边顶点落在不同连通分量上,则将其并入,依次类推到所有顶点到一个连通分量上。

总复杂度O(eloge),与n无关,适合稀疏图。

Kruscal算法是逐条边读入,检查是否构成回路,Prim算法是逐个顶点并入,根据并入顶点找最小边。

算法思路有了,可是现在还有一个问题,如何判断加入边后是否构成回路呢?

我们可以用并查集。

扫描二维码关注公众号,回复: 3574780 查看本文章

看一下百科:

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。

关于并查集的原理可以参考此博客:

并查集详解

并查集实现:

int pre[MVNUM]; //记录各个结点的双亲
int find(int x){
	//查找x的根节点
   int r=x;
   while(r!=pre[r]) //不断找双亲 直到找到根节点
      r=pre[r];
   int i=x,j;
   while(i!=r){//路径压缩算法
      j=pre[i]; //找到双亲就记录
      pre[i]=r; //改变双亲为根节点
	  i=j;
   }
   return r;
}

算法实现:

邻接矩阵存储:

用Kruskal算法求网G最小生成树 输出各边,找权值最小的边 若并入后构成回路则舍弃.

void MiniSpanTree_Kruskal(MGraph G){
	//用Kruskal算法求网G最小生成树 输出各边
	//找权值最小的边 若并入后构成回路则舍弃
   int i,k,j,f1,f2,total;
   memset(a,0,sizeof(a)); //初始化
   for(k=0;k<G.vexnum;k++) //刚开始每个结点的双亲都是他自己
	   pre[k]=k;
   total=G.vexnum-1; //有n-1条边
   while(total)
   {
      MinArc(G,i,j); //找代价最小的边
      f1=find(i);
      f2=find(j);
      if(f1!=f2){ //不构成回路
	     printf("%c->%c\n",G.vexs[i],G.vexs[j]);
		 pre[f2]=f1; //修改双亲
		 total--;
	  }
      a[i][j]=TRUE; //每次把这条边设为不可取
   }
}

从图G中查找可以选择的代价最小的弧 用i,j返回两个结点的位置.

void MinArc(MGraph G,int &i,int &j){
   //从图G中查找可以选择的代价最小的弧 用i,j返回两个结点的位置
   int x,y;
   double min=INFINITY;
   for(x=0;x<G.vexnum;x++)
	   for(y=0;y<G.vexnum;y++)
		   if(!a[x][y]&&min>G.arcs[x][y].adj){ //可以选择 代价小
		     min=G.arcs[x][y].adj;
		     i=x;
			 j=y;
		  }
}

邻接表存储:

void MiniSpanTree_Kruskal(ALGraph G){
	//用Kruskal算法求网G最小生成树 输出各边
	//找权值最小的边 若并入后构成回路则舍弃
   int i,k,j,f1,f2,total;
   memset(a,0,sizeof(a)); //初始化
   for(k=0;k<G.vexnum;k++) //刚开始每个结点的双亲都是他自己
	   pre[k]=k;
   total=G.vexnum-1; //有n-1条边
   while(total)  {
      MinArc(G,i,j); //找代价最小的边
      f1=find(i);
      f2=find(j);
      if(f1!=f2){ //不构成回路
	     printf("%c->%c\n",G.vertices[i].data,G.vertices[j].data);
		 pre[f2]=f1; //修改双亲
		 total--;
	  }
      a[i][j]=TRUE; //每次把这条边设为不可取
   }
}

从图G中查找可以选择的代价最小的弧 用i,j返回两个结点的位置。

void MinArc(ALGraph G,int &i,int &j){
	//从图G中查找可以选择的代价最小的弧 用i,j返回两个结点的位置
   int x;
   double min=INFINITY;
   ArcNode *p;
   for(x=0;x<G.vexnum;x++) {
      p=G.vertices[x].firstarc;
      while(p){
		  if(!a[x][p->adjvex]&&min>p->adj){ //可以选择 代价小
		     min=p->adj;
		     i=x;
			 j=p->adjvex;
		 }
		 p=p->nextarc;
	  }
   }
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/83033223