目录
1.认识最小生成树
在无向图当中,如果我们从任意一个顶点出发能到达图中的其他所有顶点,这样的图我们叫做连通图;连通图中的所有极大无环子图都是原图的一棵生成树。
极大无环子图中的无环和子图好理解,如何理解这里的极大两个字呢?极大指的是在满足某种特性的前提下(连通性),尽可能多的包含原图的顶点和边。假设原连通图有n个顶点,而极大无环子图要保证连通性,肯定要包含n个顶点,又要保证无环,最多只能包含n-1条边。所以,一个连通图的包含n个顶点,n-1条边的连通子图就是生成树。
如下所示:

可见,连通图的生成树不止一棵,那么什么是最小生成树呢?我们试着给连通图中的每条边带上权值,权值之和最小的生成树就是该连通图的最小生成树(其意义就是用最小的成本让着n个点连通)。
如下所示:

由此可见,该连通图的最小生成树为生成树C。
2.最小生成树构建算法
我们已经知道了什么是最小生成树,那如何构建一棵图的最小生成树呢?连通图的生成树必须包含n个顶点和n-1条边(n是原图的顶点个数),因此构建最小生成树的准则有以下三条:
- 只能使用无向图中的顶点和边来构造最小生成树
- 只能使用恰好n-1条边来连接图中的n个顶点
- 选用的n-1条边不能构成回路
构建最小生成树的经典算法有Kruskal算法(克鲁斯卡尔算法)和Prim算法(普里姆算法),这两个算法都采用了逐步求解的贪心策略。
3.Kruskal算法
Kruskal算法的大致思想:先记录连通图的所有顶点(n个顶点)和所有边,然后每次都从边集中选取权值最小的边以及这条边对应的两个顶点用于组建最小生成树,并且每次添加这条边的时候判断是否会构成环,如果会构成环就舍弃这条边,否则就添加这条边,直到n个顶点都添加进来之后,如果边的条数等于n-1,则构建出来的就是最小生成树。
Kruskal算法流程图:此图源自于《算法导论》

最后的最小生成树如下:权值之和为37。

Kruskal算法流程:任给一个有n个顶点的连通图G{V, E},其中V是点集,E是边集。
- 首先构造出有n个顶点,不含任何边的图minTree_G{V, NULL},其中,我们可以把每个顶点单独看成一个集合。
- 然后不断从边集E中取出权值最小的边,如果该边的两个顶点来自不同的集合,则将该边加入到图minTree_G中;如果该边的两个顶点来自同一个集合,在图minTree_G中添加该边就会构成环,需要舍弃。
- 重复第二点,直到所有的点都在同一个集合中。如果此时的添加的边的条数为n-1条,那么构成的图minTree_G就是图G的最小生成树。
Kruskal算法代码示例:示例代码设置为类的成员函数,由于篇幅原因并没有在此给出图这个类的全部代码,文末附完整源代码。
- 需要注意的是:
- 我们每添加一条边的时候,都是选取权值最小的边添加,因此我们可以用一个小根堆存储边的信息。
- 而且,我们添加边的时候,都需要判断是否会构成环,也就是判断这条边的两个顶点是否在同一集合中,因此,我们可以使用并查集这种数据结构来判断是否构成环。不了解并查集这种数据结构的朋友可以看一下这篇文章
- 并查集的原理及实现
https://blog.csdn.net/D5486789_/article/details/144227145 (本文末附并查集源码)
/*
* V: 顶点的类型
* W: 权值的类型
* MAX_VAL: 权值的最大值,表示两个顶点之间没有关系,默认是int的最大值
* Direction: 表示该图为有向图还是无向图,默认是无向图
*/
template<class V, class W, W MAX_VAL = INT_MAX, bool Direction = false>
class Graph
{
using Self = Graph<V, W, MAX_VAL, Direction>;
public:
/*定义边这种数据结构,用于表示边*/
struct Edge
{
// 成员变量
size_t _srci;
size_t _dsti;
W _w;
//构造函数
Edge(size_t srci, size_t dsti, const W&am

、Prim算法(普里姆算法)&spm=1001.2101.3001.5002&articleId=144293337&d=1&t=3&u=7e3bde1b6beb47d89d3a60aa65dd96dd)
9440

被折叠的 条评论
为什么被折叠?



