最小生成树寻路(prim)

接着上一次的kruskal算法,此次讲更高级的prim算法算法

#Prim Algorithm prim算法和经典的Dijkstra最短路径寻路算法惊人的类似,都是采用层层扩散的方式收敛出树。同时又与kruskal算法分享着相似的逻辑。关于Dijkstra算法敬请参考以前发布的《SPF算法完美教程》,若是没听过它也无碍,prim算法将展现它的思想。 前提准备:总共n个节点编号,放入集合甲中,设一个集合乙用来存放生成树成长过程当中依次覆盖的节点,记这棵生成树年轻时为T。(注意,这是个动态生长的树,从0开始直到长成最小生成树) Prim算法的基本流程(一个周期):(同kruskal同样也是经过一个个简单的循环来完成的) 首先,从甲中取出一个距离T最短的节点Q,就是乙中全部节点的全部外部邻居中最近的那个点,若是是第一次循环的话就从甲中随机取出一点。(如果并列最短就随便选)。而后将这个点加入到乙中。以此循环直到甲空掉了为止。 (@ο@) 哇~是否是感受比kruskal算法还要简单直接,流程图都不须要画了(由于是一条笔直的直线流程),若是将各个循环结束时的状态图记录下来,就会看到一棵生成树从小长到大的过程。如同这个动态图: 输入图片说明 ##有待调用的重要前提:教程

在证实prim算法以前咱们须要用到一个底层结论:在一个连通图G中,对于每一个点,与本身相连的最短边必定属于G的生成树。(若是有并列则任意一个最短边) 这个结论very重要,想要证实他也很easy,仍是用万能的反证法: 对于一个点Q它链接着m条边,其中有一条最短边L,G的最小生成树T不通过L,那么对于Q剩下m-1条边中至少有一条边链接Q与T,设有z条这样的边(0<z<m)。 那么若是此时在T中把Q及Q链接的m条边都移除,T剩下的部分将被分红z个相互隔离的部分(生成树的特性),并且Q关于L对称的那个点有且只有属于z个部分中的某一个部分。那么问题来了,属于的那个部分与Q相连的边应当被替换成开销更小的L,因此与T是最小生成树矛盾,得以反证。 上图解(图中z=3): 输入图片说明 这样就一清二楚了(吧?),图中各个区域的“树枝”符号就表明了被分割的部分树,他们之间只能经过Q相通。因此Q的最短边L必然在真正的生成树中。图片

##数学概括法证实:数学

有了这个结论后大势已定,接下来我将展现用经典的数学概括法证实prim算法,其中以集合乙中的节点数量为递增变量(因此这里的n是动态的),也能够当作是动态增加的树T。 n=1,选择任意一个点Q1。 n=2,Q1发散到最近的Q2其中边L1属于最终最小生成树T,成立。 假设n=k的时候成立,也就是Q1Q2Q3一直到Qk所在的T属于最终最小生成树。 那么接下来作一个惊人之举:把此时的T总体当作一个节点。为何能够这么看呢,由于T和一个节点share共同的属性:都是属于最终生成树;都有若干个与本身相连的边。于是此举不影响最后的生成树。记住,最小生成树的根本目的和原则就是千方百计不择手段地用最少的边链接最多的节点! 输入图片说明 当n=k+1的时候,从甲中剩下的节点中选择距离T(点)最近的一条边Lk加入到乙中,根据以前定理,T+Lk一块儿也属于最终生成树。成立。 由数学概括法得证prim算法的正确性。完。it

##最后,两种算法的异同变量

不难看出,两种基本算法的内容都通俗易懂,只是证实起来略有困难。二者的区别在于,kruskal基于边来收敛,而prim基于点。可是综合来看prim要比kruskal高级一点,在边数比较稠密的状况下用prim求生成树要快于kruskal,由于kruskal是一条边一条边来找的,毕竟prim使用和Dijkstra类似的“堆栈”思想而kruskal是一种贪心算法,当边稀疏时二者均可适用。Anyway,两者都是图论学中很是重要的算法,你们务必牢记!循环

相关文章
相关标签/搜索