这是图算法的第四篇文章 图解:如何实现最小生成树算法
文章目录:数组
今天咱们考虑的模型是加权无向图
,问题是如何获取它的一幅最小生成树!首先,咱们给出最小生成树的定义:微信
图的生成树是它的一棵含有其全部顶点的无环连通子图。一幅加权图的最小生成树(MST)是它的一棵权值(树中全部边的权值之和)最小的生成树。数据结构
如图所示:code
首先,咱们给出一些约定来简化问题(这并不会影响咱们理解问题)对象
简而言之,咱们的讨论对象是一幅权重各不相同的加权无向图,任务是求最小生成树的每条边。接下来,咱们一块儿思考如何实现这个算法!blog
1)咱们的任务是求得最小生成树的每条边,也就是我只要肯定了这些边,天然而然也就惟一肯定了最小生成树;那么,一棵最小生成树有多少条边呢?咱们先来回顾一下树
的两个性质:排序
由于一共有V
个顶点,生成树的边刚好链接全部顶点(很少很多),因此生成树一定有V-1
条边。好了,恭喜你!🙃到这里咱们已经前进了一小步!索引
2)接下来,我说一句话你看是否是对的:队列
只要找到属于最小生成树的
V-1
条边(不管什么手段),也就解决了这个问题
你确定会说,这不是显然的吗?对!但这个是咱们向前走的基本思想。记牢了🤓
3)接下来,咱们就要寻找一种条件,只要一条边知足这个条件,那么咱们就可以断言这条边确定在最小生成树中。一旦存在,咱们就能够经过创造这种条件找到属于最小生成树的边,将它标记;反复创造上述条件,就能够反复地标记边;直到咱们标记了V-1
条边! 你是否是惊奇地发现:咱们已经成功地解决了这个问题!
4)咱们的任务变成了如何寻找与制造这种条件。站在巨人的肩膀上,咱们只须要理解就好了😂。这个条件,咱们称之为切分定理。
6)咱们随意将一幅加权图分为两个非空的集合,横跨两个集合的一条边被称为横切边。而横切边中最短的那个一定属于最小生成树! 如图所示:
全部的灰色顶点是一个集合,全部的白色顶点是另一个集合,横跨两个集合的全部的边称为横切边(用红色标出);其中权重最小的横切边一定属于最小生成树!
这个定理其实很容易想明白,由于这两个集合之间必需要存在且只能存在一条边;若是存在的不是这条最短横切边,那它就不是最小生成树了!请注意一条很重要的性质:这种划分是任意的!
——————咱们随便怎么划分都无所谓!这就为处理问题带来了很强的灵活性!
7)咱们随后介绍一种通用的算法思想:贪心算法(其实咱们在前文已经接触过)。
使用切分定理找到最小生成树的一条边,不断重复直到找到最小生成树的全部边(
V-1
条便可)
这是一幅贪心算法的执行过程,每次都是将全部顶点分红两个集合(注意:这是任意的!!),而后取最小的横切边加入最小生成树。如此反复,最终就达到了咱们的目的!
8)接下来再日后,咱们将真正地实现这种算法,而不是只停留在思想上(talk is cheap,show me the code!😍)
1)咱们接着刚才的思路继续,咱们面临着两个问题:切分
与找到最小横切边
;对于切分,因为是随意的,因此仍是很容易实现的;另外一个问题:怎样很天然地找到最小的横切边呢?
2)一个比较容易想到的解决方案是:
按照边的权重顺序(从小到大)处理他们;
首先,将最小的边加入最小生成树,而后从小到大依次加入边,(注意:待加入的边不能和已经加入的边构成环);一直重复上述过程直到树中含有V-1
条边为止
3)如今咱们仔细思考一下这个方法。只要待加入的边和已经加入的边没有构成环,就说明这条边是一条横切边
,同时,得益于咱们加入的顺序(从小到大),咱们能够肯定这条待加入的边是最小横切边,那么它必定属于最小生成树,将它加入也就没有什么毛病了。来看一下下面的过程:
咱们在实现的时候使用了一条优先队列
来将边按照权重排序;用前几篇文章中实现的判断无向图连通性的类判断是否连通;用一条队列来保存最小生成树的全部边;就能够很容易实现Kruskal算法
。
Prim算法
的思想与Kruskal算法
乍一看有所不一样,可是最终你会发现,只是在寻找最小权重的横切边这里使用了不一样的 策略罢了。
1)咱们考虑这样一种方案:维护一棵生长中的树
A
)添加到最小生成树中2)这个过程比Kruskal
更加简明——————与最小生成树相连的权重最小的一条边;咱们把已经在树中的点记为集合A,全部没有在树中的顶点记为集合B,显然咱们选择的那条边就是最小横切边!
3)虽然过程比较简明,可是实现的代码却不简单,咱们须要:
marked[]
,若是顶点 v
在树中,那么 marked[v]
的值为true
mst
来保存最小生成树中的边MinPQ<Edge>
来根据权重比较全部边具体的操做过程以下:
4)到这儿,咱们已经实现了Prim算法
,它被称为 Prim算法的延时实现
;可是,还有能够改进的地方,咱们能够经过一些改进————删除一些冗余的信息,从而获得Prim算法的即时实现
。
5)可是,在这篇文章中,咱们就不加以介绍了;它的思想和延时实现一致,目标一样是找到与最小生成树相连的权重最小的一条边,只不过实现方法更加灵活罢了!
此次和往常不一样,我并无在文章中间掺杂算法的具体实现,个人想法是把它真正的思路讲明白(但愿我讲的没有让你失望🤔);可是,代码仍是要有的,我将它们放在了这里,具体来讲书籍算法4上面都有!!
Kruskal算法
的实现Prim
算法的实现如何实现一个加权边
如何实现加权无向图
Kruskal算法
的实现
Prim
算法的实现(两张图片)
码字绘图不易,若是以为本文对你有帮助,还请不要白嫖,关注、点赞、在看都是对小超创做的一种承认!
欢迎你们关注个人公众号:小超说 ,以后我会继续创做算法与数据结构以及计算机基础知识的文章。也能够加我微信chao_hey(备注:职业-城市) ,咱们一块儿交流,一块儿进步!
本文参考:《算法》(第四版),图片来源于此