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

文章目录

    • 前言
    • 参考目录
    • 学习笔记
      • 1:介绍
      • 1.1:定义
      • 1.2:应用
      • 2:贪心算法 greedy algorithm
      • 2.1:简化假设
      • 2.2:切分定理
      • 2.3:demo 演示
      • 2.4:贪心算法的证明
      • 2.5:算法实现简要说明
      • 2.6:删除简化假设
      • 3:加权边 API
      • 3.1:加权边 API (Weighted edge API)
      • 3.2:Java 实现
      • 3.3:加权无向图的API(Edge-weighted graph API)
      • 3.4:Java 实现
      • 4:Kruskal 算法
      • 4.1:demo 演示
      • 4.2:证明
      • 4.3:Java 实现
      • 4.4:运行时间
      • 5:Prim 算法
      • 5.1:demo 演示
      • 5.2:证明
      • 5.3:实现:延迟实现 (lazy implementation)
      • 5.3.1:demo 演示
      • 5.3.2:Java 实现
      • 5.3.3:运行时间
      • 5.4:实现:即时实现(eager implementation)
      • 5.4.1:demo 演示
      • 5.4.2:索引优先队列(Indexed priority queue)
      • 5.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)是值得投入精力提升性能的。
  • 斐波那契堆在理论上的优越性虽高,但在实际开发中却未必值得进行具体实现。

(完)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/535485.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年GitHub 上那些优秀Android开源库,这里是Top10!

6.1 如何使用&#xff1f; 在build.gradle 中添加如下依赖&#xff1a; dependencies { implementation ‘nl.joery.animatedbottombar:library:1.0.8’ } 在xml文件中添加AnimatedBottomBar和自定义属性 <nl.joery.animatedbottombar.AnimatedBottomBar android:id“id…

PFA容量瓶volumetric flask应用研究分析

容量瓶是一个透明的长颈瓶&#xff0c;瓶体为梨形&#xff0c;便于摇荡液体和刷洗。每一个PFA容量瓶上的刻度线都是用千分之一的电子天平称量、标注&#xff0c;PFA容量瓶以其优异的耐化学腐蚀性和热稳定性&#xff0c;在实验室器皿中占有重要地位。随着科学技术的不断发展&…

JVM诊断,调优(STW)

调优目的 1.尽可能让对象在新生代进行回收&#xff0c;避免进入老年代 2.给内存足够大小&#xff0c;避免新生代频繁的进行回收 STW机制设置的原因 线程结束后&#xff0c;局部变量也就释放了&#xff0c;堆区对象的引用也就失效了&#xff0c;就变为垃圾对象&#xff0c;若…

【JavaScript】JS基础、元素属性、定时器函数、事件监听

JS基础 <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style></style> </head>…

上位机图像处理和嵌入式模块部署(qmacvisual串口输出结果)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们谈到了图像的输入、算法的添加&#xff0c;一切看上去都没有问题。但是这中间缺少了一个重要的环节&#xff0c;那就是结果的输出。如果我…

[Java、Android面试]_02_HashMap的原理

本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料&#xff0c;感兴趣的朋友可收藏关注。由于时间有限&#xff0c;只能每天整理一点&#xff0c;分享一点儿&#xff01; 现分享如下&#xf…

代码随想录算法训练营第25天|216.组和总和三、17.电话号码的字母组合

目录 一、力扣216.组合总和三1.1 题目1.2 思路1.3 代码 二、力扣17.电话号码的字母组合2.1 题目2.2 思路2.3 代码 一、力扣216.组合总和三 1.1 题目 1.2 思路 自己的想法&#xff1a;和总和问题思路类似&#xff0c;回溯法。 &#xff08;1&#xff09;k个数的组合&#xff0…

【C语言】三种方式实现字符串(char*)/字符数组(char[ ])输入输出

前言 做题时经常需要用到字符串&#xff0c;写篇笔记加强记忆&#xff0c;本文用 4个例子实现字符串的输入输出操作。 scanf(); 从键盘输入数据时&#xff0c;遇到 “空格”、“回车” 都会终止。若要接受空格&#xff0c;使用 gets(); 代替 scanf(); 多个 scanf(); 同时出现…

yum安装mysql、数据库tab自动补全,快来浅了解下 ?

centos7上面没有mysql&#xff0c;它的数据库名字叫做mariadb [rootlocalhost ~]#yum install mariadb-server -y [rootlocalhost ~]#systemctl start mariadb.service [rootlocalhost ~]#systemctl stop firewalld [rootlocalhost ~]#setenforce 0 [rootlocalhost ~]#ss -na…

(自用笔记)每天一点vue3—— echarts横坐标刻度标签显示不完全的问题

我是想做一个vue3echarts的账单数据展示项目&#xff0c;因为有vue2的基础&#xff0c;打算直接在这个项目上熟悉掌握vue3的新特性。这系列笔记就按照遇见问题解决问题的思路更新&#xff0c;不按照官方快速上手的章节&#xff0c;特此说明。 echarts 上次遗留一个横坐标刻度标…

CSS学习2

自己在工作中总是有一些自动化开发的需求&#xff0c;总是以为自己是有前端基础的&#xff0c;但是一写页面&#xff0c;布局都布不好&#xff0c;真是搞笑&#xff0c;说起来还是基本功不扎实啊&#xff0c;这里在重新复习一下&#xff0c;然后记录一下文档。后边在写两个综合…

判断出栈顺序是否合法

给你一个入栈顺序&#xff0c;判断出栈顺序是否合法 入栈的顺序&#xff08;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff09;出栈&#xff08;4&#xff0c;5&#xff0c;3&#xff0c;2&#xff0c;1&#xff09;是合法序列 入栈的顺序&#xff08;1&…