下面讨论的两种最小生成树算法都是贪心算法。贪心算法的每一步必须在多个可能的选择中选择一种,贪心算法选择在当前看来最好的选择。
通用算法是每个时刻生长最小生成树的一条边(安全边),并在整个策略的实施过程中,管理一个遵守下述循环不变式的边集合A:在每遍循环之前,A是某棵最小生成树的子集。
GENERIC-MST(G,W)
A=∅
while A does not form a spanning tree
find an edge(u,v) that is safe for A
A=A∪{(u,v)}
return A
Kruskal算法:
找安全边,在所有连接森林中两颗不同树的边里面,找到权重最小的边(u,v)。
在该算法中,集合A是一个森林,其结点就是给定图的结点,每次加入集合A中的安全边永远是权重最小的连接两个不同分量的边。我们使用一个不相交集合(并查集)数据结构来维护几个互不相交的元素集合。每个集合代表当前森林中的一棵树。操作FIND-SET(u)用来返回包含元素u的集合的代表元素。我们可以通过测试FIND-SET(u)是否等于FIND-SET(v)来判断结点u和结点v是否属于同一棵树。使用UNION过程来对两棵树进行合并。
MST-KRUSKAL(G,w)
A=∅
for each vertex v∈G.v
MAKE-SET(v)
sort the each of G.E into nondecreasing order by weight w
for each edge(u,v)∈G.E,taken in nondecreasing order by weight
if FIND-SET(u)≠FIND-SET(v)
A=A∪{(u,v)}
UNION(u,v)
return A
Prim算法:
该算法中,集合A是一棵树。每次加入到A中的安全边永远是连接A和A之外某个结点的边中权重最小的边。在算法的执行过程中,所有不在树A中的结点都存放在一个基于key属性的最小优先队列Q中。对于每个结点v,属性v.key保存的是连接v和树中节点的所有边中所有边中最小的边的权重。
MST-PRIM(G,w,r)
for each u∈G.V
u:key=∞
u:π=NIL
r:key=0
Q=G.V
while Q≠∅
u=EXTRACT-MIN(Q)
for each v∈G.Adj[u]
if v∈Q and w(u,v)<v.key
v.=u
v.key=w(u,v)