一、Kruskal算法
1.算法思想
设有两颗树 A , B A,B A,B,需要从中选取两个结点相连。
情况1:选取的结点 u , v u,v u,v属于同一颗树,则 u , v u,v u,v的连接必然使得那棵树形成回路,此时 A , B A,B A,B无论如何都不能再组成一颗树。
情况2:选取的结点 u , v u,v u,v分属于 A , B A,B A,B,则 u , v u,v u,v的连接不会构成回路,此时 A , B A,B A,B已然组成一颗新树 C C C
为了使得新树 C C C的总权值最小,需要使得 w = m i n { w e i g h t ( u , v ) , u ∈ A . V , v ∈ B . V } w=min \begin{Bmatrix}weight_{(u,v)},u\in A.V,v\in B.V \\ \end{Bmatrix} w=min{
weight(u,v),u∈A.V,v∈B.V};否则,必然可以构造出一个 A , B A,B A,B结合的总代价更小的生成树。
现将一个图中所有的 n n n个结点均看作一颗独立的只有根结点的树,从中可以选取一条权值最小的边来将某两颗树合并为一颗新树。按照上面的思想,需要判断该边连接的结点 u , v u,v u,v是否属于同一颗树,否则将有构成回路的风险。因此,每次取出所有边中权值最小的边 w w w,判断连接的结点 u , v u,v u,v是否是同一颗树,若是则不作考虑;若否则将两棵树合并为一棵树并将 u , w , v u,w,v u,w,v加入到结果集中,表示该边为最小生成树的一条边。直至边被取完。
2.算法步骤
S t e p 1 : Step 1: Step1:结果集置空
S t e p 2 : Step 2: Step2:将所有结点看作一颗只有一个元素的集合
S t e p 3 : Step 3: Step3:其次将所有边按照权值大小升序排列
S t e p 4 : Step 4: Step4:遍历已经排序好的边:1)如果边连接的两个结点在同一集合中,则不做任何操作;2)如果边连接的两个结点 u , v u,v u,v不在同一个集合中,则将这两个结点所在的集合合并为一个集合,并将 u , v u,v u,v加入结果集中
S t e p 5 : Step 5: Step5:返回结果
3.伪代码(参考自算法导论)
用到了并查集这一结构:并查集原理与实现
K r u s k a l ( G ) Kruskal(G) Kruskal(G)
1. A = ∅ 1.A=\varnothing 1.A=∅
2. f o r 2.for 2.for v ∈ G . V v \in G.V v∈G.V
M A K E − S E T ( v ) MAKE-SET(v) MAKE−SET(v)
3. e L i s t ← s o r t ( e ∈ G . E ) 3.eList\leftarrow sort(e \in G.E) 3.eList←sort(e∈G.E) / / o r d e r //order //order b y by by w e i g h t weight weight
4. f o r 4.for 4.for e ∈ e L i s t e \in eList e∈eList
i f if if F I N D − S E T ( u ) ≠ F I N D − S E T ( v ) FIND-SET(u)\ne FIND-SET(v) FIND−SET(u)=FIND−SET(v)
A = A ∪ ( u , v ) A=A\cup (u,v) A=A∪(u,v)
U N I O N ( u , v ) UNION(u,v) UNI