最小生成树-Kruscal算法

输入:创建图。

输出:组成最小生成树的所有边。

运行结果:

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

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

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

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

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

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

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

路呢?

我们可以用并查集。

看一下百科:

并查集,在一些有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;
      }
   }
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值