数据结构与算法之最小生成树
最小生成树的概念
生成树概念
连通图的生成树是包含图中全部顶点的一个极小连通子图。
边尽可能的少,但要保持连通
若图中顶点数为 n,则它的生成树含有 n − 1 n-1 n−1条边。对于生成树而言,若砍去它的一条边,则会变成非连通图,若加上一条边则会形成一个回路。
最小生成树 (最小代价树)
如下图,思考:道路规划要求:所有地方都连通,且成本尽可能的低
下面是提供的两种方案,看图:
此处引出最小生成树的概念,又称为最小代价树。
最小生成树概念
对于一个带权连通无向图 G = ( V , E ) G=(V,E) G=(V,E),生成树不同,每颗树的权 (即树中所有边上的权值之和) 也可能不同。设 R 为 G 的所有生成树的集合,若 T 为 R 中边的权值之和最小的生成树,则 T 称为 G 的最小生树 (Minimum-Spanning-Tree,MST)。
-
最小生成树可能有多个,但边的权值之和总是唯一且最小的
-
最小生成树的边数=顶点数 -1.砍掉一条则不连通,增加一条边则会出现回路。
-
若果连通图本身就是一棵树,则其最小生成树就是它本身
-
只有连通图才有生成树,非连通图只有森林
-
而求最小生成树就需要用到:Prim算法和Kruskal 算法
-
Prim 算法
算法思想:
- 从某一顶点开始构建生成树;
- 每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。
- 时间复杂度: O ( ∣ V ∣ 2 ) O(|V|^2) O(∣V∣2)
- 适合用于边稠密图
算法实现
- 从 V_0 开始,总共需要 n-1 轮循环。
- 每一轮处理:循环遍历所有结点,找到 lowCase 最低的,且还没加入树的顶点。
- 再次循环遍历,更新还没加入的各个顶点的 lowCase 值
以下面这个连通图为例:
-
初始:从 V 0 V_0 V0开始
-
标记各节点是否已经加入树
-
各节点加入树的最低代价 (没有边连通,就是无穷)
-
-
第一轮:循环遍历所有结点,找到 lowCast 最低的,且还没有加入树的顶点。
-
再次循环遍历,更新还没加入各个顶点的 lowCast 值。
-
第一轮:循环遍历所有结点,找到 lowCast 最低的,且还没有加入树的顶点。
Kruskal 算法
算法思想:
- 每次选择一条权值最小的边,使者条边的两头连通 (原本已经连通的就不选)
- 直到所有结点都连通
- 时间复杂度: O ( ∣ E ∣ l o g 2 ∣ E ∣ ) O(|E|{log}_2|E|) O(∣E∣log2∣E∣)
- 适合用于边稀疏图
算法实现
如下图,进行Kruskal算法获取最小生成树
-
初始:将各条边按权值排序,结果如下图
-
第一轮:检查第一条边的两个顶点是否连通(是否属于同一个集合) ^ac06e2
- 不连通,连起来
-
后序几轮依次进行1操作
共执行e[边数]轮,每轮判断两个顶点是否属于同一集合,需要 O ( l o g 2 e ) O({log}_2e) O(log2e)