生成树
1.一个连通图的生成树是一个极小连通子图,它含有原图中全部顶点,并且有保持图连通的最少的边。
2.生成树不唯一。
![](https://i-blog.csdnimg.cn/blog_migrate/5363387c928e961867f3d0933c1284f8.png)
最小生成树
设
G=(V,E)
G
=
(
V
,
E
)
是一个无向连通网,生成树上各边的权值之和为该生成树的代价,在
G
G
的所有生成树中,代价最小的生成树称为最小生成树。
![](https://i-blog.csdnimg.cn/blog_migrate/7972c88cd0ed966d541b1247d0ede0f3.png)
贪心策略
在最小生成树问题中,至少有两种合理地贪心策略:
- 最近顶点策略
- 最短边策略
1.最近顶点策略
任选一个顶点,并以此建立起生成树,每一步的贪心选择是简单地把不在生成树中的最近顶点添加到生成树中。
Prim算法就应用了这个贪心策略,它使生成树以一种自然的方式生长,即从任意顶点开始,每一步为这个顶点加一个分枝,直到生成树中包含全部顶点。
设最小生成树T=(U,TE),初始化时U={}(
u0
u
0
为任意顶点),TE={ }。Prim算法的关键是如何找到连接 U 和 V-U 的最短边来扩充生成树T。
对于每一个不在当前生成树中的顶点v∈ V-U,必须知道它连接生成树中每一个顶点u∈U的边信息,从中选择最短边。
所以,对当前不在生成树中的顶点v∈ V-U,需要保存两个信息:lowcost[v]表示顶点v到生成树中所有顶点的最短边;adjvex[v]表示该最短边在生成树中的顶点。
以下图所示的连通网为例,用Prim算法构造最小生成树。
![](https://i-blog.csdnimg.cn/blog_migrate/7296f80fc991d6ec59c2101202977f5d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/090c8c8db824377621ededdda5a8e631.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c3f8bf9abddff507a226a6b37e0fa5f6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/49b4766b02c51c68544daaa963ac09b2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/79688baab82ce477e23fe860b274d52a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/34d846b4b7bcdfec1991c4db9e9a4f59.png)
伪代码描述
- 初始化两个辅助数组 lowcost l o w c o s t 和 adjvex a d j v e x ;
- U={ u0 u 0 };输出顶点 u0 u 0 ; //将顶点 u0 u 0 加入生成树中
- 重复执行下列操作
n−1
n
−
1
次
3.1 在 lowcost l o w c o s t 中选择最短边,取 adjvex a d j v e x 中对应的顶点序号 k k ;
3.2 输出顶点 和对应的权值;
3.3 U=U+k U = U + k ;
3.4 调整数组 lowcost l o w c o s t 和 adjvex a d j v e x ;
时间复杂度
分析Prim算法,设连通网中有 n 个顶点,则第一个进行初始化的循环语句需要执行 n-1 次,第二个循环共执行 n-1 次,内嵌两个循环,其一是在长度为 n 的数组中求最小值,需要执行 n-1 次,其二是调整辅助数组,需要执行 n-1 次,所以,Prim 算法的时间复杂度为 O(n2) O ( n 2 ) 。
2.最短边策略
设G=(V,E)是一个无向连通网,令T=(U,TE)是G的最小生成树。最短边策略从TE={ }开始,每一次贪心选择都是在边集E中选择最短边(u,v),如果边(u,v)加入集合TE中不产生回路,则将边(u,v)加入边集TE中,并将它在集合E中删去。
Kruskal算法就应用了这个贪心策略,它使生成树以一种随意的方式生长,先让森林中的树木随意生长,没生长一次就将两棵树合并,到最后合并成一棵树。
以下图所示的连通网为例,用Kruskal算法构造最小生成树。
伪代码描述:
- 初始化:U=V;TE={ };
- 循环直到T中的连通分量个数为1
2.1 在E中寻找最短边(u,v);
2.2 如果顶点u、v位于T的两个不同连通分量,则
2.2.1 将边(u,v)并入TE;
2.2.2 将这两个连通分量合并为一个;
2.3 E=E- {(u,v)};
时间复杂度
Kruskal算法为了提高每次贪心选择时查找最短边的效率,可以先将图G中的边按代价从小到达排序,则这个操作的时间复杂度为 O(elog2e) O ( e l o g 2 e ) ,其中e为无向连通网中边的个数。对于两个顶点是否属于同一个连通分量,可以用并查集的操作将其时间性能提高到 O(n) O ( n ) ,所以Kruskal算法的时间性能是 O(elog2e) O ( e l o g 2 e ) 。