最小生成树-Kruscal算法

输入:创建图。

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

最小生成树-Kruscal算法_第1张图片

运行结果:

最小生成树-Kruscal算法_第2张图片

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%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;xG.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%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;xadjvex]&&min>p->adj){ //可以选择 代价小
	      min=p->adj;
	      i=x;
	      j=p->adjvex;
	  }
	  p=p->nextarc;
      }
   }
}

 

你可能感兴趣的:(数据结构)