Prim演算法,同Kruskal演算法一樣,也是解決最小產生樹的演算法。在講這個演算法前,我們先來看看其他的一些概念。
什麼是割?在無向圖中,割指的是對圖的一種劃分。當一條邊(u,v)的一個頂點屬於S,另一個頂點屬於V-S,則我們稱(u,v)邊通過割(S,V-S)。如果一個邊的集合A中沒有任何一條邊通過割,則我們稱該割不妨害邊集A。如果某條邊的權值在通過某個割的所有邊中是最小的,則稱該邊是通過該割的一條輕邊。
Prim演算法的基本思想就是不斷的尋找通過一條割的輕邊,這個割是指當前最小產生樹所組成的點集S和圖中不在最小產生樹中的點集(V-S)所形成的一種圖的劃分,然後將所找到的輕邊添加到最小產生樹中。我們使用最小優先隊列來快速的尋找通過某個割的輕邊。當然,我們在尋找輕邊的時候要檢查該邊的兩個頂點是否已經在最小產生樹中,如果在的話,我們就不需要再將這條邊添加到最小產生樹的邊集了,因為這兩個端點已經是連通著的了。
代碼實現如下所示:
package com.chapter4;
//用於解決最小產生樹問題的Prim演算法(延時版本)
import java.util.Queue;
import java.util.LinkedList;
public class LazyPrimMST {
privateQueue<Edge> mst;
private boolean[]marked;
private doubletotalweight;
privateMinPriorityQueue<Edge> mpq;
publicLazyPrimMST(EdgeWeightedGraph G)
{
int V=G.V();
mst=newLinkedList<Edge>();
marked=newboolean[V];
mpq=newMinPriorityQueue<Edge>();
for(inti=0;i<V;i++)
{
if(!marked[i])
prim(G,i);
}
}
private voidprim(EdgeWeightedGraph G,int s)
{
scan(G,s);
while(!mpq.isEmpty())
{
Edgee=mpq.deleteMin();
System.out.println("從優先隊列中移除"+e);
intv=e.either(),w=e.other(v);
assertmarked[v]||marked[w];
if(marked[v]&&marked[w])continue;
mst.add(e);
System.out.println("向最小產生樹的邊集合中加入"+e);
totalweight+=e.weight();
if(!marked[v])scan(G,v);
if(!marked[w])scan(G,w);
}
}
private voidscan(EdgeWeightedGraph G,int v)
{
assert!marked[v];
marked[v]=true;
for(Edgee:G.adj(v))
{
if(!marked[e.other(v)])
{
mpq.insert(e);
System.out.println("向優先隊列中加入"+e);
}
}
}
public doubletotalWeight(){return totalweight;}
public StringtoString()
{
StringBuildersb=new StringBuilder();
sb.append("最小產生樹的邊資訊:\n");
for(Edgee:mst)
{
sb.append(e.toString()+"\n");
}
sb.append(String.format("權值和為:%.5f",totalweight));
returnsb.toString();
}
public static voidmain(String[] args) {
// TODOAuto-generated method stub
In in=newIn("tinyEWG.txt");
EdgeWeightedGraphgraph=new EdgeWeightedGraph(in);
LazyPrimMSTsample=new LazyPrimMST(graph);
System.out.println(sample);
}
}
運行結果如下所示:
向優先隊列中加入0--7[0.16000]
向優先隊列中加入0--4[0.38000]
向優先隊列中加入0--2[0.26000]
向優先隊列中加入6--0[0.58000]
從優先隊列中移除0--7[0.16000]
向最小產生樹的邊集合中加入0--7[0.16000]
向優先隊列中加入4--7[0.37000]
向優先隊列中加入5--7[0.28000]
向優先隊列中加入1--7[0.19000]
向優先隊列中加入2--7[0.34000]
從優先隊列中移除1--7[0.19000]
向最小產生樹的邊集合中加入1--7[0.19000]
向優先隊列中加入1--5[0.32000]
向優先隊列中加入1--2[0.36000]
向優先隊列中加入1--3[0.29000]
從優先隊列中移除0--2[0.26000]
向最小產生樹的邊集合中加入0--2[0.26000]
向優先隊列中加入2--3[0.17000]
向優先隊列中加入6--2[0.40000]
從優先隊列中移除2--3[0.17000]
向最小產生樹的邊集合中加入2--3[0.17000]
向優先隊列中加入3--6[0.52000]
從優先隊列中移除5--7[0.28000]
向最小產生樹的邊集合中加入5--7[0.28000]
向優先隊列中加入4--5[0.35000]
從優先隊列中移除1--3[0.29000]
從優先隊列中移除1--5[0.32000]
從優先隊列中移除2--7[0.34000]
從優先隊列中移除4--5[0.35000]
向最小產生樹的邊集合中加入4--5[0.35000]
向優先隊列中加入6--4[0.93000]
從優先隊列中移除1--2[0.36000]
從優先隊列中移除4--7[0.37000]
從優先隊列中移除0--4[0.38000]
從優先隊列中移除6--2[0.40000]
向最小產生樹的邊集合中加入6--2[0.40000]
從優先隊列中移除3--6[0.52000]
從優先隊列中移除6--0[0.58000]
從優先隊列中移除6--4[0.93000]
最小產生樹的邊資訊:
0--7[0.16000]
1--7[0.19000]
0--2[0.26000]
2--3[0.17000]
5--7[0.28000]
4--5[0.35000]
6--2[0.40000]
權值和為:1.81000
(說明:程式中需要的其他一些類可以在“用於最小產生樹的Kruskal演算法實現”一文中查到,在這篇文章中不在重複!)
文章連結: http://blog.csdn.net/andamajing/article/details/8702179點擊開啟連結