最小生成树

一颗带权无向图的生成树的代价是该生成树中所有边的代价之和,最小代价生成树就是一颗代价最小的生成树,构建无向图的最小生成树就是采用贪心算法,不过对于最小生成树问题,需满足以下约束条件:

  • 只能使用图中的边
  • 只能使用恰好n-1条边
  • 不能使用产生环路的边
    Kruskal算法通过每次向当前最小代价生成树T中加入一条边的方法构成最终的最小生成树T,算法按照边的代价非递减的顺序选取,并加入T中,如果所选取的边与T中的边不形成环路,则这条边加入到T中,由于图G是连通的,且具有n个顶点,所以最终恰好选取n-1条边加入到T中。
    如图所示:
    最小生成树_第1张图片
权值 结果
初始化
(0,5) 10 加入树
(2,3) 12 加入
(1,6) 14 加入
(1,2) 16 加入
(3,6) 18 丢弃
(3,4) 22 加入
(4,6) 24 丢弃
(4,5) 25 加入
(0,1) 28 不再考虑

为了实现Kruskal算法,必须找出最小代价的边并将其从E中删除,如果把E中的边按权值进行排序,保存为一个顺序表,就可以有效的完成上述两个操作,但实际上,只要能够快速地找到下一条边最小代价的边,就没有要对E中的边进行排序,显然最小堆非常适合这个任务,因为最小堆可以在O(loge)时间内找出并删除下一条最小权值的边,而构造最小堆本身的时间复杂性为O(e).
伪代码实现:

//最小生成树算法
void create minTree()
{
   T={};//最小生成树的集合
   //T的边数需小于n-1,却无向图的边不能为空
   while(T.edgesCount<n-1&&E.edgesCount>0)
   {
      minHeap(v,w,E);//从无向图E集合选择最小代价的边
      delete(v,w,E);//删除该边
      //如果新加入边不构成环,则加入,否则丢弃
      if(!isCycle(v,w,T))
      {
         add(v,w,T)
      }
      else
      {
         discard(v,w)
      }
   }
   //检查最小生成树的边数是否满足约束条件
   if(T.egdescount!=n-1)
   {
      printf("No spanning tree\n");
   }
}

你可能感兴趣的:(最小生成树,kruskal算法)