- 博客(551)
- 资源 (716)
- 收藏
- 关注
原创 12.5 小结
12.5 小结分治是一种常见的算法设计策略,包括分(划分)和治(合并)两个阶段,通常基于递归实现。 判断是否是分治算法问题的依据包括:问题能否分解、子问题是否独立、子问题能否合并。 归并排序是分治策略的典型应用,其递归地将数组划分为等长的两个子数组,直到只剩一个元素时开始逐层合并,从而完成排序。 引入分治策略往往可以提升算法效率。一方面,分治策略减少了操作数量;另一方面,分治后有利于系统的并行优化。 分治既可以解决许多算法问题,也广泛应用于数据结构与算法设计中,处处可见其身影。 相较于暴力
2024-06-09 06:30:00 160 1
原创 12.4 汉诺塔问题
在古印度的一个寺庙里,僧侣们有三根高大的钻石柱子,以及 64 个大小不一的金圆盘。至此,我们可总结出图 12-14 所示的解决汉诺塔问题的分治策略:将原问题 𝑓(𝑛) 划分为两个子问题 𝑓(𝑛−1) 和一个子问题 𝑓(1) ,并按照以下顺序解决这三个子问题。如图 12-15 所示,汉诺塔问题形成一棵高度为 𝑛 的递归树,每个节点代表一个子问题,对应一个开启的。如图 12-11 所示,对于问题 𝑓(1) ,即当只有一个圆盘时,我们将它直接从。如图 12-12 所示,对于问题 𝑓(2) ,即当有两个圆盘时,
2024-06-09 05:00:00 602
原创 12.3 构建二叉树问题
在最差情况下,即二叉树退化为链表时,递归深度达到 𝑛 ,使用 𝑂(𝑛) 的栈帧空间。图 12-8 展示了构建二叉树的递归过程,各个节点是在向下“递”的过程中建立的,而各条边(引用)是在向上“归”的过程中建立的。请注意,右子树根节点索引中的 (𝑚−𝑙) 的含义是“左子树的节点数量”,建议结合图 12-7 理解。,请从中构建二叉树,返回二叉树的根节点。假设二叉树中没有值重复的节点(如图 12-5 所示)。以上图数据为例,我们可以通过图 12-6 所示的步骤得到划分结果。的划分结果如图 12-9 所示。
2024-06-08 06:00:00 828
原创 12.2 分治搜索策略
在之前的章节中,二分查找是基于递推(迭代)实现的。现在我们基于分治(递归)来实现它。从分治角度,我们将搜索区间 [𝑖,𝑗] 对应的子问题记为 𝑓(𝑖,𝑗)。分治能够提升搜索效率,本质上是因为暴力搜索每轮只能排除一个选项,以原问题 𝑓(0,𝑛−1) 为起始点,通过以下步骤进行二分查找。图 12-4 展示了在数组中二分查找元素 6 的分治过程。,其中所有元素都是唯一的,请查找元素。图 12-4 二分查找的分治过程。我们已经学过,搜索算法分为两大类。二分查找的分治策略如下所示。,例如二分查找和树。
2024-06-08 05:00:00 348
原创 12.1 分治算法
换句话说,将大问题分解为多个子问题、解决子问题、将子问题的解合并为原问题的解,这几步的效率为什么比直接解决原问题的效率更高?比如在图 12-3 所示的“桶排序”中,我们将海量的数据平均分配到各个桶中,则可将所有桶的排序任务分散到各个计算单元,完成后再合并结果。并行优化在多核或多处理器的环境中尤其有效,因为系统可以同时处理多个子问题,更加充分地利用计算资源,从而显著减少总体的运行时间。请注意,划分后的时间复杂度仍然是平方阶 𝑂(𝑛2) ,只是复杂度中的常数项变小了。我们知道,分治生成的子问题是相互独立的,
2024-06-07 05:45:00 1613
原创 11.11 小结
假设最差情况,一直为一半长度,那么最终的递归深度就是 log𝑛。在该方法下,输入元素全部相等的数组,仅一轮哨兵划分即可完成排序。回顾原始的快速排序,我们有可能会连续地递归长度较大的数组,最差情况下为 𝑛、𝑛−1、…、2、1 ,递归深度为 𝑛。不行,当我们以最左端元素为基准数时,必须先“从右往左查找”再“从左往右查找”。也就是说,此时最后一步交换操作会把一个比基准数更大的元素交换至数组最左端,导致哨兵划分失败。可以发现,学生 D 和 C 的位置发生了交换,姓名的有序性被破坏了,而这是我们不希望看到的。
2024-06-06 05:30:00 795
原创 11.10 基数排序
假设我们需要对 𝑛=106 个学号进行排序,而学号是一个 8 位数字,这意味着数据范围 𝑚=108 非常大,使用计数排序需要分配大量内存空间,而基数排序可以避免这种情况。举例来说,如果第一轮排序结果 𝑎𝑏 ,那么第二轮的结果将取代第一轮的结果。在此基础上,基数排序利用数字各位之间的递进关系,依次对每一位进行排序,从而得到最终的排序结果。以学号数据为例,假设数字的最低位是第 1 位,最高位是第 8 位,基数排序的流程如图 11-18 所示。为什么从最低位开始排序?
2024-06-06 05:00:00 1208
原创 11.8 桶排序
例如,我们想要将淘宝上的所有商品按价格范围平均分配到 10 个桶中,但商品价格分布不均,低于 100 元的非常多,高于 1000 元的非常少。此时,可以将数据分成 1000 个桶,然后分别对每个桶进行排序,最后将结果合并。它通过设置一些具有大小顺序的桶,每个桶对应一个数据范围,将数据平均分配到各个桶中;如图 11-15 所示,我们假设商品价格服从正态分布,这样就可以合理地设定价格区间,从而将商品平均分配到各个桶中。为实现平均分配,我们可以先设定一条大致的分界线,将数据粗略地分到 3 个桶中。
2024-06-05 05:00:00 884
原创 11.7 堆排序
以上方法虽然可行,但需要借助一个额外数组来保存弹出的元素,比较浪费空间。在实际中,我们通常使用一种更加优雅的实现方式。我们可以利用已经学过的“建堆操作”和“元素出堆操作”实现堆排序。值得注意的是,由于堆的长度会随着提取最大元素而减小,因此我们需要给。函数添加一个长度参数 𝑛 ,用于指定堆的当前有效长度。设数组的长度为 𝑛 ,堆排序的流程如图 11-12 所示。在代码实现中,我们使用了与“堆”章节相同的从顶至底堆化。阅读本节前,请确保已学完“堆“章节。步,只是多了一个弹出元素的步骤。
2024-06-04 05:30:00 360
原创 11.6 归并排序
合并阶段”从底至顶地将左子数组和右子数组合并为一个有序数组。需要注意的是,从长度为 1 的子数组开始合并,合并阶段中的每个子数组都是有序的。是一种基于分治策略的排序算法,包含图 11-10 所示的“划分”和“合并”阶段。如图 11-11 所示,“划分阶段”从顶至底递归地将数组从中点切分为两个子数组。具体实现细节比较复杂,有兴趣的读者可以查阅相关资料进行学习。观察发现,归并排序与二叉树后序遍历的递归顺序是一致的。对于链表,归并排序相较于其他排序算法具有显著优势,归并排序的实现如以下代码所示。
2024-06-04 05:00:00 834
原创 11.5 快速排序
以完全有序的输入数组为例,设递归中的子数组长度为 𝑚 ,每轮哨兵划分操作都将产生长度为 0 的左子数组和长度为 𝑚−1 的右子数组,这意味着每一层递归调用减少的问题规模非常小(只减少一个元素),递归树的高度会达到 𝑛−1 ,此时需要占用 𝑂(𝑛) 大小的栈帧空间。快速排序的核心操作是“哨兵划分”,其目标是:选择数组中的某个元素作为“基准数”,将所有小于基准数的元素移到其左侧,而大于基准数的元素移到其右侧。尽管快速排序的平均时间复杂度与“归并排序”和“堆排序”相同,但通常快速排序的效率更高,主要有以下原因。
2024-06-03 05:30:00 875
原创 11.4 插入排序
而在数据量较小时,𝑛2 和 𝑛log𝑛 的数值比较接近,复杂度不占主导地位,每轮中的单元操作数量起到决定性作用。实际上,许多编程语言(例如 Java)的内置排序函数采用了插入排序,大致思路为:对于长数组,采用基于分治策略的排序算法,例如快速排序;插入排序的时间复杂度为 𝑂(𝑛2) ,而我们即将学习的快速排序的时间复杂度为 𝑂(𝑛log𝑛)。尽管插入排序的时间复杂度更高,具体来说,我们在未排序区间选择一个基准元素,将该元素与其左侧已排序区间的元素逐一比较大小,并将该元素插入到正确的位置。
2024-06-03 05:00:00 762
原创 11.3 冒泡排序
如图 11-4 所示,冒泡过程可以利用元素交换操作来模拟:从数组最左端开始向右遍历,依次比较相邻元素大小,如果“左元素 > 右元素”就交换二者。遍历完成后,最大的元素会被移动到数组的最右端。经过优化,冒泡排序的最差时间复杂度和平均时间复杂度仍为 𝑂(𝑛2);但当输入数组完全有序时,可达到最佳时间复杂度 𝑂(𝑛)。我们发现,如果某轮“冒泡”中没有执行任何交换操作,说明数组已经完成排序,可直接返回结果。设数组的长度为 𝑛 ,冒泡排序的步骤如图 11-5 所示。来监测这种情况,一旦出现就立即返回。
2024-06-02 05:30:00 414
原创 11.2 选择排序
的工作原理非常简单:开启一个循环,每轮从未排序区间选择最小的元素,将其放到已排序区间的末尾。设数组的长度为 𝑛 ,选择排序的算法流程如图 11-2 所示。选择排序(selection sort)
2024-06-02 05:00:00 433
原创 11.1 排序算法
我们期望排序算法的时间复杂度尽量低,且总体操作数量较少(时间复杂度中的常数项变小)。通过在原数组上直接操作实现排序,无须借助额外的辅助数组,从而节省内存。通常情况下,原地排序的数据搬运操作较少,运行速度也更快。因此,在选择排序算法时,需要根据具体的数据特点和问题需求来决定。依赖比较运算符()来判断元素的相对顺序,从而排序整个数组,理论最优时间复杂度为 𝑂(𝑛log𝑛)。的时间复杂度会受输入数据的影响,即最佳时间复杂度、最差时间复杂度、平均时间复杂度并不完全相等。
2024-06-01 05:30:00 377
原创 第 11 章 排序
排序犹如一把将混乱变为秩序的魔法钥匙,使我们能以更高效的方式理解与处理数据。无论是简单的升序,还是复杂的分类排列,排序都向我们展示了数据的和谐美感。
2024-06-01 05:00:00 212
原创 3、【AutoSar_UDS服务】0x14服务_清除DTC
UDS 0x14服务用于清除存储的故障诊断信息,清除的故障诊断信息可以是某一个特定的故障码,也可以是某个类别的故障诊断码,也可以是所有的故障诊断码。这里所说的某个类别的DTC,其实是DTC Group(比如动力总成,车身,底盘等),DTC Group的区间范围一般由主机厂的需求确定并在Dem模块进行实现。DTC 状态信息;DTC 相关数据(包括冻结帧数据和扩展数据);DTC 其他数据(时间,发生次数等);该响应仅有:SID+0x40 = 0x54。
2024-05-31 05:30:00 204
原创 2、【AutoSar_UDS服务】0x11服务_ECU复位
UDS 0x11服务被client用来请求ECU复位,ECU复位有多种方式,由0x11服务的子功能参数resetType来决定;0x11服务的肯定响应会在执行复位动作之前发出;ECU在复位成功之后,将直接进入默认会话。从ECU复位请求的积极响应消息之后的时间,直到复位成功完成,ISO 14229中没有定义ECU的行为。建议在此期间ECU不接受任何请求消息,也不发送任何响应消息。该服务使用的sub-function如下,并不包含bit7肯定响应抑制位。
2024-05-31 05:00:00 110
原创 1、【AutoSar_UDS服务】0x10服务_诊断会话控制
UDS 0x10服务主要有以下功能:作为用来切换Server(即ECU)不同诊断会话的一种服务;不同的诊断会话则规定了Server在相应session可以开启的服务权限;在不同的诊断会话则应使用对应的数据链路层的时间参数( P2ServerMax, P2*ServerMax);会话状态切换结果会通过Rte,以便恢复通信;按照14229-1标准所述,如下图所示:由上图我们提到10服务会话类型,该会话类型(子服务)可以主要可以分为六种:会话类型取值(hex)解释默认会话0x01。
2024-05-30 05:30:00 112
原创 汽车电子软件设计-刷新介绍
汽车电子控制器给汽车的发展带来了无限的可能,也即是软件定义汽车功能。汽车电子控制器里的软件越来越复杂,动不动就是几十万行的代码,不免会出现一些软件bug,当出现软件bug时,更新控制器里的软件就成为必需,对控制器开发过程中,刷新功能必不可少。此次就讲一下电子控制器里的刷新功能。根据不同阶段,刷新的种类也不同:1)初次刷新;2)Debug刷新;3)基于UDS刷新;4)OTA刷新;本次文章主要讲述前二种,后面几点再开专题进行讲述。
2024-05-30 05:00:00 116
原创 AURIX TC3xx单片机介绍-启动过程介绍3
Reset类型的识别是用来判断上次的复位是Application Reset还是System Reset还是CPU0 Reset。基于复位的原因,启动软件会运行不同的分支逻辑。复位原因可以通过RSTSTAT和RSTCON寄存器来进行判断。SW,STMx,SMU,ESRx,CB3复位源只能产生Application Reset,其他所有的Reset是可以产生System Reset的,但是需要进行软件配置。
2024-05-29 05:30:00 247
原创 AURIX TC3xx单片机介绍-启动过程介绍2
,初始化过程是CPU0完成的。用户可以根据不同的复位事件来选择不同的执行路径。用户启动程序是在Boot Firmware之后运行的程序(
2024-05-29 05:00:00 433
原创 AURIX TC3xx单片机介绍-启动过程介绍1
在AURIX 2代,总共有4个Boot Mode Header(BMHDx, x=0-3),他们都是定义在UCB里的,为了防止数据的损坏,每个Boot Mode Header都有其一个备份,即有原始的Boot Mode Header,,UCB_BMHDx_ORIG,也有其备份的UCB_BMHDx_COPY,为了保证正常启动,在UCB里至少有一个存在。对于第二个问题,从Security的角度来说,是不建议用HWCFG的方式来决定启动模式的,防止被暴力刷新;如果BMHD无效,可能会去检查其他的启动模式:。
2024-05-28 06:00:00 420
原创 【收录 Hello 算法】10.6 小结
10.6 小结二分查找依赖数据的有序性,通过循环逐步缩减一半搜索区间来进行查找。它要求输入数据有序,且仅适用于数组或基于数组实现的数据结构。 暴力搜索通过遍历数据结构来定位数据。线性搜索适用于数组和链表,广度优先搜索和深度优先搜索适用于图和树。此类算法通用性好,无须对数据进行预处理,但时间复杂度𝑂(𝑛)较高。 哈希查找、树查找和二分查找属于高效搜索方法,可在特定数据结构中快速定位目标元素。此类算法效率高,时间复杂度可达𝑂(log𝑛)甚至𝑂(1),但通常需要借助额外数据结构。 实际
2024-05-28 05:00:00 206
原创 【收录 Hello 算法】10.5 重识搜索算法
给定大小为 𝑛 的一组数据,我们可以使用线性搜索、二分查找、树查找、哈希查找等多种方法从中搜索目标元素。不难发现,这些知识点都已在前面的章节中介绍过,因此搜索算法对于我们来说并不陌生。在本节中,我们将从更加系统的视角切入,重新审视搜索算法。例如,二分查找需要预先对数组进行排序,哈希查找和树查找都需要借助额外的数据结构,维护这些数据结构也需要额外的时间和空间开销。自适应搜索利用数据的特有属性(例如有序性)来优化搜索过程,从而更高效地定位目标元素。,其中 𝑛 为元素数量,因此在数据量较大的情况下性能较差。
2024-05-27 05:30:00 964
原创 【收录 Hello 算法】10.4 哈希优化策略
如图 10-9 所示,我们开启一个两层循环,在每轮中判断两个整数的和是否为。考虑借助一个哈希表,键值对分别为数组元素和元素索引。循环遍历数组,每轮执行图 10-10 所示的步骤。此方法的时间复杂度为 𝑂(𝑛2) ,空间复杂度为 𝑂(1) ,在大数据量下非常耗时。此方法通过哈希查找将时间复杂度从 𝑂(𝑛2) 降至 𝑂(𝑛) ,大幅提升运行效率。由于需要维护一个额外的哈希表,因此空间复杂度为 𝑂(𝑛)。的两个元素,并返回它们的数组索引。返回任意一个解即可。,请在数组中搜索“和”为。,若是,则返回它们的索引。
2024-05-27 05:00:00 485
原创 【收录 Hello 算法】10.3 二分查找边界
因此,如图 10-8 所示,我们可以构造一个数组中不存在的元素,用于查找左右边界。考虑通过查找插入点的函数实现查找左边界。代码在此省略,有兴趣的读者可以自行实现。当遇到以上两种情况时,直接返回 −1 即可。如图 10-7 所示,查找完成后,指针 𝑖 指向最左一个。回忆二分查找插入点的方法,搜索完成后 𝑖 指向最左一个。,其中可能包含重复元素。若数组中不包含该元素,则返回 −1。图 10-7 将查找右边界转化为查找左边界。最直接的方式是修改代码,替换在。代码在此省略,以下两点值得注意。
2024-05-26 06:30:00 1767
原创 【收录 Hello 算法】10.2 二分查找插入点
在不断的循环二分中,指针 𝑖 和 𝑗 都逐渐逼近预先设定的目标。如图 10-6 所示,整体流程保持不变,每轮先计算中点索引 𝑚 ,再判断。总的来看,二分查找无非就是给指针 𝑖 和 𝑗 分别设定搜索目标,目标可能是一个具体的元素(例如。二分查找不仅可用于搜索目标元素,还可用于解决许多变种问题,比如搜索目标元素的插入位置。在上一题的基础上,规定数组可能包含重复元素,其余不变。图 10-6 二分查找重复元素的插入点的步骤。插入到相等元素的左边,这意味着新插入的。时,插入点的索引是否是该元素的索引?
2024-05-26 05:00:00 979
原创 【收录 Hello 算法】10.1 二分查找
如图 10-2 所示,我们先初始化指针 𝑖=0 和 𝑗=𝑛−1 ,分别指向数组首元素和尾元素,代表搜索区间 [0,𝑛−1]。除了上述双闭区间外,常见的区间表示还有“左闭右开”区间,定义为 [0,𝑛) ,即左边界包含自身,右边界不包含自身。在该表示下,区间 [𝑖,𝑗) 在 𝑖=𝑗 时为空。由于“双闭区间”表示中的左右边界都被定义为闭区间,因此通过指针 𝑖 和指针 𝑗 缩小区间的操作也是对称的。如图 10-3 所示,在两种区间表示下,二分查找算法的初始化、循环条件和缩小区间操作皆有所不同。
2024-05-25 06:00:00 1608
原创 【收录 Hello 算法】第 10 章 搜索
搜索是一场未知的冒险,我们或许需要走遍神秘空间的每个角落,又或许可以快速锁定目标。在这场寻觅之旅中,每一次探索都可能得到一个未曾料想的答案。
2024-05-25 05:00:00 310
原创 【收录 Hello 算法】9.4 小结
维基百科上不同语言版本的定义不一致:英文版是“路径是一个边序列”,而中文版是“路径是一个顶点序列”。但在实际应用中,可能需要按照指定规则来排序,比如按照顶点添加的次序,或者按照顶点值大小的顺序等,这样有助于快速查找“带有某种极值”的顶点。在本文中,路径被视为一个边序列,而不是一个顶点序列。这是因为两个顶点之间可能存在多条边连接,此时每条边都对应一条路径。在非连通图中,从某个顶点出发,至少有一个顶点无法到达。:在邻接表中,“与该顶点相连的所有顶点”的顶点顺序是否有要求?:路径的定义是顶点序列还是边序列?
2024-05-24 06:00:00 415
原创 【收录 Hello 算法】9.3 图的遍历
在遍历邻接顶点的过程中,由于是无向图,因此所有边都会被访问 2 次,使用 𝑂(2|𝐸|) 时间;如图 9-11 所示,从左上角顶点出发,访问当前顶点的某个邻接顶点,直到走到尽头时返回,再继续走到尽头并返回,以此类推,直至所有顶点遍历完成。如图 9-9 所示,从左上角顶点出发,首先遍历该顶点的所有邻接顶点,然后遍历下一个顶点的所有邻接顶点,以此类推,直至所有顶点访问完毕。顶点数量最多为 |𝑉| ,递归深度最大为 |𝑉| ,因此使用 𝑂(|𝑉|) 空间。中的顶点数量最多为 |𝑉| ,使用 𝑂(|𝑉|) 空间。
2024-05-24 05:00:00 1360
原创 【收录 Hello 算法】9.2 图的基础操作
综合来看,邻接矩阵体现了“以空间换时间”的原则,而邻接表体现了“以时间换空间”的原则。类来表示顶点,这样做的原因是:如果与邻接矩阵一样,用列表索引来区分不同顶点,那么假设要删除索引为 𝑖 的顶点,则需遍历整个邻接表,将所有大于 𝑖 的索引全部减 1 ,效率很低。图的基础操作可分为对“边”的操作和对“顶点”的操作。设图中共有 𝑛 个顶点和 𝑚 条边,表 9-2 对比了邻接矩阵和邻接表的时间效率和空间效率。设无向图的顶点总数为 𝑛、边总数为 𝑚 ,则可根据图 9-8 所示的方法实现各种操作。
2024-05-23 06:00:00 675
原创 【收录 Hello 算法】9.1 图
如图 9-5 所示,设邻接矩阵为 𝑀、顶点列表为 𝑉 ,那么矩阵元素 𝑀[𝑖,𝑗]=1 表示顶点 𝑉[𝑖] 到顶点 𝑉[𝑗] 之间存在边,反之 𝑀[𝑖,𝑗]=0 表示两顶点之间无边。第 𝑖 个链表对应顶点 𝑖 ,其中存储了该顶点的所有邻接顶点(与该顶点相连的顶点)。使用邻接矩阵表示图时,我们可以直接访问矩阵元素以获取边,因此增删查改操作的效率很高,时间复杂度均为 𝑂(1)。使用一个 𝑛×𝑛 大小的矩阵来表示图,每一行(列)代表一个顶点,矩阵元素代表边,用 1 或 0 表示两个顶点之间是否存在边。
2024-05-23 05:30:00 1558
原创 【收录 Hello 算法】第 9 章 图
在生命旅途中,我们就像是一个个节点,被无数看不见的边相连。每一次的相识与相离,都在这张巨大的网络图中留下独特的印记。
2024-05-22 06:00:00 287
原创 【收录 Hello 算法】8.4 小结
两者不是同一个概念,只是碰巧都叫“堆”。计算机系统内存中的堆是动态内存分配的一部分,程序在运行时可以使用它来存储数据。程序可以请求一定量的堆内存,用于存储如对象和数组等复杂结构。当这些数据不再需要时,程序需要释放这些内存,以防止内存泄漏。相较于栈内存,堆内存的管理和使用需要更谨慎,使用不当可能会导致内存泄漏和野指针等问题。:数据结构的“堆”与内存管理的“堆”是同一个概念吗?
2024-05-22 05:30:00 282
优越者 USB2.0转RS232串口线 Y105驱动.rar、PL2303-Prolific-DriverInstaller驱动
2024-05-22
Specification of Basic Software Mode Manager
2024-01-01
Specification of Diagnostic Event Manager
2023-12-30
Specification of ECU State Manager
2023-12-30
CDD-MC33771系列CDD复杂驱动; BMS常用芯片
2023-10-15
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人