这篇文章由 最小生成树-Prim算法和Kruskal算法 整理而来, 感谢这篇文章的作者
Prime算法
1. 概述
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。
2. 算法简单描述
输入:一个加权连通图,其中顶点集合为 V,边集合为 E;
初始化:Vnew = {x},其中 x 为集合 V 中的任一节点(起始点),Enew = {},为空;
-
重复下列操作,直到 Vnew = V:
在集合 E 中选取权值最小的边 <u, v>,其中 u 为集合 Vnew 中的元素,而v不在 Vnew 集合当中,并且 v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
将v加入集合 Vnew中,将 <u, v> 边加入集合 Enew 中;
4 .输出:使用集合 Vnew 和 Enew 来描述所得到的最小生成树。
下面对算法的图例描述
3. 简单证明prim算法
反证法:假设prim生成的不是最小生成树
设prime生成的树为 G0
假设存在 Gmin 使得cost(Gmin) < cost(G0) 则在 Gmin 中存在 <u,v> 不属于G0
将<u,v>加入 G0 中可得一个环,且 <u,v> 不是该环的最长边(这是因为 <u,v> ∈ Gmin)
这与prime每次生成最短边矛盾
故假设不成立,命题得证.
4. 代码实现
// to be done ...
5. 时间复杂度
Prime算法主要用于边比较多, 点比较少的时候
这里记顶点数v,边数e
邻接矩阵:O(v2)
邻接表:O(e * log2v)
Kruskal算法
1. 概览
Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有 Prime 算法和 Boruvka 算法等。三种算法都是贪婪算法的应用。和 Boruvka 算法不同的地方是,Kruskal 算法在图中存在相同权值的边时也有效。
2. 算法简单描述
记 Graph 中有v个顶点,e个边
新建图 Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
将原图 Graphnew 中所有e个边按权值从小到大排序
循环:从权值最小的边开始遍历每条边 直至图 Graphnew 中所有的节点都在同一个连通分量中
如果这条边连接的两个节点于图 Graphnew 中不在同一个连通分量中
添加这条边到图 Graphnew 中
图例描述:
3. 简单证明Kruskal算法
对图的顶点数 n 做归纳,证明 Kruskal 算法对任意 n 阶图适用。
归纳基础:
n = 1,显然能够找到最小生成树。
归纳过程:
假设 Kruskal 算法对 n ≤ k 阶图适用,那么,在 k + 1 阶图 G 中,我们把最短边的两个端点 a 和 b 做一个合并操作,即把 u 与 v 合为一个点 v',把原来接在 u 和 v 的边都接到 v' 上去,这样就能够得到一个 k阶图 G'(u ,v 的合并是 k + 1 少一条边),G' 最小生成树 T' 可以用Kruskal 算法得到。
我们证明 T' + {<u,v>} 是 G 的最小生成树。
用反证法,如果 T' + {<u,v>} 不是最小生成树,最小生成树是 T,即W(T) < W(T' + {<u,v>})。显然 T 应该包含 <u,v>,否则,可以用<u,v> 加入到 T 中,形成一个环,删除环上原有的任意一条边,形成一棵更小权值的生成树。而T - {<u,v>},是 G' 的生成树。所以 W(T-{<u,v>}) <= W(T'),也就是 W(T) <= W(T') + W(<u,v>) = W(T'+{<u,v>}),产生了矛盾。于是假设不成立,T' + {<u,v>}是 G 的最小生成树,Kruskal 算法对 k+1 阶图也适用。
由数学归纳法,Kruskal 算法得证。
4. 代码实现
// to be done ...
5. 时间复杂度
Kruskal算法主要用于边比较少, 点比较多的时候
e * log2e (e为图中的边数)