#重要#图之最小生成树

最小生成树

一个图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边。通俗一点讲,就是使用n-1条线把n个点连接起来,那么这些线和点构成的图形就叫生成树。在网图中,每条边有自己的权重,最小生成树就是指所有边的权重加起来最小的一种生成树。
最小生成树的典型应用如:要在一些村庄之间铺设电线,使所有的村庄都能通上电且成本最低(电线总长度最小),解决这个问题的过程就是求最小生成树。

克鲁斯卡尔(Kruskal)算法

1.1 算法原理
克鲁斯卡尔算法比较好理解,既然要保证总权重最小,就先把所有边按权重从小到大排列起来,然后依次取一条边回填至图中。因为要保证是生成树,所以不能有环路,如果回填某条边使得形成环路,则舍弃该边,继续选择下一条边回填,直到连接所有顶点。此时的生成树就是最小生成树。
可见,既然关注的是边的权重,采用边集数组的存储方式最方便。

边集数组

1.2 视频
视频描述的很形象,一看就懂。
视频:最小生成树(Kruskal(克鲁斯卡尔)和Prim(普里姆))算法动画演示

1.3 代码关键点
所以编程的关键是,如何判断是否形成环路?定义数组parent[]来判断边与边是否形成环路。

我们先看如何使用parent数组判断是否形成环路,再去讨论怎么生成更新这一数组。
在上图中,执行到i =6时,parent数组为

下标 0 1 2 3 4 5 6 7 8
parent数组 1 5 8 7 7 8 0 0 6

其中,下标代表一条边所依附的一个顶点,对应parent元素代表改变所依附的另一个顶点,也就是说每列就是一条边。
由0→1→5→8→6和2→8说明v0v1v2v5v6v8这六个点被连在了一起;由3→7和4→7说明v3v4v7在另一个集合里被连到了一起。

当新边edges[7]-5-6尝试回填时,其实就是判断v5v6是否已经在一个集合里。
通过分析可知,当两个点在同一集合中时,将返回相同的数。

int Find(int *parent, int f)
{
    while (parent[f] > 0)
        f = parent[f];
    return f;
}

如输入f = 0, 1, 5, 6, 8都将返回6,输入f = 3, 4, 7都将返回7。因此(5, 6)不能回填,继续尝试下一条边。

初始状态下,parent数组的值都为零,依次选择一条边回填时,判断是否形成环路,如果形成环路则舍弃改变继续尝试下一条边,如果不形成环路,则确认回填,并将改边写入parent数组。

这个思想还是比较有趣的,实际上parent数组通过<下标,元素>对应<起点,终点>,将相关联的点的集合串成了一串,通过Find函数,只要输入的点在这个集合中,最后总指向值为0的那个下标。

这个方法的巧妙之处在于将已加入生成树的顶点分成了两个集合,只有新加入的边的两个顶点在同一集合内才是形成了环路。只用一个selected数组是无法实现的。

1.4 代码
Graph/Kruskal_MiniSpanTree.c


普里姆(Prim)算法

2.1 基本原理
kruskal算法从边出发,采用依次尝试回填的方法找出最小生成树。而Prim算法则是从顶点出发,同样基于贪心算法的思想,依次找出局部最优,从而生成的最优方案也就是全局最优方案。

如下图所示,将已经归入最小生成树的顶点集合为左侧集合A,未归入的为右侧集合B。现在想继续寻找最小生成树的下一个顶点,就是在集合A、B分别找一个顶点,两顶点之间距离最小,将该B中的顶点归入最小生成树。这样不断寻找A集合与B集合之间的权值最小的边,直到所有顶点遍历完成。
具体过程同样参考前面的视频。

Prim算法示意图

2.2 关键代码
在编程中,是通过三个数组实现这一搜索过程的,分别是selectedminDistparent
selected数组初始化为0,表明还没有顶点加入生成树;
parent数组初始化为-1,用于标识每次新加入的边,同时方便打印结果。
选定一个初始顶点,这里选择V0,取出邻接矩阵的第0行对minDist数组进行更新,在这里更新后就是{0, 4, INF, INF, INF, INF, INF, 8, INF},同时在parent数组对应的位置(下标分别是1和7的位置)写入父亲顶点(因为本次是扫描V0相连的顶点,所以写入0),在下一步就是找出权重最小的一条路径,将其加入最小生成树。在这里就是V1
V1加入后,同样根据邻接矩阵,对minDist进行更新,现在可以看出minDist就是集合A与外围区域所有可能路径的权重,整个循环过程就是:
Update:更新minDist→Search:找出最小权重→Add:加入最小生成树
这样不断找出当前集合与外围集合之间权重最小的一条边加入生成树,最终将所有顶点遍历完毕后,得到的生成树就是最小生成树。

如果不使用selected数组也可以,这样需要将已完成顶点的信息保存在minDist数组中。
增加三个处理:

  1. 生成树每增加一个顶点,将对应下标的minDist值置为0(或者其他的一个特定值)标识该顶点已进入生成树。
    选择0号顶点作为起点,也就是0进入生成树,那么此时minDist就是{0, INF, INF, INF, INF, INF, INF, INF, INF}
  2. 使用G更新minDist时,不更新minDist[i] == 0的顶点。因为如果为0,说明该顶点已经进入生成树。
  3. 扫描minDist得到最小权重时,排除0元素。

不过这样使代码逻辑不太清晰,还是增加一个selected[]数组好一点。

2.3 代码
Graph/Prim_MiniSpanTree.c

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

推荐阅读更多精彩内容

  • 图的定义与术语 1、图按照有无方向分为无向图和有向图。无向图由顶点和边构成,有向图由顶点和弧构成。弧有弧尾和弧头之...
    unravelW阅读 408评论 0 0
  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,830评论 0 13
  • 图是由顶点的有穷非空集合和顶点之间的边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图中的顶点的集...
    keeeeeenon阅读 551评论 0 2
  • 1. 图的定义和基本术语 线性结构中,元素仅有线性关系,每个元素只有一个直接前驱和直接后继;树形结构中,数据元素(...
    yinxmm阅读 5,457评论 0 3
  • 一觉醒来,我望着天花板,想起昨晚和哥哥的通话“去做你想做的事情,不要给自己留下遗憾”。 23岁,应届毕业生,就业恐...
    蛋蛋oY阅读 767评论 5 1