考点频率 :★★★★★(选择题必考,下午题偶尔结合图考查算法选边过程)
难度 :⭐⭐⭐⭐
建议:重点掌握Prim和Kruskal的选边策略差异,能模拟两种算法的执行过程,熟记时间复杂度与适用场景
1️⃣ 什么是最小生成树?
最小生成树(Minimum Spanning Tree,MST) 是图论中的一个核心概念,定义如下:
在一个带权连通无向图 中,选择 n−1n-1n−1 条边,将所有 nnn 个顶点连接起来,使得边的总权值之和最小。这样形成的树称为最小生成树。
打个比方 :你是电信公司的工程师,要在 nnn 个城市之间铺设光缆。城市之间的道路距离(权值)已知。你的任务是用最短的总长度 把 nnn 个城市全部连通------不需要每两个城市都直接连,只要所有城市能互相连通即可(可以经过中间城市)。这个问题的最优解就是最小生成树。
最小生成树的重要性质:
- 一棵有 nnn 个顶点的树,恰好有 n−1n-1n−1 条边
- 最小生成树不唯一(当存在相同权值的边时,可能有多种方案),但总权值唯一(如果图的边权不全相等,MST可能不唯一)
- 最小生成树中没有环路(树的基本性质)
- 任何最小生成树都满足 "切割性质" :对于任意一个顶点集合 SSS,连接 SSS 和 V−SV-SV−S 的最小权值边一定属于某棵最小生成树
求解最小生成树的两种经典算法:
- Prim算法:从顶点出发,逐步"长大"成一棵树(类似"贪心式扩张")
- Kruskal算法:从边出发,逐步合并森林(类似"贪心式并集")
这两种算法都基于贪心策略,但贪心的对象不同------Prim贪心的是"离当前树最近的顶点",Kruskal贪心的是"当前最小的边"。
2️⃣ Prim算法(从顶点出发,逐步扩张)
2.1 核心思想
Prim算法的策略是:
从任意一个顶点 开始,把它看作一棵树的根。然后每次选择一条连接"已选顶点集合"和"未选顶点集合"的权值最小的边 ,把这条边和它连接的新顶点加入树中。重复 n−1n-1n−1 次,直到所有顶点都被包含。
打个比方 :Prim算法像野火蔓延------从一个着火点开始,火势每次向"最近的未燃烧区域"扩散一步,直到整片森林都被点燃。
2.2 算法步骤
- 从图中任意选择一个顶点作为起点,加入集合 SSS(已选顶点集合)
- 在连接 SSS 与 V−SV-SV−S 的所有边中,选择权值最小 的一条边 (u,v)(u, v)(u,v),其中 u∈Su \in Su∈S,v∈V−Sv \in V-Sv∈V−S
- 将 vvv 加入 SSS,将边 (u,v)(u, v)(u,v) 加入最小生成树
- 重复步骤2-3,直到 SSS 包含所有顶点(共 n−1n-1n−1 次)
2.3 执行过程示例
图:4个顶点,边权如下
-
1-2: 6, 1-4: 5, 1-3: 1
-
2-3: 5, 2-4: 3
-
3-4: 6
1 / | \ 1 / | \ 5 / | \3----|----4
\ | /
5\ | /3
|/
2
从顶点1开始,逐步选择最小边:
| 步骤 | 已选顶点集合 SSS | 候选边(连接S和V-S) | 选择 | 累计权值 |
|---|---|---|---|---|
| 初始 | {1} | (1-3):1, (1-2):6, (1-4):5 | 选 1-3(权1) | 1 |
| 2 | {1, 3} | (1-2):6, (1-4):5, (3-2):5, (3-4):6 | 选 1-4 (权5)或 3-2(权5) | 6 |
| 3 | {1, 3, 4} | (1-2):6, (3-2):5, (4-2):3 | 选 4-2(权3) | 9 |
最小生成树总权值 = 1 + 5 + 3 = 9(边集:1-3, 1-4, 4-2)
注意:当有相同权值的候选边时,选哪条都可以,最终总权值相同,但树的形态可能不同。
2.4 Prim算法的复杂度与适用场景
| 存储方式 | 时间复杂度 | 说明 |
|---|---|---|
| 邻接矩阵 | O(n2)O(n^2)O(n2) | 适合稠密图 |
| 邻接表 + 二叉堆 | O(elogn)O(e \log n)O(elogn) | 适合稀疏图 |
| 邻接表 + 斐波那契堆 | O(e+nlogn)O(e + n \log n)O(e+nlogn) | 理论上最优 |
适用场景 :Prim算法适合稠密图 (边数多),因为每次选最小边时,用邻接矩阵可以 O(n2)O(n^2)O(n2) 完成,与边数无关。
3️⃣ Kruskal算法(从边出发,逐步合并森林)
3.1 核心思想
Kruskal算法的策略是:
将图中所有边按权值从小到大排序 ,然后从最小的边开始,依次尝试将每条边加入最小生成树 ,如果加入后不形成环路 ,就保留;否则丢弃。重复直到选中 n−1n-1n−1 条边为止。
打个比方 :Kruskal算法像组建联盟------城市之间有许多条可能的连接线路,你从最便宜的线路开始选,只要不会形成"封闭圈子"(环路),就把它纳入计划,直到所有城市都被连通。
3.2 算法步骤
- 将图中所有边按权值从小到大排序
- 初始化一个森林(每个顶点自成一棵树)
- 按排序顺序依次检查每条边:
- 如果这条边连接的两个顶点不在同一棵树中(加入后不形成环),则加入最小生成树,并合并两棵树
- 如果两个顶点已经在同一棵树中,则跳过这条边
- 重复直到选中 n−1n-1n−1 条边
3.3 执行过程示例
用同样的图(4个顶点,边权如下):
边列表(按权值排序):
1-3: 1
2-4: 3
1-4: 5
2-3: 5
1-2: 6
3-4: 6
| 步骤 | 当前边 | 操作 | 结果 |
|---|---|---|---|
| 初始 | --- | 4个顶点各自独立 | {1}, {2}, {3}, {4} |
| 1 | 1-3(权1) | 1和3在不同树 → 加入,合并 | {1,3}, {2}, {4} |
| 2 | 2-4(权3) | 2和4在不同树 → 加入,合并 | {1,3}, {2,4} |
| 3 | 1-4(权5) | 1和4在不同树 → 加入,合并 | {1,2,3,4} |
| 4 | 2-3(权5) | 已在同一树 → 跳过 | --- |
| 5 | 1-2(权6) | 已在同一树 → 跳过 | --- |
| 6 | 3-4(权6) | 已在同一树 → 跳过 | --- |
选中的边 :1-3(权1),2-4(权3),1-4(权5),总权值 = 9
3.4 Kruskal算法的复杂度与适用场景
| 关键操作 | 时间复杂度 | 说明 |
|---|---|---|
| 边排序 | O(eloge)O(e \log e)O(eloge) | 主要开销 |
| 并查集(判断环路) | O(eα(n))O(e \alpha(n))O(eα(n)) | 几乎常数 |
适用场景 :Kruskal算法适合稀疏图 (边数少),因为它的主要开销来自边排序,与边数 eee 的对数成正比。
4️⃣ Prim vs Kruskal(完整对比表,重点!)
| 对比项 | Prim算法 | Kruskal算法 |
|---|---|---|
| 策略 | 从顶点出发,逐步扩张 | 从边出发,逐步合并 |
| 贪心对象 | 每次选连接已选/未选集合的最小权值边 | 每次选全局最小权值边,不形成环则加入 |
| 数据结构 | 邻接矩阵 / 优先队列(堆) | 并查集(判断环路) |
| 时间复杂度(常用实现) | O(n2)O(n^2)O(n2)(邻接矩阵)或 O(elogn)O(e \log n)O(elogn)(堆) | O(eloge)O(e \log e)O(eloge)(边排序) |
| 适合图类型 | 稠密图(边多) | 稀疏图(边少) |
| 起始点 | 需要指定一个起始顶点 | 不需要起始顶点,直接从边开始 |
| 环路判断 | 天然不会形成环(每次只加一个顶点) | 需要用并查集判断是否会形成环 |
| 生成树形态 | 从起点向外"生长" | 多个连通分量逐步合并 |
5️⃣ 经典例题
例题1:对下面的图,用Prim算法从顶点A开始构造最小生成树,写出选边顺序。
A ---(4)--- B
| \ / |
| \ / |
(2) (3) (1)
| / \ |
| / \ |
C ---(5)--- D
解析:
- 从A出发
- 第1步:A的邻边中最小的是A-C(2)→ 选 A-C
- 第2步:当前树 {A,C},连接 {A,C} 和 {B,D} 的最小边是C-D(5)还是A-D(3)?→ 选 A-D(权3)
- 第3步:当前树 {A,C,D},连接 {A,C,D} 和 {B} 的最小边是D-B(1)→ 选 D-B (权1)
总权值 = 2 + 3 + 1 = 6
答案 :A-C → A-D → D-B,总权值6
例题2:对同一图,用Kruskal算法构造最小生成树,写出选边顺序。
解析 :
边排序:D-B(1),A-C(2),A-D(3),A-B(4),C-D(5)
- 选 D-B(1)
- 选 A-C(2)
- 选 A-D(3),检查D在{B,D},A在{A,C},不同树 → 加入
- 已选3条边,结束
答案 :D-B → A-C → A-D,总权值6
6️⃣ 记忆口诀
Prim从顶点出发,每次选最近新顶点。
Kruskal从边出发,最小边集合并查。
稠密图Prim,稀疏图Kruskal。
7️⃣ 小测验(评论区对答案)
用Kruskal算法构造最小生成树,边排序后依次加入。在加入第3条边时,需要检查( )。
A. 该边连接的两个顶点是否已经在同一棵树中
B. 该边连接的两个顶点是否都已经被访问过
C. 该边是否与已选边构成回路
D. A和C都正确
🔔 本专栏日更,点击头像 → 专栏《软考中级高频考点》订阅,第一时间接收新内容
#软考中级 #软件设计师 #最小生成树 #Prim #Kruskal #数据结构 #软考备考