生成树和最小生成树均是在无向连通图中进行的。html
生成树:含有连通图的所有节点n,且含有n-1条边。一个连通图能够有多个生成树。算法
最小生成树:是基于带权的无向连通图,根据权值,按必定规则,代价最小的生成树为最小生成树。网络
找最小生成树,经典的两种算法,普利姆算法和克鲁斯卡尔算法。数据结构
一、普利姆(Prim)算法ide
最小生成树是数据结构中图的一种重要应用,它的要求是从一个带权无向彻底图中选择n-1条边并使这个图仍然连通(也即获得了一棵生成树),同时还要考虑使树的权最小。 为了获得最小生成树,人们设计了不少算法,最著名的有prim算法和kruskal算法。教材中介绍了prim算法,可是讲得不够详细,理解起来比较困难,为了帮助你们更好的理解这一算法,本文对书中的内容做了进一步的细化,但愿能对你们有所帮助。spa
假设V是图中顶点的
集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim算法经过如下步骤能够获得最小生成树:
1:初始化:U={u 0},TE={f}。此步骤设立一个只有结点u 0的结点集U和一个空的边集TE做为最小生成树的初始形态,在随后的算法执行中,这个形态会不断的发生变化,直到获得最小生成树为止。
2:在全部u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u 0,v 0),将此边加进集合TE中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边知足如下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边之后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。这一步骤在算法中应执行屡次,每执行一次,集合TE和U都将发生变化,分别增长一条边和一个顶点,所以,TE和U是两个动态的集合,这一点在理解算法时要密切注意。
3:若是U=V,则算法结束;不然重复步骤2。能够把本步骤当作循环终止条件。咱们能够算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增长了n-1条边,这n-1条边就是须要求出的最小生成树的边。
二、克鲁斯卡尔(Kruskal)算法
求加权
连通图的最小生成树的算法。kruskal
算法每次选择n- 1条边,所使用的贪婪准则是:从剩下的边中选择一条不会产生
环路的具备最小耗费的边加入已选择的边的集合中。注意到所选取的边若产生环路则不可能造成一棵生成树。kruskal算法分e 步,其中e 是网络中边的数目。按耗费递增的顺序来考虑这e 条边,每次考虑一条边。当考虑某条边时,若将其加入到已选边的集合中会出现环路,则将其抛弃,不然,将它选入。
克鲁斯卡尔算法
假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造
最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点当作是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。以后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不一样的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
举例:
克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个。这里面充分体现了贪心算法的精髓。大体的流程能够用一个图来表示。这里的图的选择借用了Wikipedia上的那个。很是清晰且直观。
首先第一步,咱们有一张图,有若干点和边
以下图所示:
.
.
.
.
.
第一步咱们要作的事情就是将全部的边的长度排序,用排序的结果做为咱们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择。
排序完成后,咱们率先选择了边AD。这样咱们的图就变成了
.
.
.
.
.
第二步,在剩下的边中寻找。咱们找到了CE。这里边的权重也是5
.
.
.
.
.
依次类推咱们找到了6,7,7。完成以后,图变成了这个样子。
.
.
.
.
.
下一步就是关键了。下面选择那条边呢? BC或者EF吗?都不是,尽管如今长度为8的边是最小的未选择的边。可是他们已经连通了(对于BC能够经过CE,EB来链接,相似的EF能够经过EB,BA,AD,DF来接连)。因此咱们不须要选择他们。相似的BD也已经连通了(这里上图的连通线用红色表示了)。
最后就剩下EG和FG了。固然咱们选择了EG。最后成功的图就是下图:
.
.
.
.
.
到这里全部的边点都已经连通了,一个最小生成树构建完成。
Kruskal算法的时间复杂度由排序算法决定,若采用快排则时间复杂度为O(N log N)。