1. 问题
给定一个无向有权图G,分别使用PRIM算法和Kruakal算法来生成T的最小生成树
2. 解析
最小生成树是指顶点集与图相同,但是所有的边权值和最小的树。设G的顶点集为V,边集为E,G的最小生成树的顶点集为Vnew,边集为Enew。
PRIM算法的主要思想是以图中的点为基础,先随机选择一点加入Vnew,然后寻找所有的边<m,n>中,m在Vnew中,n不在Vnew中,且权值最小的边,将n加入Vnew中,<m,n>加入Enew,直到|Vnew| = |V|
Kurskal算法的主要思想是以图中的边为基础,不断的从E中选择最小的边<m,n>,并判断m,n是否属于同一连通分量。如果m,n都不属于连通分量,则将<m,n>加入Enew。
3. 设计
PRIM:
While (|Vnew| != |V|)
{
Endpoint = 0//每一轮选择的终止点的编号
Startpoint = 0//每一轮选择的起始点的编号
Min = infinity//记录最小值
For i in Vnew
If 存在边<i,k>的value < min
{
Endpoint = k;
Startpoint = i;
Min = <i,k>.value
}
Vnew += Endpoint;
Enew += <Startpoint,Endpoint>
}
Kurskal:
While(|E| != empty)
{
找到E中权值最小的边<m,n>
E -= <m,n>
If(<m,n>不在同一连通分量)
{
Enew += <m,n>
}
}
4. 分析
针对朴素的PRIM算法,时间复杂读为O(|V|2),首先针对关键代码,最外面的大循环要执行|V|次,针对循环内,复杂度为O(|V|),因此时间复杂度为O(|V|2).
Kurskal算法,因为一开始要对所有的边的权重进行排序,因此时间复杂度主要是由排序算法产生的,用快速排序进行,那么时间复杂度主要是O(Elog|E|)
5. 源码
https://github.com/fanchile/Algorithm
6. 扩展
(1)对于Kurskal与PRIM算法的证明
(2)Kurskal算法中,如何判断选取的边的两个点在不同的连通分量上
主要是并查集的使用,并查集用来管理不相交的集合,并支持两种操作
- merge 将两个不相交的集合合并
- find 查找两个元素是否在同一个集合
还可以对并查集进行路径压缩