最小生成树

来源:互联网 发布:.杀破狼 - js 编辑:程序博客网 时间:2024/05/17 00:58
今天开始进行最小生成树的学习,介绍两种方法Kruskal算法和Prim算法。两种算法理解起来都很简单,本来以为这两个算法是不需要做记录的,但是在实现的过程中还是遇到了一些问题。 Kruskal算法和Prim算法都是**贪心算法**,贪心算法的每一步必须在多个可能的选择中选择一种。贪心算法推荐选择在当前看来最好的选择。这种策略一般并不能找到一个全局最优的解决方案。当然,对于最小生成树来说,我们使用这种策略一定可以找到一棵权重最小的生成树。先介绍下最小生成树:> A minimum spanning tree is a spanning tree of a connected, undirected graph. It connects all the vertices together with the minimal total weighting for its edges.A single graph can have many different spanning trees. We can also assign a weight to each edge, which is a number representing how unfavorable it is, and use this to assign a weight to a spanning tree by computing the sum of the weights of the edges in that spanning tree. A minimum spanning tree (MST) or minimum weight spanning tree is then a spanning tree with weight less than or equal to the weight of every other spanning tree. More generally, any undirected graph (not necessarily connected) has a minimum spanning forest, which is a union of minimum spanning trees for its connected components.>
> >

Kruskal算法
>Kruskal’s algorithm is a minimum-spanning-tree algorithm which finds an edge of the least possible weight that connects any two trees in the forest.[1] It is a greedy algorithm in graph theory as it finds a minimum spanning tree for a connected weighted graph adding increasing cost arcs at each step.[1] This means it finds a subset of the edges that forms a tree that includes every vertex, where the total weight of all the edges in the tree is minimized. If the graph is not connected, then it finds a minimum spanning forest (a minimum spanning tree for each connected component).[点击这里有一份中文的Kruskal算法图解,可以参考](http://www.cnblogs.com/skywang12345/p/3711500.html) 这两种算法理解起来都不困难,Kruskal算法每次都选择图中的最小边,如果选择的边**不构成环路**即为最小生成树中的一条边。
MST-KRUSKAL(G,w)A != NULL ;for each vertex v∈G.VMAKE-SET(v)sort the edges of G.E into nondecreasing order by weight wfor each edge (u,v)∈G.E , taken in nondecreasing order by weightif FIND-SET(u) != FIND-SET(v)A = A ∪{u,v}UNION(u,v)return A
 选出最小边我们很容易就可以做到,我们只要把所有的边按照权值从小到大进行排序即可,然后依次检查每条边是否符合条件,到现在我们才遇到真正的问题,如何判断**我加入一条边后是否与已经存在的边构成环路???** 这里我们使用**并查集**(柱:并查集的相关知识这里先不做具体介绍,不过稍后会在文章末尾附上源代码链接,可以参考)的方法来实现上面说的那个功能,我们可以在 O(1)时间内判断如下
if FIND-SET(u) != FIND-SET(v)if FIND-SET(u) != FIND-SET(v)
在排序的地方我们使用快排方法可以将边的排序时间控制在O(eloge);
for each edge (u,v)∈G.E , taken in nondecreasing order by weight
**(其实这里是否存在可以优化的空间呢??最小生成的树的边数是不是可以确定为(v-1)即:顶点的个数减去1呢?)**最后给出整体的时间复杂度为O(ElogV) 当初写完程序没有当时总结,现在 再想,就有点忘记当初具体遇到了什么问题了,但是可以肯定是并查集是Kruskal算法效率的关键所在。
Prime算法
>1.将一个图的顶点分为两部分,一部分是最小生成树中的结点(A集合),另一部分是未处理的结点(B集合)。2.首先选择一个结点,将这个结点加入A中,然后,对集合A中的顶点遍历,找出A中顶点关联的边权值最小的那个(设为v),将此顶点从B中删除,加入集合A中。3.递归重复步骤2,直到B集合中的结点为空,结束此过程。4.A集合中的结点就是由Prime算法得到的最小生成树的结点,依照步骤2的结点连接这些顶点,得到的就是这个图的最小生成树。 同样Prim算法理解起来也很简单,将选入的顶点看成是一棵树,然后选择与这棵树相邻的边权值最小的,然后标记那个选中顶点归入到树中,此时最小生成树增加一个顶点。 现在,我们要解决的问题是如何从与最小生成树欋相邻的边中**快速**的找到最小的边??这里我们用到的是**优先队列**,我们可以用小顶堆来实现,算法导论书上说最好的情况下是使用**斐波那契堆**,之后会进行斐波那契堆的学习,因为现在还没有复习到那里,所以不会展开进行实现,这里在实现过程中使用的蝇STL的优先队列,出达到了相同的效果(效率方面暂时还不能确定使用斐波那契堆是否优于STL中的优先队列)
两种方法在实现过程中遇到的主要问题还是在实现优先队列和并查集中,但是这两部分内容还没有真正看到,所以在实现过程中尽量使用了简单或者已经存在的方法来减少相关操作。后期看相关内容时再进行补充![源码点击这里参考](https://github.com/tianzhuwei/-_-/tree/master/Introduction%20to%20Algorithms/Graph%20Algorithms/MinimumSpanningTrees)

报歉只能更到这里,内容不是很全面是因为耽搁时间有点久,期间准备英语考试。。。。

0 0
原创粉丝点击