普裡姆Prim演算法 - 圖解最小產生樹

來源:互聯網
上載者:User

標籤:針對   儲存   ora   [1]   尋找   cal   tab   儲存結構   並且   

我們在圖的定義中說過,帶有權值的圖就是網結構。一個連通圖的產生樹是一個極小的連通子圖,它含有圖中全部的頂點,但只有足以構成一棵樹的n-1條邊。所謂的最小成本,就是n個頂點,用n-1條邊把一個連通圖串連起來,並且使得權值的和最小。綜合以上兩個概念,我們可以得出:構造連通網的最小代價產生樹,即最小產生樹(Minimum Cost Spanning Tree)。

找連通圖的最小產生樹,經典的有兩種演算法,普裡姆演算法和克魯斯卡爾演算法,這裡介紹普裡姆演算法。

為了能夠講明白這個演算法,我們先構造網圖的鄰接矩陣,7-6-3的右圖所示。



也就是說,現在我們已經有了一個儲存結構為MGraph的MG(見《鄰接矩陣建立圖》)。MG有9個頂點,它的二維數組如右圖所示,數組中我們使用65535代表無窮。

下面我們對著程式和每一步迴圈的圖示來看:

演算法代碼:(改編自《大話資料結構》)

 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  /* Prim演算法產生最小產生樹  */
void MiniSpanTree_Prim(MGraph MG)
{
    int min, i, j, k;
    int adjvex[MAXVEX];/* 儲存相關頂點下標 */
    int lowcost[MAXVEX];/* 儲存相關頂點間邊的權值 */
    lowcost[0] = 0;/* 初始化第一個權值為0,即v0加入產生樹 */
    /* lowcost的值為0,在這裡就是此下標的頂點已經加入產生樹 */
    adjvex[0] = 0;/* 初始化第一個頂點下標為0 */
    cout << "最小產生樹的邊為:" << endl;
    for (i = 1; i < MG.numVertexes; i++)
    {
        lowcost[i] = MG.arc[0][i];/* 將v0頂點與之有邊的權值存入數組 */
        adjvex[i] = 0;/* 初始化都為v0的下標 */
    }

    for (i = 1; i < MG.numVertexes; i++)
    {
        min = INFINITY; /* 初始化最小權值為∞, */

        j = 1;
        k = 0;

        while (j < MG.numVertexes)/* 迴圈全部頂點 */
        {
            if (lowcost[j] != 0 && lowcost[j] < min)/* 如果權值不為0且權值小於min */
            {
                min = lowcost[j];/* 則讓當前權值成為最小值 */
                k = j;/* 將當前最小值的下標存入k */
            }

            j++;
        }

        cout << "(" << adjvex[k] << ", " << k << ")" << "  "; /* 列印當前頂點邊中權值最小的邊 */
        lowcost[k] = 0;/* 將當前頂點的權值設定為0,表示此頂點已經完成任務 */

        for (j = 1; j < MG.numVertexes; j++)/* 迴圈所有頂點 */
        {
            /* 如果下標為k頂點各邊權值小於此前這些頂點未被加入產生樹權值 */
            if (lowcost[j] != 0 && MG.arc[k][j] < lowcost[j])
            {
                lowcost[j] = MG.arc[k][j];/* 將較小的權值存入lowcost相應位置 */
                adjvex[j] = k;/* 將下標為k的頂點存入adjvex */
            }
        }
    }
    cout << endl;
}


1、程式中1~16行是初始化操作,其中第7~8行 adjvex[0] = 0 意思是現在從頂點v0開始(事實上從那一點開始都無所謂,假定從v0開始),lowcost[0]= 0 表示v0已經被納入到最小產生樹中,之後凡是lowcost數組中的值被設為0就表示此下標的頂點被納入最小產生樹。

2、第11~15行表示讀取鄰接矩陣的第一行資料,所以 lowcost數組為{ 0 ,10, 65535, 65535, 65535, 11, 65535, 65535, 65535 },而adjvex數組為全0。至此初始化完畢。

3、第17~49行共迴圈了8次,i從1一直累加到8,整個迴圈過程就是構造最小產生樹的過程。

4、第24~33行,經過迴圈後min = 10, k = 1。注意26行的if 判斷lowcost[j] != 0 表示已經是產生樹的頂點則不參加最小權值的尋找。

5、第35行,因k = 1, adjvex[1] = 0, 所以列印結果為(0, 1),表示v0 至 v1邊為最小產生樹的第一條邊,如的第一個小圖。

6、第36行,因k = 1 將lowcost[k] = 0 就是說頂點v1納入到最小產生樹中,此時lowcost數組為{ 0,0, 65535, 65535, 65535, 11, 65535, 65535, 65535 }

7、第38~47行,j 迴圈從1 到8, 因k = 1,尋找鄰接矩陣的第v1行的各個權值,與lowcost數組對應值比較,若更小則修改lowcost值,並將k值存入adjvex數組中。所以最終lowcost = { 0,0, 18, 65535, 65535, 11, 16, 65535, 12 }。 adjvex數組的值為 {0, 0, 1, 0, 0, 0, 1, 0, 1 }。這裡的if判斷也表示v0和v1已經是產生樹的頂點不參與最小權值的比對了。


上面所述為第一次迴圈,對應i = 1的第一個小圖,由於要用文字描述清楚整個流程比較繁瑣,下面給出i為不同值一次迴圈下來後的產生樹圖示,所謂一圖值千言,大家對著圖示自己類比地迴圈8次就能理解普裡姆演算法的思想了。


即最小產生樹的邊為:(0, 1), (0, 5), (1, 8), (8, 2), (1, 6), (6, 7), (7, 4), (7, 3)

最後再來總結一下普裡姆演算法的定義:

假設N = (V{E} )是連通網,TE是N上最小產生樹的集合。演算法從U = { u0} ( uo V),TE = { } 開始。重複執行下述操作:在所有

uU,v V - U 的邊(u, v) E 中找一條代價最小的邊(u0 , v0) 併入集合TE, 同時v0 併入U, 直至 U = V 為止。此時TE 中必有n-1 條邊, 則 T = (V,{TE} ) 為N的最小產生樹。


由演算法代碼中的迴圈嵌套可得知此演算法的時間複雜度為O(n^2)。

對比普裡姆和克魯斯卡爾演算法,克魯斯卡爾演算法主要針對邊來展開,邊數少時效率比較高,所以對於稀疏圖有較大的優勢;而普裡姆演算法對於稠密圖,即邊數非常多的情況下更好一些。

普裡姆Prim演算法 - 圖解最小產生樹

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.