
在学习连通图的基础上,本节学习什么是生成树,以及什么是生成森林。对连通图进行遍历,过程中所经过的边和顶点的组合可看做是一棵普通树,通常称为生成树。

如图 1 所示,图 1a) 是一张连通图,图 1b) 是其对应的 2 种生成树。
连通图中,由于任意两顶点之间可能含有多条通路,遍历连通图的方式有多种,往往一张连通图可能有多种不同的生成树与之对应。
连通图中的生成树必须满足以下 2 个条件:
- 包含连通图中所有的顶点;
- 任意两顶点之间有且仅有一条通路;
因此,连通图的生成树具有这样的特征,即生成树中边的数量 = 顶点数 - 1
。
生成森林
生成树是对应连通图来说,而生成森林是对应非连通图来说的。
我们知道,非连通图可分解为多个连通分量,而每个连通分量又各自对应多个生成树(至少是 1 棵),因此与整个非连通图相对应的,是由多棵生成树组成的生成森林。

如图 2 所示,这是一张非连通图,可分解为 3 个连通分量,其中各个连通分量对应的生成树如图 3 所示:

注意,图 3 中列出的仅是各个连通分量的其中一种生成树。
因此,多个连通分量对应的多棵生成树就构成了整个非连通图的生成森林。
图的最小生成树
一个有 n 个顶点的连通图法生成树是原图的极小连通子图,它包含原图中所有的 n 个顶点,并且具有保持图连通的最小的边。
根据生成树的定义,具有 n 个顶点的无向连通图不管它的生成树是怎么样的,它有且仅有 n-1 条边。
如果一个无向连通图是一个带权图,那么在它所有的生成树中必定有一棵树的边的权值最小,这样的树我们成为最小代价生成树,简称为最小生成树。
生活中很多求最小生成树的问题,比如在多个城市之间铺设光缆如何使得费用最小的问题。
由上面的定义我们知道最小生成树必须满足以下几个条件
1、n 个顶点
2、n-1 条边
3、不存在回路
4、权值之和最小
构造最小生成树的方法很多,最经典的构造算法是Prim算法和Kruskal算法。1、Prim算法
设G=(V,E) 为一个带权图,设置两个新的集合 U 和 T 。
其中 U 用于存放带权图G的最小生成树的顶点集合,T 用于存放带权图G的最小生成树的权值的集合。
Prim算法的思想为: 首先令集合U 的初值为 U = {u0},即初始顶点为 u0 。集合 T = {} 。
从集合 U 中包含的顶点中选取 权值最小 并且 顶点不在 U 中 的邻接顶点,将它加入U中,对应的边加入T 中。
一直重复上述操作,直到 U 集合中包含所有的顶点,此时 U 中存放的就是最小生成树的顶点的集合,T中存放的就是最小生成树的边的集合。

具体代码请查看github2、Kruskal算法
Kruskal算法是一种按照带权图中边的权值的递增顺序构造最小生成树的方法。
它 的思想是,假设带权图G的最小生成树 T={V,{}},即初始状态T包含所有的顶点,但不包含任何一条边,
然后按照权值的递增顺序考察边,如果边的两个顶点属于T的两个不同的连通分量,则将边加入T,如果属于同一连通分量则舍去该边。
当T中的连通分量个数为1时,此时T就表示最小生成树。
