最小生成树(MST)算法:Prim与Kruskal的比较与实现
字数 2190 2025-11-14 18:54:21
最小生成树(MST)算法:Prim与Kruskal的比较与实现
题目描述
最小生成树(Minimum Spanning Tree,MST)是指在一个带权的无向连通图中,找到一个边的子集,使得这些边能够连接所有顶点,并且这些边的权值之和最小。Prim算法和Kruskal算法是求解MST的两种经典方法,两者的核心思想、实现细节和适用场景有所不同。
解题过程
1. 问题分析
- 输入:一个带权的无向连通图 \(G = (V, E)\),其中 \(V\) 是顶点集合,\(E\) 是边集合,每条边有权重。
- 输出:一个边的集合 \(T \subseteq E\),使得 \(T\) 构成一棵树,连接所有顶点,且总权重最小。
- 关键约束:生成树不能有环(树的性质),且必须包含所有顶点(连通性)。
2. Kruskal算法:基于边的贪心策略
核心思想:每次选择权重最小的边,若加入该边后不会形成环,则将其加入生成树。
步骤详解:
- 排序边:将图中所有边按权重从小到大排序。
- 初始化并查集:每个顶点初始化为一个独立的集合(用于检测环)。
- 遍历边:按权重从小到大检查每条边 \((u, v)\):
- 若 \(u\) 和 \(v\) 属于不同集合(即不连通),则加入该边,并合并两个集合。
- 若属于同一集合,说明加入后会形成环,跳过。
- 终止条件:已加入 \(|V| - 1\) 条边时结束。
示例(图略,可用文字描述):
假设边排序后为:\((A,B,1), (B,C,2), (A,C,3)\)
- 加入 \((A,B)\):集合合并为 {A,B}, {C}
- 加入 \((B,C)\):合并为 {A,B,C}
- 跳过 \((A,C)\)(会形成环)
生成树包含边 \((A,B)\) 和 \((B,C)\),总权重为 3。
时间复杂度:
- 排序边:\(O(|E| \log |E|)\)
- 并查集操作(路径压缩+按秩合并):近似 \(O(|E| \alpha(|V|))\)(α为反阿克曼函数)
- 总复杂度:\(O(|E| \log |E|)\),适合边稀疏的图(\(|E| \ll |V|^2\))。
3. Prim算法:基于顶点的贪心策略
核心思想:从任意顶点开始,逐步扩展生成树,每次选择连接树与非树顶点的最小权重边。
步骤详解:
- 初始化:选择任意顶点作为起点,将其加入生成树集合 \(S\)。
- 维护优先队列:使用最小堆(优先队列)存储所有连接 \(S\) 与非 \(S\) 顶点的边(或直接存储非树顶点到树的最小距离)。
- 迭代扩展:
- 从堆中取出最小权重的边 \((u, v)\),其中 \(u \in S, v \notin S\)。
- 将 \(v\) 加入 \(S\),并更新与非树顶点相邻的边权重(若新边权重更小,则更新堆)。
- 终止条件:所有顶点均加入 \(S\)。
示例(同上图):
从顶点 A 开始:
- 初始:\(S = \{A\}\),边队列:\((A,B,1), (A,C,3)\)
- 取出 \((A,B)\):加入 B,\(S = \{A,B\}\),更新队列为 \((B,C,2), (A,C,3)\)
- 取出 \((B,C)\):加入 C,生成树完成。
时间复杂度:
- 使用邻接表+最小堆:每次更新堆需 \(O(\log |V|)\),共 \(O(|E| \log |V|)\)
- 适合边稠密的图(若用斐波那契堆可优化至 \(O(|E| + |V| \log |V|)\))。
4. 算法比较
| 特性 | Kruskal | Prim |
|---|---|---|
| 核心思想 | 按边贪心,避免环 | 按顶点扩展,维护最小边 |
| 数据结构 | 并查集+排序 | 优先队列(堆) |
| 时间复杂度 | $ O( | E |
| 适用场景 | 边稀疏图($ | E |
| 实现难度 | 简单(需并查集) | 中等(需维护堆) |
5. 关键点总结
- 贪心策略有效性:两种算法均通过局部最优选择达到全局最优,证明依赖于MST的割性质(Cut Property)。
- 环检测:Kruskal用并查集,Prim通过维护树集合自然避免环。
- 实际应用:Kruskal常用于电缆布线、网络设计;Prim在图像分割、聚类中更常见。