【Algorithms 4】算法(第4版)学习笔记 17 - 4.3 最小生成树

前言

本篇主要内容包括:贪心算法加权边 APIKruskal 算法 以及 Prim 算法

参考目录

  • B站 普林斯顿大学《Algorithms》视频课
    (请自行搜索。主要以该视频课顺序来进行笔记整理,课程讲述的教授本人是该书原版作者之一 Robert Sedgewick。)
  • 微信读书《算法(第4版)》
    (本文主要内容来自《4.3 最小生成树》)
  • 官方网站
    (有书本配套的内容以及代码)

学习笔记

注1:下面引用内容如无注明出处,均是书中摘录。
注2:所有 demo 演示均为视频 PPT demo 截图。
注3:如果 PPT 截图中没有翻译,会在下面进行汉化翻译,因为内容比较多,本文不再一一说明。

开篇语:

Today, we’re gonna talk about minimum spanning trees. This is a terrific topic for this course, because it combines a number of classic algorithms with modern data structures to solve a variety of huge problems that are important in practical applications nowadays.

今天,我们要讨论的是最小生成树这一主题,这对于本课程而言是一个绝佳的话题,因为它结合了多种经典算法以及现代数据结构,用于解决当今实际应用中一系列规模庞大且重要的问题。

1:介绍

1.1:定义

![image-20240311113055995]

定义: 一个图 G 的生成树 T 是指这样一个子图:

  • 连通的(Connected):从任一顶点出发可以到达其他所有顶点。
  • 无环的(Acyclic):不存在任何闭合的回路。
  • 包含所有顶点(Includes all of the vertices):图 G 中的每一个顶点都在生成树 T 中。

![image-20240312085713462]

1.2:应用

![L14-43MinimumSpanningTrees_12]

最小生成树(MST)问题是具有广泛实际应用的基础问题,包括但不限于以下几个方面:

  • 颗粒化(Dithering)技术。
  • 聚类分析(Cluster analysis)。
  • 最大瓶颈路径(Max bottleneck paths)问题求解。
  • 实时人脸识别验证(Real-time face verification)算法。
  • 采用低密度奇偶校验码(LDPC codes)进行错误校正。
  • 利用 Rényi 熵进行图像配准(Image registration)。
  • 在卫星和航空影像中寻找道路网络(Find road networks)。
  • 在蛋白质氨基酸序列测定中减少数据存储量。
  • 模拟湍流流体中粒子相互作用的局部性(Model locality of particle interactions in turbulent fluid flows)。
  • 以太网桥接自配置协议(Autoconfig protocol)避免网络中形成环路。
  • 近似算法用于解决NP难问题(例如,旅行商问题[TSP],Steiner树问题)。
  • 各种网络设计(包括通信网络、电力网络、液压网络、计算机网络、道路交通网络等)。

2:贪心算法 greedy algorithm

2.1:简化假设

![L14-43MinimumSpanningTrees_14]

2.2:切分定理

![L14-43MinimumSpanningTrees_15]

(这一部分参照书里面的内容)

![image-20240312092751990]

![image-20240312092900141]

![image-20240312093007272]

2.3:demo 演示

![image-20240312101237526]

对应书本命题 K:

![image-20240312101259580]

初始状态:

![image-20240312101532357]

切分后:

![image-20240312102300923]

边 0 - 2 标记为黑色,继续切分:

![image-20240312141550499]

边 5 - 7 标记为黑色,继续切分:

![image-20240312141703824]

边 6 - 2 标记为黑色,继续切分:

![image-20240312142035609]

边 0 - 7 标记为黑色,继续切分:

![image-20240312142159507]

边 2 - 3 标记为黑色,继续切分:

![image-20240312142248914]

边 1 - 7 标记为黑色,继续切分:

![image-20240312142340359]

边 4 - 5 标记为黑色:

![image-20240312142551219]

此时图中 8 个顶点,找到了最小权重的 7 条横切边,这就是 MST。

2.4:贪心算法的证明

![L14-43MinimumSpanningTrees_19]

对应书本命题 K 证明:

![image-20240312143538843]

2.5:算法实现简要说明

![L14-43MinimumSpanningTrees_20]

2.6:删除简化假设

![L14-43MinimumSpanningTrees_21]

3:加权边 API

3.1:加权边 API (Weighted edge API)

![image-20240312150749392]

3.2:Java 实现

edu.princeton.cs.algs4.Edge

![image-20240312151302437]

![image-20240312151350567]

3.3:加权无向图的API(Edge-weighted graph API)

![image-20240312160121371]

3.4:Java 实现

edu.princeton.cs.algs4.EdgeWeightedGraph

![image-20240312164956422]

edu.princeton.cs.algs4.EdgeWeightedGraph#addEdge

![image-20240312165057789]

edu.princeton.cs.algs4.EdgeWeightedGraph#adj

![image-20240312165107403]

4:Kruskal 算法

![image-20240312171123694]

4.1:demo 演示

![image-20240312170656179]

按权重递增顺序考虑边。

  • 如果添加下一条边不会形成环,则将其加入树 T 中。

初始状态:

![image-20240312170923449]

过程比较长,直接引用 官网的图 进行说明:

![image-20240312172622532]

最终产生的 MST:

![image-20240312172849804]

4.2:证明

![L14-43MinimumSpanningTrees_35]

对应书本命题 O 的证明:

![image-20240312173423438]

4.3:Java 实现

edu.princeton.cs.algs4.KruskalMST

![image-20240312174024478]

![image-20240312174156912]

4.4:运行时间

![L14-43MinimumSpanningTrees_39]

对应书本命题 N:

![image-20240312175308458]

5:Prim 算法

![image-20240312175600736]

image-20240312175642876

5.1:demo 演示

![image-20240312175757968]

  • 从顶点 0 开始,并贪婪地构建树 T。
  • 将恰好有一个端点在树 T 中的最小权重边添加到 T 中。
  • 重复此过程,直到添加了 V-1 条边为止。

初始状态:

![image-20240313102606209]

首先找到最短(权重最小)横切边 0 - 7 加入 MST:

![image-20240313104129298]

继续寻找连接 MST 的最短边 1 - 7 加入 MST:

![image-20240313104302676]

继续寻找连接 MST 的最短边 0 - 2 加入 MST:

![image-20240313104756437]

继续寻找连接 MST 的最短边 2 - 3 加入 MST:

![image-20240313105306428]

继续寻找连接 MST 的最短边 5 - 7 加入 MST:

![image-20240313105347293]

继续寻找连接 MST 的最短边 4 - 5 加入 MST:

![image-20240313105418937]

继续寻找连接 MST 的最短边 6 - 2 加入 MST:

![image-20240313105500762]

最终结果:

![image-20240313105544753]

5.2:证明

![L14-43MinimumSpanningTrees_44]

命题: [Jarník 1930, Dijkstra 1957, Prim 1959]
Prim 算法可以计算最小生成树(MST)。

证明: Prim 算法是 MST 贪心算法的一个特例。

  • 假设边 e 为连接树上顶点与非树顶点的具有最小权重的边。
  • 切割集(切分,Cut)由树上连接的所有顶点组成。
  • 没有跨越边(横切边)被标记为黑色。
  • 没有跨越边(横切边)的权重更低。

对应书本命题 L 的证明:

![image-20240313110720937]

5.3:实现:延迟实现 (lazy implementation)

![L14-43MinimumSpanningTrees_46]

**挑战:**找到仅有一端属于集合 T 的最小权重边。

**延迟解决方案:**维持一个优先队列(PriorityQueue),其中包含至少一端点属于集合 T 的边。

  • 使用键值对存储边,其中键是边本身,值是边的权重。
  • 通过调用优先队列的删除最小元素函数找到下一条要添加到集合 T 中的边 e(记作 v - w)。
  • 若边 e 的两个端点 v 和 w 都已被标记为在 T 中,则跳过这条边不处理。
  • 否则,假设 w 未被标记(不在 T 中):
    • 将所有连接 w 且另一端点目前不在 T 中的边加入到优先队列中;
    • 将边 e 加入到集合 T 中,并标记顶点 w 为已在 T 中。

5.3.1:demo 演示

初始状态:

![image-20240313142214977]

从顶点 0 开始,所有与之相关的边加入到优先队列 PQ,并按照权重排序:

![image-20240313142537151]

删除 PQ 中最小值边 0 - 7,加入到 MST:

![image-20240313142717564]

![image-20240313142753283]

将顶点 7 相关的边加入到优先队列 PQ,并按照权重排序:

![image-20240313142844465]

删除 PQ 中最小值边 1 - 7,加入到 MST:

![image-20240313145847465]

![image-20240313145906173]

将顶点 1 相关的边加入到优先队列 PQ,并按照权重排序:

![image-20240313145952535]

删除 PQ 中最小值边 0 - 2,加入到 MST:

![image-20240313150036045]

在这里插入图片描述

将顶点 2 相关的边加入到优先队列 PQ(边 1 - 2、2 - 7 已经过时,不需要添加),并按照权重排序:

![image-20240313152145161]

删除 PQ 中最小值边 2 - 3,加入到 MST:

![image-20240313152240989]

在这里插入图片描述

将顶点 3 相关的边加入到优先队列 PQ(边 1 - 3 已经过时,不需要添加),并按照权重排序:

![image-20240313152530544]

删除 PQ 中最小值边 5 - 7,加入到 MST:

![image-20240313152624070]

在这里插入图片描述

将顶点 5 相关的边加入到优先队列 PQ(边 1 - 5 已经过时,不需要添加),并按照权重排序:

![image-20240313152735994]

删除 PQ 中过时的边 1 - 3、1 - 5、2 - 7。

删除 PQ 中最小值边 4 - 5,加入到 MST:

![image-20240313153047062]

在这里插入图片描述

将顶点 4 相关的边加入到优先队列 PQ(边 4 - 7、0 - 4 已经过时,不需要添加),并按照权重排序:

![image-20240313153241505]

删除 PQ 中过时的边 1 - 2、4 - 7、0 - 4。

删除 PQ 中最小值边 6 - 2,加入到 MST:

![image-20240313153328040]

在这里插入图片描述

此时对于 V 个顶点已经有 V-1 条边,可以停止。

5.3.2:Java 实现

edu.princeton.cs.algs4.LazyPrimMST

![image-20240313153726641]

![image-20240313153855668]

edu.princeton.cs.algs4.LazyPrimMST#scan

![image-20240313154149665]

5.3.3:运行时间

![L14-43MinimumSpanningTrees_51]

对应书本命题 M:

![image-20240313154507366]

5.4:实现:即时实现(eager implementation)

![L14-43MinimumSpanningTrees_52]

**挑战:**找到与树 T 有且仅有一个端点相连的最小权重边。

**即时解决方案:**维护一个优先队列(其中每个顶点最多有一个条目),包含通过边与树 T 相连接的所有顶点,顶点 v 的优先级等于连接 v到 T 的最短边的权重。

  • 从优先队列中删除具有最小优先级的顶点 v,并将其关联的边 e = v - w 添加到 T 中。
  • 考虑所有与顶点 v 相连的边 e = v - x。
    • 如果 x 已经位于树 T 中,则忽略这条边。
    • 如果 x 尚未加入优先队列,则将 x 添加到优先队列中。
    • 如果经过边 v - x 后,x 到 T 的最短边距离变小,则更新 x 在优先队列中的优先级。

5.4.1:demo 演示

初始状态:

![image-20240313160553416]

从顶点 0 开始,所有与之相邻的顶点 7、2、4、6 加入到优先队列 PQ,并按照权重排序:

![image-20240313160726419]

边 0 - 7 权重最小,加入 MST:

![image-20240313160924040]

继续检查顶点 7,与之相邻的顶点 1、5 加入 PQ(顶点 2、4 已经在 PQ 中),并按照权重排序:

![image-20240313161210350]

边 1 - 7 权重最小,加入 MST:

![image-20240313161638191]

继续检查顶点 1,与之相邻的顶点 3 加入 PQ(顶点 5、7 已经在 PQ 中),并按照权重排序:

![image-20240313161754133]

边 0 - 2 权重最小,加入 MST:

![image-20240313161917509]

继续检查顶点 2,与之相邻的顶点 3、6 权重变小,更新权重后重新排序:

![image-20240313162137051]

边 2 - 3 权重最小,加入 MST:

![image-20240313162355439]

继续检查顶点 3,与之相邻的顶点 6 已经在 PQ 中,无需做任何操作:

![image-20240313162532074]

边 5 - 7 权重最小,加入 MST:

![image-20240313162619724]

继续检查顶点 5,与之相邻的顶点 4 权重变小,更新权重后重新排序:

![image-20240313162715259]

边 4 - 5 权重最小,加入 MST:

![image-20240313162830329]

继续检查顶点 4,与之相邻的顶点 6 已经在 PQ 中,无需做任何操作:

![image-20240313162859047]

最后一条边 6 - 2,加入 MST:

![image-20240313162935350]

最终结果:

![image-20240313163035162]

5.4.2:索引优先队列(Indexed priority queue)

![L14-43MinimumSpanningTrees_55]

为优先队列中的每个键关联一个介于 0 和 N - 1 之间的索引。

  • 支持插入(insert)操作,即可以将带有特定索引的键值插入队列中。
  • 支持删除最小元素(delete-the-minimum)操作,即能够移除并返回当前优先队列中优先级最高的元素。
  • 支持基于索引的减小键值(decrease-key)操作,给定键的索引时,允许修改该键对应的值,使其优先级降低。

edu.princeton.cs.algs4.IndexMinPQ

![image-20240313163727738]

5.4.3:运行时间

![L14-43MinimumSpanningTrees_57]

核心要点:

  • 采用数组实现对稠密图(Dense graphs)而言是最佳方案。
  • 对于稀疏图(Sparse graphs),二叉堆在性能上要快得多。
  • 在对性能要求极高的情况下,使用四路堆(4-way heap)是值得投入精力提升性能的。
  • 斐波那契堆在理论上的优越性虽高,但在实际开发中却未必值得进行具体实现。

(完)

  • 24
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MichelleChung

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值