数据结构与算法之图(四)图的最小生成树

引言

现在假设有一个很实际的问题:我们要在n个城市中建立一个通信网络,则连通这n个城市需要布置n-1一条通信线路,这个时候我们需要考虑如何在成本最低的情况下建立这个通信网?
于是我们就可以引入连通图来解决我们遇到的问题,n个城市就是图上的n个顶点,然后,边表示两个城市的通信线路,每条边上的权重就是我们搭建这条线路所需要的成本,所以现在我们有n个顶点的连通网可以建立不同的生成树,每一颗生成树都可以作为一个通信网,当我们构造这个连通网所花的成本最小时,搭建该连通网的生成树,就称为最小生成树。

最小生成树算法思路

构造最小生成树有很多算法,但是他们都是利用了最小生成树的同一种性质:MST性质:假设图N=(V,E)是一个连通网,U是顶点集V的一个非空子集,如果(u,v)是一条具有最小权值的边,其中u属于U,v属于V-U,则必定存在一颗包含边(u,v)的最小生成树,今天我们学习使用MST性质生成最小生成树的算法:普里姆算法。
普里姆算法的关键就是寻找集合U 和V-U之间的最小权边(u,v),然后把v顶点加入U,它把顶点集分割成两部分,每一次操作就从V-U寻找顶点v,把它放到集合U中,这样保证生成树没有回环,俗称"避圈法"。实现流程如下:
1.原始图:



2.假设我们从顶点v1开始,所以我们可以发现(v1,v3)边的权重最小,所以第一个输出的边就是:(v1,v3):



3.从v1和v3作为起点的边中寻找权重最小的边,发现(v3,v6)这条边最小,所以输出边就是(v3,v6):

4.从v1、v3、v6这三个点相关联的边中寻找一条权重最小的边,我们可以发现边(v6,v4)权重最小,所以输出边就是(v6,v4):

5.从v1、v3、v6、v4这四个顶点相关联的边中寻找权重最小的边,发现边(v3, v2)的权重最小,所以输出边:(v3, v2):



6.从v1、v3、v6、v4、v2这五个顶点相关联的边中寻找权重最小的边,发现边(v2,v5)的权重最小,所以输出边(v2,v5):

7.六个顶点全部连接,最小生成树构建完成.
算法流程:
1>设u为起点,无向图的邻接矩阵C[N][N],U为已经加入生成树的顶点集合,V-U为未加入生成树的顶点集合,s[]数组做为顶点所属集合的标记。closest[]数组存放V-U中顶点j到集合U中距离最近的顶点索引,如上面的步骤2中,closest[3]=1,表示顶点V3的最近顶点为V1.lowcost[]数组存放V-U集合中到U最近顶点的边权值,如步骤2中,lowcost[3]=1,表示V3到集合{V1}的最小权重为1.
2>.初始化U={u},closest[]、lowcost[]和s[].
3>.在V-U中寻找lowcost[]最小的顶点t,加入集合U.
4>.更新lowcost和closest,更新公式:如果C[t][j]<lowcost[j],则更新lowcost[j]=C[t][j], closest[j]=t.
5>步骤2、3、4循环执行N次。

代码实现

package graphic;

/**
 * Created by chenming on 2018/6/18
 * 最小生成树算法-普利姆算法
 */
public class Prim {
    private int[][] map;
    //V-U集合中距离U集合中顶点最近的点,如closest[j] = i,
    // 表示j距离U集合最近的顶点为i,在最小树中,i为j的前驱
    private int[] closest;
    private int[] lowcost;//V-U集合中距离U最近顶点的边长(j, closest[j])
    private boolean[] s;//标记是否添加到集合U

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


    /**
     * 构造最小生成树
     *
     * @param u0 起点顶点
     */
    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表示没有前驱
            }
        }

        //Step2 S-U中寻找距离U最小的顶点t,加入集合,更新lowcost和closest
        for (int i = 0; i < n; i++) {
            //寻找
            int min = Integer.MAX_VALUE;
            //找最小权边顶点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) {//没找到最小值,跳出循环
                break;
            }
            s[t] = true;
            //更新lowcost和closest,从最小顶点t出发,如果它的邻接顶点j的边权小于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;
                }
            }

        }

        //输出结果
        dumpResult();
    }

    /**
     * 输出边和顶点即可
     */
    private void dumpResult() {
        System.out.println("======最小树结构======");
        for (int i = 0; i < lowcost.length; i++) {
            System.out.println("顶点" + i + "的前驱:" + closest[i]);
        }
        System.out.println("======最小树权值======");
        for (int i = 0; i < lowcost.length; i++) {
            System.out.println("权值:" + lowcost[i]);
        }
    }
}

测试代码:

 @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);
    }

测试结果:

======最小树结构======
顶点0的前驱:-1
顶点1的前驱:0
顶点2的前驱:6
顶点3的前驱:6
顶点4的前驱:3
顶点5的前驱:4
顶点6的前驱:1
======最小树权值======
权值:0
权值:23
权值:4
权值:9
权值:3
权值:17
权值:1

完整代码地址:数据结构与算法学习JAVA描述GayHub地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容

  • 弗洛伊德算法适用于为图中每一个顶点求最短路径,思路如下 检查图中任何一个 到 任何另一个点能否通过第一个点降低最短...
    RichardW阅读 956评论 0 1
  • 定义 关于最小生成树的定义,需要先了解如下这几个相关概念: 连通图:在无向图中,若任意两个顶点vi与vj都有路径相...
    JarryWell阅读 3,885评论 0 4
  • 第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章...
    SeanCheney阅读 5,771评论 0 19
  • 我们都不可避免的成长,会有无数杯从头头淋下的冷水,会有无数瞬间心如死灰,会有无数人把你的绝望当作笑点,会有无数人来...
    DrJoseph阅读 212评论 0 0
  • 一位大师带着两个小和尚下山化缘,他们走进一个村子,村子里的人看上去都很聪明,也都很忙碌,都在各自做着自己的事情,没...
    不帅任你踹阅读 343评论 2 2