算法《第四版》笔记整理

news2024/11/20 14:23:44

算法第四版

先导例子:动态连通性 - 书中1.5

知识点:并查集-一种用于解决动态连通性问题的算法

描述:对于N个对象,有两种操作:1.连接两个对象 2.判断两个对象是否存在连接路径

如巨大的连通性问题:

在分析问题模型时,可以先把已知的性质写出来,哪怕是显而易见的

1.对称性:如果p与q相连,则q与p连通。

2.传递性:如果p与q相连,而q与r相连,则p与r相连

定义目标的API:

客户端调用:

从标准输入中读取对象数N。

重复:从标准输入读取对整数-如果它们尚未连接,连接它们并打印对

实现及讨论历程:

原有的联合:数据结构。长度为n的整数数组id。解释: id[i]是i的父项。i的根是id[id[id[...id[i]...]]]。

步骤1.将每个对象的ID设置为其自身(N个数组访问)

步骤2.追踪父指针,直到到达根(i数组访问的深度)

步骤3.将p的根更改为指向q的根(p和q数组访问的深度)

改进1:加权。修改快速联合,以避免高大的树木。保持跟踪每棵树的大小(对象的数量)。通过连接小树的根和大树的根来实现平衡。目的是减小树的层数,避免树过高,加快寻找根的速度。

改进前后:

改进方法:

数据结构:与快速并集相同,但是保持额外的数组sz[i]来计算树中基于i的对象的数量。

查找/连接:与快速结合相同。

新快速联合:1.将小树的根链接到大树的根。2.更新存储存储模块数组。

改进2:路径压缩。在计算完p的根之后,将每个被检查节点的id[]设置为指向该根。

只需加入一行代码

应用

  • 渗透率。
  • 游戏(围棋,十六进制)。
  • ✓动态连接。最不共同的祖先。
  • 有限状态自动机的等价性。
  • 物理学中的霍申-科佩尔曼算法。
  • 欣利-米尔纳多态类型推断。
  • Kruskal的最小生成树算法。
  • 在Fortran中编译等价性语句。
  • 形态学属性的开启和关闭。
  • Matlab的bwlabel()在图像处理中的功能。

例子:渗透率

针对许多物理系统的一个抽象模型:N对N的站点网格。每个站点打开的概率为p(阻塞的概率为1-p)。

如果顶部和底部通过开放站点连接,则系统渗透。

如何检查n对n系统是否渗透?模型作为一个动态连接问题,并使用联合查找

如何检查一个n-n的系统是否渗透?为每个站点创建一个对象,并将其命名为0到 N 2 – 1

如何检查一个n-n的系统是否渗透?

为每个站点创建一个对象,并将其命名为0到N2-1。

站点位于由开放的站点连接的同一组件中。

如果底部一行的任何站点都连接到顶部行的任何站点相连。(蛮力算法: N 2调用connected())

聪明的技巧:添加2个虚拟站点(以及连接到顶部和底部的连接)。如果虚拟顶部站点已连接到虚拟底部站点

如何模拟开设一个新的站点?将新站点标记为开放站点;将其连接到所有相邻的开放站点。

算法分析 - 书中1.4

算法分析名词

最好的情况。成本的下限。由“最简单”的输入决定。为所有输入提供一个目标。

最坏的情况。成本的上限。由“最困难”的输入决定。为所有输入提供保证。

平均情况。随机输入的预期成本。需要一个“随机”输入的模型。提供了一种预测性能的方法


我们的目标:确定问题的“困难”。开发“最优”算法。

方法抑制分析中的细节:分析“在一个常数因素范围内”。消除输入模型中的可变性:关注最坏的情况。


上限,算法对任何输入的性能保证。

下界,证明没有任何算法能做得更好。

最优算法:下界=上界(在常数因子内)。

3-SUM问题实例

主要是讲算法性能的分析,重点看一个例子

3-SUM:给定N个不同的整数,有多少三数之和恰好为零?

这个例子与计算几何学中的问题密切相关。

蛮力算法

检查每三个。为简单起见,请忽略整数溢出

现在不知道3-SUM的更好方法,先看另两个例子,1-SUM,2-SUM

1-SUM

1-SUM:给定N个不同的整数,有多少1数之和恰好为零?

有多少条指令作为输入大小N的函数?N次访问

2-SUM

2-SUM:给定N个不同的整数,有多少2数之和恰好为零?

有多少条指令作为输入大小N的函数?N2次访问

3-SUM性能分析

大约有多少次数组访问作为输入大小N的函数?N3次访问

2-SUM,3-SUM快速解法

二叉搜索,首先将数组排序,O(N log N),在用二叉搜索,整体性能,O(N log N)

下面代码是二叉搜索的非递归实现,虽然二叉搜索是个简单的算法,却是众人皆知很难把每个细节实现正确的,实际上直到1962年才发表第一个没有错误的二叉搜索算法,所以我们在开发算法是要极其小心。

3-SUM算法步骤

1:对N个(不同的)数字进行排序。

2:对于每一对数字a和a[j],二进制搜索-(a[i] + a[j])。只有当a[i]


分析。增长顺序为N 2 log N。

步骤1:插入排序N2。

步骤2:加二叉搜索N 2 log N

栈和队列 - 书中1.3

单独的接口和实现

Ex:堆栈、队列、包、优先级队列、符号表、联合查找等

好处:

  • 客户端有很多实现可供选择。
  • 实现不需要知道客户端需求的细节。
  • 许多客户端可以重用相同的实现。
  • 设计:创建模块化的、可重用的库。
  • 性能:在重要的地方使用优化的实现。

API

链表实现

节点定义

在链表头部增加/删除,实现Push/Pop

代码实现

性能:常数级别

内存:有N个项的堆栈需要使用~ 40 N字节

节点对象开销16字节,8字节内部类的额外开销,8字节实际数据开销,8字节节点指针开销,共40字节

数组实现

固定容量的数组实现栈

使用数组s[]可以在堆栈上存储N个项。

push():在s[N]处添加新项目。

pop():从s中删除项目

代码实现,需要客户端提供容量。

下溢出:如果从空堆栈中弹出,则抛出异常。

上溢出:使用调整数组大小的方法进行数组实现。后续改进。

允许插入null项。

游离:当不再需要时仍然保持对对象的引用。

避免游离:将弹出的项手动设为null,只有在没有未完成的引用时,垃圾收集器才能回收对象的内存。

调整数组容量的实现

重复加倍:为了确保调整数组大小很少发生,如果数组已满,则创建一个两倍大小的新数组,并复制项目。

四分之一缩小:如果数组在满一半时缩小,可能存在抖动的情况,在一半的边界频繁增减,性能很坏。通用策略为当数组满四分之一时,数组缩小为数组的一半大小。

所以数组在25%到100%之间为满,此时数组要伸缩。

性能:因为数组的伸缩只发生在少数时间,平摊到整体中,也是常数级别。

内存:在8N到32N之间,在数组使用100%时8N,在数组使用25%时32N。

数组实现和链表实现比较

客户端可以使用由动态数组或链表实现的栈。哪一个更好?

链表实现即使在最坏的情况下,每次操作都需要恒定的时间。需要使用额外的时间和空间。

数组实现总的平均操作效率不错,平均时间比链表要少,浪费更少的空间。

结论:因为数组的单次操作时间不稳定,在伸缩数组时会慢,而链表每次都是常数时间是有保障的,所以对每次操作的时间都要求低且稳定的情况下应选择链表实现。比

如一架飞机进场等待降落,不想系统突然不能高效运转,或者互联网的路由器,数据包高速涌来,不想因为某个操作突然变得很慢而丢失一些数据,选择链表实现。如果关心总的时间,选择数组实现。

队列

API

链表实现

保存一个指针,指向单链列表中的第一个节点。

保存一个指针,指向单链列表中的最后一个节点。

从第一个队列开始退出队列。

从最后一个入队。

入队和出队

代码实现

数组实现

使用数组q[]存储队列中的项目。

enqueue():在q[]处添加新项目。

dequeue():从q[]头中删除项目。

更新头部和尾部的容量。

添加可调整的数组的大小。

这个队列的实现并不完善,比如数组大小固定,当头部和尾部突破界限时未处理,后面自己完善。

泛型

因为要为栈和队列设计单独的接口和实现,如果为每种类型实现一个单独的堆栈类。重写代码非常乏味且容易出错。维护剪切粘贴代码是乏味且容易出错的。

链表实现

数组实现

java数组不支持泛型,所以不得不加入强制类型转换,强制类型转换因为编译时无法判断对错,会在运行时留下隐患,但是我们下面的代码是可靠的。

迭代器

目的:支持通过客户端对堆栈项进行迭代,而不透露堆栈的内部表示。实现foreach

什么是迭代器? 有方法hasnext()和next()

迭代器和非迭代器代码调用比较

利用java接口:

实现 Iterable<>接口

应用

栈的应用

  • 在编译器中进行解析。
  • Java虚拟机。
  • 在文字处理器中进行撤销。
  • Web浏览器中的后退按钮。
  • 打印机的PostScript语言。
  • 在编译器中实现函数调用。

另外:我们设计的栈或队列等在java库中有同样的功能的通用api,实现也是使用的可变大小数组,我们考虑的通用api也同样考虑了,但是有时候不直接使用那些api,因为公共库开发组设计的加入了越来越多的操作,api变、的过宽和臃肿,在api中拥有非常多的操作并不好,真正的问题在于关于库代码的性能知之甚少或者不能对其性能很好的估计,可能会因此遇到性能瓶颈。

比如我们需要访问一个序列的索引,如果我们自定义数组访问会是常数时间,但是如果用库的LinkedList帮助我们存储数据并访问索引则需要线性时间,这就隐藏的降低了我们的性能。

递归就是使用栈,实际上总是能显式的使用栈将递归程序非递归化,需要确定跳出递归的条件。

最大公约数

这是一个递归方式求最大公约数gcd()方法,p与q的最大公约数就是q与p mod q的最大公约数,如此反复对两个数取模求得。

Dijkstra双栈算术表达式

计算中缀算术表达式

  1. 数值:推到数值栈上。
  2. 操作符:推入操作符栈上。
  3. 左括号:忽略。
  4. 右括号:出栈操作符和两个数值,并将运算结果入栈。

也就是当算法遇到一个在括号内被两个值包围的操作符时,它会先计算这两个值结果并将结果留在值栈上。

实际还可以扩展为更复杂,如更多的操作,优先顺序,结合性。

基本排序

对任何类型的数据进行排序,总是一个二元关系,需满足:

  • 对称性:如果v≤w和w≤v,那么v = w.
  • 传递性:如果v≤w和w≤x,那么v≤x。
  • 整体:v≤w或w≤v或两者都有

无传递性不行,如石头剪刀布。

无整体性不行。PU课程先决条件。

回调

因为我们的api要对任何类型的数据进行排序,也可能是自定义的类型,那么sort()如何知道不同类型的数据间的不同比较规则?

回调:引用可执行代码。客户端传递数组对象给sort()函数,sort()函数根据被调用对象的compareTo()方法进行比较。

不同语言实现回调的方式:

  • Java:interfaces
  • C:函数指针
  • C++:class-type functors
  • C#:delegates
  • Python, Perl, ML, Javascript:first-class functions

如,对String类型的对象排序

String内部实现compareTo()方法,返回-1表示小于,1表示大于,0表示等于。

实现Comparable<>接口

sort()实现中,比较对象大小,调用对象类型内部compareTo()方法

如自定义Date类型实现compareTo()方法

选择排序

归并排序

两种经典的排序算法:合并排序和快速排序

世界计算基础设施中的关键组件。对它们特性的充分科学理解使我们能够将它们发展成实际的系统分类。快速排序被评为20世纪科学和工程领域的十大算法之一。

归并排序

核心思想:将数组分成两半。递归排序的每一半。合并两部分。

归并功能代码实现

MergeSort()代码实现

递归一分为二

归并过程

性能分析

归并排序效率≤N lg N。需要一个长度为N的辅助数组

性能模型

假设N是2的幂次, 每一层合并N次,一共lg N层,共计N lg N

改进1:小数组使用插入排序

归并排序对于很小的子数组来说有太多的开销,比如函数调用与合并。所以对小的子数组使用插入排序,截止到≈10项时使用插入排序。

归并到最小数组长度为10

改进2:如果已经排序,停止合并

在合并前,如果前一半的数组已经比后一半的数组小,已经是最终的顺序,不再合并。

改进3:节省拷贝到辅助数组的时间

转换一下原数组和辅助数组的角色,不过还是需要辅助数组,可以节省时间,但不节省空间。

自顶向上归并排序

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【力扣刷题】Day32——单调栈专题

文章目录单调栈1.每日温度2.下一个更大元素 I3.下一个更大元素II4. 接雨水5.柱状图中最大的矩形单调栈 单调栈基础知识回顾&#xff1a;单调栈与单调队列_塔塔开!!!的博客-CSDN博客_单调栈 单调队列 单调栈一般模板&#xff1a; int[] stk new int[N] //Stack<Integer>…

倒排索引-字符串相似匹配(结巴分词、中文转拼音)

工作中&#xff0c;遇到有两个不同的系统&#xff0c;两个系统中有相同的功能&#xff0c;维护一个主播的名称。现在准备将两个系统的主播合并到一起。因为主播名称可能由不同的人维护的&#xff0c;他们也不知道主播的真实姓名&#xff0c;比如一条小团团&#xff0c;可能维护…

香橙派3LTS部署ROS2阿克曼开源平台

1.系统镜像下载 这里我们需要安装ROS2的humble版本&#xff0c;需要ubuntu 22.04版本的系统。 香橙派镜像下载&#xff1a;http://www.orangepi.cn/html/hardWare/computerAndMicrocontrollers/service-and-support/Orange-Pi-3-LTS.html 点击Ubuntu镜像&#xff0c;选择jamm…

【linux】进程概念详述

进程概念一、冯诺依曼系统二、操作系统2.1 OS层次图2.2 操作系统的意义2.2.1 系统调用与库函数的区别2.3 管理的理解三、进程3.1 进程的概念3.2 描述进程-PCB3.3 进程和程序3.4 PCB内容3.4.1 查看进程3.4.2 标识符3.4.3 状态3.4.4 程序计数器3.4.5 记账信息3.4.6 上下文信息❗️…

1.极限与连续-——“机器学习中的数学”

1.通过集合相等来讲解什么是映射关系 上面问的这个问题&#xff08;2N N2&#xff09;说明了什么&#xff1f; ——两个无穷集合&#xff0c;如果能找到一种对应关系&#xff08;映射关系&#xff09;&#xff0c;那么我们就可以说这两个集合是等价的。 数列的极限就是趋势 …

字符串转二叉树

一. 题目介绍 二. 题目分析 首先 题目让我们以先序遍历的方式用字符串建立一个二叉树 输入是一个字符串 输出是是以中序遍历二叉树打印 我们先来看最简单的输入 这里只要建立一个字符数组 然后等测试用例输入就好了 // 接受输入值char arr[100]{0};scanf("%s",…

网络原理 --- 传输层Ⅳ TCP协议中的延迟应答、捎带应答、面向字节流、TCP中的异常处理

文章目录网络原理传输层TCP协议7.延迟应答8.捎带应答9. 面向字节流10.TCP中的异常处理总结网络原理 介绍TCP/IP协议中每一层里面的核心内容~ 应用层传输层网络层数据链路层物理层 传输层TCP协议 7.延迟应答 提高传输效率的机制 又是基于流量控制,来引入的提高效率的机制 实…

数据在内存中的存储

目录 数据在内存中的存储&#xff1a;&#xff1a; 整型及其浮点型存储方式: 1.数据类型介绍 2.整形在内存中的存储&#xff1a;原码 反码 补码 3.大小端字节序介绍及判断 4.浮点型在内存中的存储 5.两道经典指针选择题 C语言编程训练(牛客网) 1.喝汽水问题 2.字符串逆序 3.打…

Python编程运算符 ——算数运算符

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.运算符 1.在Python运算符中分为 2.算数运算符 3.比较重要的运算符 4…

网络原理——No.1 传输层_TCP的确认应答机制与超时重传

JavaEE传送门JavaEE JavaEE——网络原理_应用层 网络原理——传输层_UDP 目录传输层TCPTCP 的基本特性确认应答机制超时重传传输层 端到端之间的传输, 重点关注的是起点和终点 核心的协议有两个: UDP: 无连接, 不可靠传输,面向数据报, 全双工 TCP: 有链接, 可靠传输, 面向字…

黑猫带你学UFS协议第11篇:什么是逻辑单元(LU)与逻辑块(Sector)

本文依据UFS3.1 JEDEC协议及个人工作经验整理而成,如有错误请留言。 文章为个人辛苦整理,付费内容,已加入原创维权,禁止私自转载。 文章所在专栏:《黑猫带你学:UFS协议详解》 1 LU简介 我们对与UFS、emmc一类存储芯片,最重要的功能是什么?无非就是存数据和取出数据,也…

神经网络的输入稀疏矩阵,神经网络中的矩阵运算

1、BP神经网络模型各个参数的选取问题 样本变量不需要那么多&#xff0c;因为神经网络的信息存储能力有限&#xff0c;过多的样本会造成一些有用的信息被丢弃。如果样本数量过多&#xff0c;应增加隐层节点数或隐层数目&#xff0c;才能增强学习能力。 一、隐层数 一般认为&am…

牛客前端刷题(九)—— 打包篇

还在担心面试不通过吗&#xff1f;给大家推荐一个超级好用的刷面试题神器&#xff1a;牛客网&#xff0c;里面涵盖了各个领域的面试题库&#xff0c;还有大厂真题哦&#xff01; 赶快悄悄的努力起来吧&#xff0c;不苒在这里衷心祝愿各位大佬都能顺利通过面试。 面试专栏分享&a…

greenplum 源码解析 FTS辅助进程--ReadMe

简介 在greenplum数据库中master节点有一个专属进程Fault Tolerance Service (FTS: 容错服务)&#xff0c;其主要功能是检测所有segment节点的健康信息&#xff0c;如果其检测到segment节点的primary出现异常[硬件故障/宕机]&#xff0c;会在第一时间将其对应的mirror提升为新的…

MySql(50)MySQL日志

文章目录MySQL支持的日志日志类型日志的弊端慢查询日志(slow query log)通用查询日志查看当前状态启动日志永久启动临时启动查看日志删除\刷新日志错误日志(error log)删除\刷新日志二进制日志(bin log)查看默认情况日志参数设置查看日志使用日志恢复数据删除二进制日志PURGE M…

vue3 响应式对象的 api ,你全用过了吗?

文章目录Ⅰ. ref、reactive ( 递归监听 )Ⅱ. isRef、isReactive ( 判断 )Ⅲ. toRef 和 toRefs ( 解构 )Ⅳ. toRaw 、 markRaw ( 解除代理)Ⅴ. unref ( 拷贝 )Ⅵ. shallowRef 、shallowReactive&#xff08; 非递归监听 &#xff09;Ⅶ. triggerRef &#xff08;强制更新&#x…

红黑树原理及旋转

红黑树&#xff0c;本质上来说就是一棵二叉查找树 但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡 保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n) 但它是如何保证一棵n个结点的红黑树的高度始终保持在h logn的呢&#xff1f;这就引出了红黑…

相似度_对抗学习:SimCSE: Simple Contrastive Learning of Sentence Embeddings

SimCSE: Simple Contrastive Learning of Sentence Embeddings 这篇论文&#xff0c;我觉得有意思。在创造对抗学习的正负例时&#xff0c;正例直接使用它本身。将同一个句子传递给预先训练好的编码器两次&#xff1a;通过应用两次dropout&#xff0c;我们可以得到两个不同的嵌…

云计算基础:云计算越来越广泛,我们应该如何去学习云计算

随着时代的发展&#xff0c;云计算越来越普及&#xff0c;越大众化&#xff0c;使用的人越来越多&#xff0c;我们应该如何去学习这门技术呢?这篇文章我们就来介绍如何学习我们的云计算。 学前介绍&#xff1a; 学前介绍 学习资料&#xff1a;HedEX Lite、产品文档、笔记、P…

非科班程序员被裁员后反而涨薪了200%,这两个月他都经历了哪些?

今年年初开始&#xff0c;裁员潮一浪接着一浪翻滚而来&#xff0c;让互联网人胆颤心惊&#xff0c;时刻担心下一波裁员是否就要降临到自己身上。 小帅&#xff08;化名&#xff09;是一个原本月薪8k&#xff0c;在小外包公司做政府项目的一名普通员工&#xff0c;前不久就被裁员…