數(shù)據(jù)結(jié)構(gòu)與算法之圖(四)圖的最小生成樹(shù)

引言

現(xiàn)在假設(shè)有一個(gè)很實(shí)際的問(wèn)題:我們要在n個(gè)城市中建立一個(gè)通信網(wǎng)絡(luò),則連通這n個(gè)城市需要布置n-1一條通信線路,這個(gè)時(shí)候我們需要考慮如何在成本最低的情況下建立這個(gè)通信網(wǎng)?
于是我們就可以引入連通圖來(lái)解決我們遇到的問(wèn)題,n個(gè)城市就是圖上的n個(gè)頂點(diǎn),然后,邊表示兩個(gè)城市的通信線路,每條邊上的權(quán)重就是我們搭建這條線路所需要的成本,所以現(xiàn)在我們有n個(gè)頂點(diǎn)的連通網(wǎng)可以建立不同的生成樹(shù),每一顆生成樹(shù)都可以作為一個(gè)通信網(wǎng),當(dāng)我們構(gòu)造這個(gè)連通網(wǎng)所花的成本最小時(shí),搭建該連通網(wǎng)的生成樹(shù),就稱為最小生成樹(shù)。

最小生成樹(shù)算法思路

構(gòu)造最小生成樹(shù)有很多算法,但是他們都是利用了最小生成樹(shù)的同一種性質(zhì):MST性質(zhì):假設(shè)圖N=(V,E)是一個(gè)連通網(wǎng),U是頂點(diǎn)集V的一個(gè)非空子集,如果(u,v)是一條具有最小權(quán)值的邊,其中u屬于U,v屬于V-U,則必定存在一顆包含邊(u,v)的最小生成樹(shù),今天我們學(xué)習(xí)使用MST性質(zhì)生成最小生成樹(shù)的算法:普里姆算法。
普里姆算法的關(guān)鍵就是尋找集合U 和V-U之間的最小權(quán)邊(u,v),然后把v頂點(diǎn)加入U(xiǎn),它把頂點(diǎn)集分割成兩部分,每一次操作就從V-U尋找頂點(diǎn)v,把它放到集合U中,這樣保證生成樹(shù)沒(méi)有回環(huán),俗稱"避圈法"。實(shí)現(xiàn)流程如下:
1.原始圖:



2.假設(shè)我們從頂點(diǎn)v1開(kāi)始,所以我們可以發(fā)現(xiàn)(v1,v3)邊的權(quán)重最小,所以第一個(gè)輸出的邊就是:(v1,v3):



3.從v1和v3作為起點(diǎn)的邊中尋找權(quán)重最小的邊,發(fā)現(xiàn)(v3,v6)這條邊最小,所以輸出邊就是(v3,v6):

4.從v1、v3、v6這三個(gè)點(diǎn)相關(guān)聯(lián)的邊中尋找一條權(quán)重最小的邊,我們可以發(fā)現(xiàn)邊(v6,v4)權(quán)重最小,所以輸出邊就是(v6,v4):

5.從v1、v3、v6、v4這四個(gè)頂點(diǎn)相關(guān)聯(lián)的邊中尋找權(quán)重最小的邊,發(fā)現(xiàn)邊(v3, v2)的權(quán)重最小,所以輸出邊:(v3, v2):



6.從v1、v3、v6、v4、v2這五個(gè)頂點(diǎn)相關(guān)聯(lián)的邊中尋找權(quán)重最小的邊,發(fā)現(xiàn)邊(v2,v5)的權(quán)重最小,所以輸出邊(v2,v5):

7.六個(gè)頂點(diǎn)全部連接,最小生成樹(shù)構(gòu)建完成.
算法流程:
1>設(shè)u為起點(diǎn),無(wú)向圖的鄰接矩陣C[N][N],U為已經(jīng)加入生成樹(shù)的頂點(diǎn)集合,V-U為未加入生成樹(shù)的頂點(diǎn)集合,s[]數(shù)組做為頂點(diǎn)所屬集合的標(biāo)記。closest[]數(shù)組存放V-U中頂點(diǎn)j到集合U中距離最近的頂點(diǎn)索引,如上面的步驟2中,closest[3]=1,表示頂點(diǎn)V3的最近頂點(diǎn)為V1.lowcost[]數(shù)組存放V-U集合中到U最近頂點(diǎn)的邊權(quán)值,如步驟2中,lowcost[3]=1,表示V3到集合{V1}的最小權(quán)重為1.
2>.初始化U={u},closest[]、lowcost[]和s[].
3>.在V-U中尋找lowcost[]最小的頂點(diǎn)t,加入集合U.
4>.更新lowcost和closest,更新公式:如果C[t][j]<lowcost[j],則更新lowcost[j]=C[t][j], closest[j]=t.
5>步驟2、3、4循環(huán)執(zhí)行N次。

代碼實(shí)現(xiàn)

package graphic;

/**
 * Created by chenming on 2018/6/18
 * 最小生成樹(shù)算法-普利姆算法
 */
public class Prim {
    private int[][] map;
    //V-U集合中距離U集合中頂點(diǎn)最近的點(diǎn),如closest[j] = i,
    // 表示j距離U集合最近的頂點(diǎn)為i,在最小樹(shù)中,i為j的前驅(qū)
    private int[] closest;
    private int[] lowcost;//V-U集合中距離U最近頂點(diǎn)的邊長(zhǎng)(j, closest[j])
    private boolean[] s;//標(biāo)記是否添加到集合U

    public Prim(int[][] map) {
        this.map = map;
        int size = map.length;
        closest = new int[size];
        lowcost = new int[size];
        s = new boolean[size];
    }


    /**
     * 構(gòu)造最小生成樹(shù)
     *
     * @param u0 起點(diǎn)頂點(diǎn)
     */
    public void prim(int u0) {
        int n = map.length;
        //Step1初始化
        s[u0] = true;//u0加入集合
        for (int i = 0; i < n; i++) {
            if (i != u0) {
                lowcost[i] = map[u0][i];
                closest[i] = u0;
            } else {
                lowcost[i] = 0;
                closest[i] = -1;//-1表示沒(méi)有前驅(qū)
            }
        }

        //Step2 S-U中尋找距離U最小的頂點(diǎn)t,加入集合,更新lowcost和closest
        for (int i = 0; i < n; i++) {
            //尋找
            int min = Integer.MAX_VALUE;
            //找最小權(quán)邊頂點(diǎn)t
            int t = u0;
            for (int j = 0; j < n; j++) {
                if (!s[j] && lowcost[j] < min) {
                    t = j;
                    min = lowcost[j];
                }
            }

            //加入集合
            if (t == u0) {//沒(méi)找到最小值,跳出循環(huán)
                break;
            }
            s[t] = true;
            //更新lowcost和closest,從最小頂點(diǎn)t出發(fā),如果它的鄰接頂點(diǎn)j的邊權(quán)小于lowcost[j],則更新lowcost和closest
            for (int j = 0; j < n; j++) {
                if (!s[j] && map[t][j] < lowcost[j]) {
                    lowcost[j] = map[t][j];
                    closest[j] = t;
                }
            }

        }

        //輸出結(jié)果
        dumpResult();
    }

    /**
     * 輸出邊和頂點(diǎn)即可
     */
    private void dumpResult() {
        System.out.println("======最小樹(shù)結(jié)構(gòu)======");
        for (int i = 0; i < lowcost.length; i++) {
            System.out.println("頂點(diǎn)" + i + "的前驅(qū):" + closest[i]);
        }
        System.out.println("======最小樹(shù)權(quán)值======");
        for (int i = 0; i < lowcost.length; i++) {
            System.out.println("權(quán)值:" + lowcost[i]);
        }
    }
}

測(cè)試代碼:

 @Test
    public void testPrim() {
        int INF = Integer.MAX_VALUE;
        int[][] map = {
                {INF, 23, INF, INF, INF, 28, 36},
                {23, INF, 20, INF, INF, INF, 1},
                {INF, 20, INF, 15, INF, INF, 4},
                {INF, INF, 15, INF, 3, INF, 9},
                {INF, INF, INF, 3, INF, 17, 16},
                {28, INF, INF, INF, 17, INF, 25},
                {36, 1, 4, 9, 16, 25, INF}
        };

        Prim prim = new Prim(map);
        prim.prim(0);
    }

測(cè)試結(jié)果:

======最小樹(shù)結(jié)構(gòu)======
頂點(diǎn)0的前驅(qū):-1
頂點(diǎn)1的前驅(qū):0
頂點(diǎn)2的前驅(qū):6
頂點(diǎn)3的前驅(qū):6
頂點(diǎn)4的前驅(qū):3
頂點(diǎn)5的前驅(qū):4
頂點(diǎn)6的前驅(qū):1
======最小樹(shù)權(quán)值======
權(quán)值:0
權(quán)值:23
權(quán)值:4
權(quán)值:9
權(quán)值:3
權(quán)值:17
權(quán)值:1

完整代碼地址:數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)JAVA描述GayHub地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 弗洛伊德算法適用于為圖中每一個(gè)頂點(diǎn)求最短路徑,思路如下 檢查圖中任何一個(gè) 到 任何另一個(gè)點(diǎn)能否通過(guò)第一個(gè)點(diǎn)降低最短...
    RichardW閱讀 1,007評(píng)論 0 1
  • 定義 關(guān)于最小生成樹(shù)的定義,需要先了解如下這幾個(gè)相關(guān)概念: 連通圖:在無(wú)向圖中,若任意兩個(gè)頂點(diǎn)vi與vj都有路徑相...
    JarryWell閱讀 4,183評(píng)論 0 4
  • 第一章 緒論 什么是數(shù)據(jù)結(jié)構(gòu)? 數(shù)據(jù)結(jié)構(gòu)的定義:數(shù)據(jù)結(jié)構(gòu)是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。 第二章...
    SeanCheney閱讀 5,986評(píng)論 0 19
  • 我們都不可避免的成長(zhǎng),會(huì)有無(wú)數(shù)杯從頭頭淋下的冷水,會(huì)有無(wú)數(shù)瞬間心如死灰,會(huì)有無(wú)數(shù)人把你的絕望當(dāng)作笑點(diǎn),會(huì)有無(wú)數(shù)人來(lái)...
    DrJoseph閱讀 231評(píng)論 0 0
  • 一位大師帶著兩個(gè)小和尚下山化緣,他們走進(jìn)一個(gè)村子,村子里的人看上去都很聰明,也都很忙碌,都在各自做著自己的事情,沒(méi)...
    不帥任你踹閱讀 413評(píng)論 2 2

友情鏈接更多精彩內(nèi)容