Prim算法詳解


Prim算法是干什么的?

Prim算法可以計算出一個無向加權圖的最小生成樹

什么是最小生成樹?

首先,樹兩個最重要的性質是①用一條邊連接樹中的任意兩點都會產生一個新的環從樹中刪除一條邊將會得到兩棵獨立的樹最小生成樹即為連接圖中所有點,且總權重最小的樹。最小生成樹的性質:將圖中的點分為兩個集合,橫跨兩個集合的邊中權重最

小的邊必在最小生成樹中(並不只有權重最小邊在樹中)

最小生成樹的性質的證明:

用反證法,如果權重最小的邊 e 不在樹中,那和它橫跨兩個相同的集合且權重比它大的邊 f 樹一定在樹中,如果把 e 加入樹中,再將 f 刪除,則得到一個權重更小的樹,所以 e 必在樹中

Prim算法如何進行計算?

①選定一個點做為一個集合 a ,剩下的點為另一個集合 b

②將橫跨兩個集合且權重在其中最小的邊加入最小生成樹

③將剛剛加入最小生成樹的邊中不在集合 a 中的點加入集合 a,直到所有的點加入集合 a

具體到代碼如何計算?

 1 class MST {
 2     private boolean[] marked; //點是否已在樹中
 3     private double[] distTo; //點到樹的距離
 4     private ArrayList<Edge> mst; //最小生成樹
 5     private EdgeWeightedGraph G; //要處理的圖
 6     private TreeMap<Double, Edge> pq; //保存一個點到樹距離最短的邊和那個距離 按距離從小到大的優先隊列
 7     
 8     public MST(EdgeWeightedGraph G) {
 9         this.G = G;
10         int V = G.V();
11         marked = new boolean[V];
12         distTo = new double[V];
13         mst = new ArrayList<>();
14         pq = new TreeMap<>();
15         //將所有點到樹的距離設置為正無窮
16         for (int i = 0; i < distTo.length; i++)
17             distTo[i] = Double.POSITIVE_INFINITY;
18         //0到0的距離為0
19         distTo[0] = 0;
20         visit(0);
21         Edge tEdge;
22         
23         while (!pq.isEmpty()) {
24             tEdge = pq.remove(pq.firstKey()); //從優先隊列中取出距離樹最短的邊
25             mst.add(tEdge); //加入樹中
26             //更新優先隊列
27             int v = tEdge.either(); //either()返回邊的任意一個點
28             if (!marked[v]) visit(v);
29             else            visit(tEdge.other(v)); //other(v)返回除v外的另一個節點
30         }
31     }
32     /*
33      * 將v的邊加入優先隊列
34      */
35     private void visit(int v) {
36         marked[v] = true;
37         for (Edge e : G.adj(v)) { //adj(v)返回該點的所有邊
38             int w = e.other(v);
39             double weight = e.weight();
40             //如果發現了使此點到樹的距離更小的通路,則更新優先隊列
41             if (weight < distTo[w]) {
42                 //如果以前已經存過這個點w到最小生成樹的邊了 現在找到了權重更小的所以把它刪除
43                 pq.remove(distTo[w]);
44                 distTo[w] = weight; //更新最小距離
45                 pq.put(weight, e); //插入優先隊列
46             }
47         }
48     }
49     
50     public Iterable<Edge> edgs() { return mst;}
51 }

將樹所有鄰近點的到樹距離最短的邊 全部加入優先隊列,從隊列中拿出最短的邊,將其加入樹中

pq始終保存着樹旁邊所有的節點到樹的最短距離

①將0加入mst,將0-7,0-2,0-4,0-6加入優先隊列,其中0-7的權重最小

②將7加入mst,將7-1,7-4(因為發現了比0-4到樹距離更小的邊所以刪了0-4,加入7-4),7-5,(7-2不加入因為原來的距離更小),其中7-1權重最小

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM