粉丝134获赞1153

冒泡排序是最简单最基础的排序算法,通过解决排序的问题,可以快速体验一下算法设计的灵魂所在。假如有一组数据里面有五个数字,将这组数据进行从大到小的排列,应该怎么做呢? 依次选择两个连接的元素进行对比,将最小的移动到左边,第一对七和三,三比七小,将三移动到七的左边, 第二对七和九,七比九小不需要移动。第三对八和九,自然是将八移动到九的左边,以此类推。第四对九和一,需要将一移动到九的左边。上数的步骤进行了一次相邻数字之间的对比,数字有原来的七到一的组合, 进行了三到九这样一个新的组合。在这个过程中,我们可以看到相对比较大的数字都进行了向左的移动,最大的数字九甚至移动到了最右边,这个过程和水中泡泡上升的方式很相似,所以这也是这种 排序叫做冒泡排序的原因。上述过程中的速度对比,从左边开始到最右边为止,记做一次运算,重复上述的步骤,进行第二次运算,我们可以得到这样一个结果,以此类推。第三次, 第四次。到这一步我们可以看到,此时数字组合已经完成了从小到大的排序,无需再进行移动我们的排序任务至此完成这个完整的过程。 冒泡排序的过程我们可以看到,完成这个排序做了四次循环,每次循环中进行了四次数字之间的对比,这样就一共进行了十六次的对比。有没有更偷懒的办法,使得对比的次数变得更少,也就是速度更快的完成排序呢。好了,这期视频就到这里,我们下期视频继续解答。


嘿,来看看这个。相信你们很多人应该都熟悉这类排序算法,就像我现在所展示的,这就是冒泡排序。一种研究较为充分的简单排序算法。你想了解的所有与之相关信息在互联网上都能轻松找到,但有一个问题除外,它形成的这条曲线究竟是什么? 这正是我将在本视频中解答的问题。排序算法是一组精确的计算机可遵循的分布指令,用于对列表进行排序。排序是计算机的常见任务,因此学术界在设计高效排序算法方面开展了大量研究。 但在本视频中,我们不关注算法效率,也不会对任何真实数据进行排序,而是对垂直条从短到长进行排序。这是一种常用的格式化方式,能让我们清晰观察到算法运行时的每一步操作。 只需使用更长的列表并加快算法运行速度,你就能得到经典的排序算法。格式化视频。目前排序列表的方法不止一种, 人们设计出了各种各样的排序算法,他们的工作原理截然不同,我们可以通过可视化呈现来验证这一点,观察它们运行时形成的不同形状即可。 先说明一下,我为这些算法动画设置了相同的时长,这样大家就能更直观的对比形状。但在实际场景中,快速排序和规定排序的运行速度远超另外三种,而冒泡排序几乎是效率最低的, 不过它正是本视频的核心主题,因为其可视化形状最令人困惑。或许你得先相信我的判断,但如果你了解其他算法的工作原理,它们的可视化形状会一目了然。 相比之下,冒泡排序的曲线却让人摸不着头脑,完全值得专门做一期视频来解析。显然,有人已经这么做了。接下来,我们将以直观的方式探索答案,不会过度追求严谨性。 仔细想想,我们要寻找的是大量随机锯齿状图表的整体形状,这些图表代表着任意长度的列表。 这个问题即便要给出严密定义都十分复杂,若采用过于严谨的表述,只会让视频变得融长难懂。因此,我们将采用相对通俗的思考方式,并做出一些假设。首先,我们假设这些图表确实能形成某种形状,且该形状可解读为连续函数。 基于这一前提,我们就能精确推导出该形状的数学表达式。另外,需要说明的是,我们仅针对均匀分布的数据列表进行分析,即排序后呈现为三角形或近似三角形的列表。同时,这些列表是完全随机打乱的。 当然,存在一些特殊的打乱情况。这类情况不会形成我们关注的曲线,但由于其发生概率极低,我们将忽略不计。 好了,现在来详细了解冒泡排序的工作原理。他通常以代码形式实现,大致如下所示。但幸运的是,该算法足够简单,无需编程基础也能理解,所以我不必额外讲解编程知识。 算法步骤如下,从左到右,便利列表依次比较相邻的两个元素。若元素顺序颠倒,即左侧元素大于右侧元素,则交换二者位置,否则直接跳过。便利完整个列表后,重复上述过程,直至列表完全有序。 如果刚才的讲解你听明白了,那太好了,如果没有一个简单的例子就能帮你理解。 这里有一个包含十个元素的列表,我们从列表左侧开始比较前两个元素。在这个例子中,这两个元素顺序颠倒,因此我们交换它们的位置,接着向右移动一位,比较下一组相邻元素。此次二者顺序正确,我们直接跳过,继续向右移动。 这一次元素再次颠倒顺序,我们交换位置后继续右移。接下来两组元素同样需要交换,之后的元素顺序正确,我们不予处理。 随后又遇到两组颠倒顺序的元素,交换后继续最后一组元素顺序正确,无需操作。此时我们已便利完整个列表,接下来重新开始。便利持续交换顺序颠倒的相邻元素。反复重复这一过程,最终就能将整个列表排序完成。 这就是冒泡排序的完整流程。目前存在该算法的优化版本,但在讨论格式化形状时,这些优化无关紧要。 因此我们将沿用基础版本进行分析。为了方便后续表述,我们将对列表的每一次完整便利称为一次迭代。从迭代的角度分析十分有用,因为每次迭代对列表的影响具有简单且可预测的规律。 让我们具体看看。这是一个刚打乱的列表,我们重点关注最大的元素。开始第一次迭代时,这个最大元素在被比较到之前不会移动。由于它比所有其他元素都大,不会与左侧元素交换位置。但当便利到它时,它会与右侧更小的元素交换位置。 同时,我们继续向右移动,再次比较它与新右侧元素的大小,显然他人更大,因此它会持续向右移动,直到到达列表末尾的正确位置。第二次迭代时,第二大的元素会重复这一过程,最终停留在倒数第二个位置。 同理,每一次后续迭代都会将下一个最大的元素冒泡到正确位置。因此,以排序元素的数量等于迭代次数。 如果你对该算法的重要性存在疑问,这一过程就是最好的证明。对于包含 n 个元素的列表,经过 n 减一次迭代后,除最小元素外,所有元素都会处于正确位置,而最小元素自然也只能在剩余的唯一位置上,因此列表完全有序。 除了验证算法有效性,我们还发现它将格式化图表分为两个不同部分,左侧是未排序部分,这正是我们要寻找的曲线。右侧是以完全排序的部分,因此呈现为完美的对角线,而非曲线。 了解了冒泡排序的工作原理后,接下来我们将思考如何用数学方式描述该图表的形状。为此,我们需要明确两个约定, 第一,图标的宽高比可任意设定为简化计算,我们将其固定为一单位宽,一单位高。第二,我们需要一个指标来衡量算法的执行进度。这里我们采用时间作为指标。 假设排序整个列表需要一单位时间,且每次迭代耗时相同。用字母 t 表示时间, t 等于临时列表完全未排序, t 等于一时完全有序。 由于每次迭代耗时相同,图表中以排序部分的宽度会随 t 从零到一的增长,而稳部从零增加到一,因此以排序部分的宽度等于 t 的 值。 基于此,我们可以将图表形状定义为一个二元函数, f x t。 对 于任意给定的 t, f x, t 与 x 的 关系曲线即为该时刻的图表形状。目前我们尚未清楚曲线具体形式,用波浪线表示, 但我们已知右侧以排序部分的曲线是对角线。 y 等于 x, 且该部分对应 x 大 于一减 t 的 区域。因此可先写出分段函数的一部分,当 x 大 于一减 t 时, f x, t 等于 x。 对 于 x 小 于或等于一减 t 的 区域,我们仍需进一步推导函数表达式。 另外,我们之前假设函数是连续的,即对于任意固定的 t, f, x, t。 关于 x 连续不存在瞬时跳跃,这一点后续会发挥重要作用。 首先,我们需要更深入的分析图表特征。一个元素可以在单次迭代中从列表左侧一直移动到右侧,但反向移动却受到限制。元素每次迭代最多只能向左移动一个位置,因为算法仅从左到右变里不会主动向左移动元素。 进一步推导可知列表左侧的元素移动与右侧元素无关。假设我们有一个列表仅已知前十个元素,其余元素隐藏在盒子中。当执行迭代时,除最后一个已知元素外,已知的前九个元素的移动方式是完全确定的,与隐藏元素无关。 每次迭代后,已知部分的长度会缓慢缩减,但缩减规律固定。这一特征的重要性在于, 假设有三个不同长度的列表,其前五十个元素完全相同。对三个列表执行相同次数的迭代后,由于前五十个元素的移动规律与后续元素无关,他们的出使部分仍会保持一致。 因此,三个函数在对应区域的曲线形状必须相同。尽管三次迭代对短列表的排序净度大于长列表,但当我们将它们统一缩放到一单位宽、一单位高的比例后,本质上是函数在不同梯值下的表现, 这正是关键。发现曲线不会随时间变化,仅会随 t 的 增加而水平拉升。你可能会质疑多个列表前五十个元素完全相同的概率极低。确实如此,但这只是为了直观说明原理。 需记住,我们假设列表是均匀分布且随机打乱的,而长列表的前 k 个元素与一个长度为 k 的 随机列表本质上是等价的, 因此它们的曲线形状必然相同,无需数据完全一致。回到曲线推倒部分,我们会绘制成取两个不同值的函数曲线,然后将下方 t 等于 b 的 曲线进行水平拉伸,直到它的以排序部分。宽度与上方 t 等于 a 的 曲线相同,也就是从宽度 b 拉伸到宽度 a。 水平拉伸的缩放因子是 b 分 之 a, 而水平绘图的实现方式是用 x 除以这个缩放因子,这和用 x 乘以 a 分 之 b 是 同一个意思。这样操作后,我们就能看到曲线如预期般被拉伸了。 之所以要做这个拉伸操作,是因为现在这两条曲线所代表的列表能呈现出我们之前发现的特征。 我们可以把它们看作是在相同缩放比例下绘制的,其中下方列表的元素个数是上方列表的 b 分 之 a 倍,而且它们都执行了相同次数的迭代。就像我们之前看到的,它们的初始部分会保持一致,所以函数的对应部分必须相等。 因此,在这个紫色图处显示的区域里,这两个函数是相等的。现在这个紫色部分是除了上方图表最右侧 a 对 应的区域之外的所有部分,所以这个相等关系在 x 小 于或等于一减 a 的 范围内都成立。 另外,我们别忘了,一开始设定的条件是 a 大 于或等于 b, 接下来我们可以保持 b 的 值固定,同时调整 a 的 值。 当我们这么做的时候,相当于在上方图标上随着时间变化,而下方图标则保持不变,只是进行水平拉伸。但无论怎么调整,两个图标在紫色区域始终保持一致, 这一点非常关键。我们知道了这两条曲线是相等的,但除非我们知道其中一条曲线的具体形式,否则这个结论的用处不大。而这正是我们假设函数连续的价值所在。 因为我们已经明确函数不允许出现任何瞬时跳跃,所以上方图标的弯曲部分必须在这个位置与它的对角线 y 等于 x 衔接,所以这个衔接点的 x 坐标和 y 坐标都是一减 a, 用函数表示就是 f 一 减 a, a 等于一减 a。 又因为这个点在紫色区域内,所以我们可以确定下方图标上也存在这个完全相同的点。一个点看起来可能没什么用,但这个看似不起眼的点正是我们所需要的关键。 事实上,他并不是单个孤立的点,而是一个连续的点击,每个可能的 a 值都对应着一个这样的点, 所以我们要做的就是把 a 从零连续增加到一,同时在下方图标上追踪这些点的轨迹,之后在撤销之前的拉伸操作,就能得到对应这个特定逼值的完整曲线了。现在光有图像演示还不够,我们来推导具体的数学公式。 我们先来看之前得出的两个表达式,重点关注第一个,我们考虑 x 等于一减 a 的 情况,把这个关系带入公式中。当我们将其应用到第一个条件, x 小 于或等于一减 a 时,会得到一减 a 必须小于或等于它本身,这显然是成立的, 所以我们不用纠结这个条件。至于剩下的条件我们之后再处理。现在我们已经把 x 设定为一减 a, 那 么表达式的右侧就正好是我们之前证明过的等于一减 a 的 结果,所以我们可以进行这个替换。到这一步,我们已经很接近答案了,只需要做一些代数整理。 先看 f 的 第一个参数,既然我们现在不再使用 x 这个符号,我就重新引入 x 作为这个参数的简写,这样表达式就变成了 f x b 看起来会更简洁。 接下来我们需要用 x 表示出 a, 这一步可以通过简单的代数运算实现。我们先把含 a 的 项移到一侧,分发 b 的 值,再移动含 a、 b 的 项,接着分发 a, 最后把含 x 和 b 的 项移到另一侧,这样就能得到用 x 表示的 a 的 表达式。 之后我们把这个 a 的 表达式带入之前的公式中,再把各项合并成一个分数,这样就完成了公式的推导。 这就是冒泡排序曲线的数学公式。我本来想说推导到这里就结束了,但出于严谨性,我不能忽略之前那个未处理的条件,因为它现在还是用 a 表示的。不过这并不是什么大问题, 我们只需要把刚才得到的 a 的 表达式带入这个条件中,然后把含 x 和 b 的 相 e 到一侧,在两边同时除以 b, 最后把 b 移到另一侧,并颠倒不等式的方向,这样就完成了条件的转换。现在我的心里也踏实了。这里唯一需要说明的是,我们之前用的是字母 b, 而现在应该换成表示时间的 t。 不过用什么字母并不影响表达式的本质,所以我们可以把所有 b 都替换成 t。 巧合的是,如果我们回头看看之前写下的分段函数,就会发现我们刚刚推导出来的条件正好就是之前我们不知道函数表达式的那个区间的条件,所以现在我们已经得到了完整的函数 f 的 表达式。 现在我们还有一件非常重要的事情要做,根据真实的列表来绘制这个函数,看看它是否符合实际情况,结果非常理想,完美契合好了推导部分到此结束。但最后我想补充一些关于严谨性和我们所做假设的说明。 我们假设图表形成的形状是一个连续函数,在我看来这个假设是合理的,但如果能弱化这个假设会更好。而事实上,我们也确实可以做到。如果我们放弃连续性假设,转而假设函数是单调递增的,那么曲线和对角线之间如果存在不连续性, 就意味着数据中出现了间隙,这与我们数据均匀分布的前提相矛盾。因此,函数在衔接点处必然是连续的, 后续的推导过程也就依然成立。如果想进一步放弃单调递增的假设,就需要采用其他的推理方式了。不过,限于视频篇幅,这里就不展开细说了。但即便如此,我们仍然需要假设曲线会趋近于某个固定形状。 还有一个更大的问题是,我们目前无法从严格的数学意义上证明他确实会趋近于某个形状,因为我们甚至没有对曲线收敛给出一个精确的数学定义。这个问题曾一直困扰着我,让我无法释怀,所以我花了远超预期的时间去探寻答案。 为了方便想继续深入学习的小伙伴,我特意整理了一份笔记,里面不仅有完整的证明过程, 还有更通俗易懂的核心总结,它也会作为一个专门的内容载体,分享一些不太适合用视频形式呈现的技术细节和延伸知识。好了,本视频的内容就到这里,我们下期再见,感谢观看!

好,我们从排序来开始接触算法啊,从也从排序开始来逐渐的了解跟逐渐的练习这个算法。 呃,排序有很多种,然后今天我挑了三个比较简单,浅显易懂的这个排序方法作为入门来讲,我觉得是比较合适的。然后这三个我把它称为排序三废 啊,就是比较简单,比较适合初学者呃,或者是一些小白来利用这个排序来去了解算法,去练习算法,因为他的思想也很简单,便于理解,然后代码也不多,所以拿来做入门的话是非常合适的选 择。其中我选择的是呃,一个选择排序,冒泡排序和插入排序,这三种排序其实一点也不费,他们的思想都是非常经典的, 只是说从那个现实中可能用的比较少,因为他们的性能不是很好,然后包括稳定性也不是很好,所以实际工作中可能用的比较少,但是用来作为一个算法的入门是非常合适的。 ok, 那 么首先我们先来看这个选择排序, 什么是选择排序啊?选择排序啊,这么一大串给你解释了,我们来画图讲解一下,比较适合那个画图讲解,八零七一九三六。 然后在这个数字里面我要用选择排序来给它进行一个排序。那么一开始,一开始的时候我是不是从八来开始, 那最早的话,在这一个数组里面我挨个变例走,首先来到八,来到八的时候,因为你只有这一个数字,所以那么在这个位置上他就是有序的, 因为这个八你只有一个数,你没见过别的数字,所以八没有的东西跟他比较,他就是最小的,然后现在我要从八后面,也就是这么一坨里面, 我挨个拿一个数字来跟八进行比较,然后看谁小,然后就把他俩的位置进行交换。就说首先我下一步我会去从八后面,也就是说从零开始, 我拿零来跟八进行比较,然后拿零跟八进行比较以后,嗯,会发现零比八小,所以就会变成零八七幺九三六, 然后再下一步就到七,我用七来跟零进行比较,然后发现不变,哎,还是零八七一九三六,再下一步到一一再跟零进行比较,哎,我发现一比零还是大,所以不变,这边还是零八七一九三六, 然后再下一步到九,然后再到三,再到六等等。这这些数字后面 后面所有的数字循环完以后,你发现零就是最小的,所以这一轮排序完以后就变成零零八七一,所以第一个数字我就确定下来了,他的这个零的位置就是最小的,然后我确定完了零以后,我现在是不是要开始排第二个? 我确定完零是最小的以后,我现在就要开始排第二个数字,那同样的第二个数字,我会用它这个数字后面的这个数字来跟它进行比较。八跟七进行比较,你会发现七比八小,所以这边就变成了零七零七 零七八一九三六 九三六,然后 再到用一的位置跟七比较,哎,我发现一比七小,所以就变零一八七九三六, 然后九来再跟一比较,然后再拿三根一比较,六根一比较,这些都比一大,所以他们就不会交换。那么我这一轮结束完以后,我是不是就固定下来了这两个数值,它就是最小的, 那周而复始,我然后前两位已经定了,下一步就从八开始,然后第八位置定完以后,再从七的位置开始,再从这个位置这个位置开始,如此周而复始一个,每一次我比较完以后,我就可以选择出一个最小的,然后放在当前的位置 选择排序的命名就是这么来的,我每一次都是从我后面的书里面,我都挨个跟我前一这个 i 位置进行比较,那这样的话,我就一定能选择出一个最小的放在 i 位置,从而达到整个数组的这么一个有序。 ok, 那 我们下面就来直接写吧, 排序,选择排序, 接收一个无序的数组。呃,首先还是先探讨一下边界吧,这是老规矩啊,一个成熟的, 成熟成熟的程序员都都会第一件事情一定不是写逻辑,而是写探讨边界。如果你这个数组是空的,或者说你这个数组 你一共就两个数字都不到啊,一共就一个数,那我就不用排序了,你就是有序的啊,空的,你一共就一个数字,那你不用比较了,你一定是有序的。那当你有两个 g 以上的数以后呢? 那么按照刚刚的那个算法,我是不是每一次我会先先得到一个数啊?会先进行一个标记,然后我会标记第几个位置的数,我现在要去排第几个位置的数,我让第几个位置的数来变得有序,那也就是说从头到尾我会挨个把这个数组便利一遍, 是吧?我先排第一位,再排第二位,再排第三位,再排第四位,那么我这个排第几位,我就可以用一个 i 来进行代替,是吧? 我就直接便利这个数,这个 i 就是 我当下要排第几位,然后当我在一开始我在第一位的时候,那我没有别的数给你选,所以我假设 你 i 这个时候就是最小的一个数字,那我假设你 i 位目前就是最小的一个数字,然后我会从后面的数字里面去挨个去选择数字,跟我当前 i 这个位置我来比较,到底谁大谁小。所以我要重新定义一个 勾啊,我就勾,我就等于 i 加一,然后勾他也有边界,不能小于,不能大于这个整个数组的长度,然后勾加加, 这样的话我就是相当于说我把 i 后面位置的每一个数字我都拿过来跟 i 进行一下比较,从而选择出一个最小的位置,那么我比较的时候就是很简单了,那我就是如果 这个最小值到底是哪一个啊?如果我勾位置的数字就是我这个当前最小的位置,结果比我勾位置的数还要大, 那么我这个勾位置就是小的,否则的话我不动啊你,你那个挨位置还是最小的,那么比较完以后,我就选择出一个最小的了,然后把这个最小的数字跟当前的位置进行交换,我定一个临时变量去给他俩交换一下 i 位置的数,然后 i 就是 跟勾位置进行一下交换,命不对,应该是最小的位置跟命进行一个交换,然后 命就等于 i, 然后啊,瑞亚 好选择排序就写完了,验证一下对不对?我们先给他打印一下原来的这个数值, 然后调用一下我们的这个选择,再看一下, 嗯,排序正常,没毛病。那么这个选择排序再解释一遍啊,在呃,我们现在把验证了没问题以后,我们来看一下这个代码,把这个代码逐行解释一遍。 首先第一个佛循环做的位做的事是我要去排序这个数组里面第几个位置的数,我要让他变得有序,就是我一个,我先拿到一个无序的数组以后,我这边拿到了一个无序的数组,那我肯定从第一个位置我开始让他变得有序 啊。我先把第一个位置我确定你是最小的,然后第二个位置你是第二小的,第三个位置你是第三小的,这样周而复始,一直到这个数组的结尾,那么这个数组就会变成了一个有序的数组, 这是第一个,这是第一个负循环干的事情,要确定每一个位置的数,我要把它变成最小,我要拍哪个位置的数。 然后第二个负循环干的事是我确定好了第一个位置,我要排这个位置以后,我就拿这个位置后面的数,我挨个跟这个位置比较啊,从而选择出一个最小的数字,然后我于当前的这个数字给进行交换。就比如说我拿这个数字 啊,我去跟八去,去跟八进行交换,我我挨个跟八对比,我选择出一个最小的,那肯定就是零嘛,对吧?那我零固定下来以后,那我下一个,我就排他嘛,排他就从他这里面拿一个最小的数字,我跟八相比较,那最小的肯定是一嘛,对吧?所以就是挨个周而复始,周而复始,从而使得整个数组 从而变得有序,这就是选择排序。好,说完选择排序,我们现在看第二个冒泡排序,其实冒泡排序,嗯,还用原来的这个数组吧。啊?那个 八零七一九三六 冒泡排序,这个顾名思义啊,你会发现在整个排序的过程中,它就像是气泡一直在往上哎冒一样。首先我拿到一个无序的数组,然后我想要把这个数组来进行有序,那么冒泡的思想就是说 相邻的两个数进行比较,如果我后面的数比前面的数大,就交换相邻的两个数进行比较,一个数组我肯定是从这个 还是从第一个位置开始相邻的数比较,哎,我八跟零比较,我发现八比零大,它就交换,它就变成了这样,然后这两个再进行交换,然后就发现了这样, 然后这两个进行交换, 然后这两个不交换,这两个交换, 这两个还是交换, 那么交换到头以后,那么我最后一位,这个九一定是最大的,就是说我数组的最后一位一定是最大的,因为两两交换,只要我比你大,我就交换,所以等到我到这个数组末位的时候,我九一定是最大的了,这个数组的后面最后一位 一定是最大的,所以对于这个数组来讲,此时我这个最后一位我就固定死了,我就不用管它了,那么我接下来只需要管从零到倒数第二位这个数字上 就好了。那么同样的,我现在对这组数组进行交换,同样的两两进行交换,那么是零七一八三六不用变,然后这边进行交换,这这两也这边就要进行交换, 这个他就是一,他就是七,然后这两不用交换,七小于八就不用进行交换,然后这两个进行交换,然后他就是三,他就是八, 这两个也进行交换,他就是六,他就是八。那好了,我到这一步的时候,我这个倒数第二位八,那他一定是第二大的, 他一定是第二大的,那我倒数第二位我也不用管了,我只需要管我倒数第二位之前就好了。所以你们有没有发现一个规律啊?我用冒泡排序来进行排序的话,我一开始排的是整个数组, 转换转换转换,转换到最后一个数组,然后我这位置固定以后,我剩下我只用管他到这个位置就好了。固定以后我剩下只要管他到这个位置就好了。固定以后我只要管这个位置,这个位置,这个从而一直到这个数组的第一位。 所以也就是说我一开始我是在整个数组,我一开始要定一个下标,这个下标我用来去管理我 这个数组,这个无序数组的范围是多少?一开始是整个数组吗?但是我第一次完了以后,我最后一个有序了,所以我范围就变成了,呃,数组的长度减一就是少一个,然后减二、减三、减四,一直到头 后就变成一个有序的输入了。所以这个过程中你看他俩交换、交换,交换,交换,交换,是不是像一个小泡泡,一直往上冒,一直往上冒,一直往上冒,一直往上冒,所以这就是冒破排序这个名称的来历。好了,我们现在知道了原理以后,我们就来直接写代码吧。哎呀,直接输入,哎, 冒泡泡表 sort, 哎,接受一个无序的数值,同样的,先访个刁民, 然后一开始我说我们先要,先要定义第一个负循环,在第一个负循环里面,我们要定义这个无序数组,它的这个范围是多少? 我用 i, 这个 i 就 等于 area 减一, i 大 于等于零, 这是我无序范围的数组。然后我第二个负循环就是我在无序范围内,我要两两给它进行交换,那么这个下标就是从零开始了。 第一个勾等于零啊,然后勾它是小于 i 的, 它不可能,它是在 i 的 范围上,所以它不可能比 i 大, 然后勾加加, 如果我勾范围的这个数据啊,我,我比我的下一位还要大, 那么它俩是不是就进行交换了? 好,这个冒泡排序就写完了,给大家表演一下 啊,没问题啊,排序没问题,无序有序。好,我们再来看一下冒泡排序的代码, ig 解释一遍。 第一个循环,首先我在一个无序的数组里面,我第一个循环就是说我定义的是这个无序数组的大小啊,一开始我拿到的是整个数组都是无序的,整个数组都是无序的,所以我我这个下就到这边, 无序的范围就到这边,那么经过我一轮的排序以后,最后一位他就是有序的了,所以我第二次的范围就到这边, 那我倒数第二位有序以后,我范围就到这边,范围就到这边,依次减少一位,直到这个数组的零位啊,就是我第一位,我第零位都有序了啊,就下标零,我第一位都有序了,那么我整个数组就是有序的了, 那我第二个负循环就是在我无序的范围内,我从第零个数组啊下标为零第一个数据开始,我两两相互比较, 两两比较,两两比较,两两比较,两两比较,两两比较啊,如果叉,这是勾,这是勾加 e, 如果我比你大,那咱俩去交换, 我比你小,那咱俩就不管。两两比较,这个过程就是冒泡的过程啊,就好像你喝汽水的时候,那个泡冒泡泡沫一直往上浮一样,往上浮就是在交换,往上浮就是在交换,从而我每一轮交换下来,我在我这个无序数组的最后一位,我都能确定他是最大的, 那么周而复始,一直到这个数组的地下标为零,就第一位的时候,那么整个数组他就是有序的了。这就是冒泡排序的基本算法,基本思想跟他的一个代码实现啊,非常简单,这个也很好理解。好,我们现在来看最后一个排序,插入排序, 呃,在排序餐费里面,插入排序相比较于冒泡跟选择来讲,算是不错的一个排序啊,虽然他本身其实也没好到哪里去,但是海子里拔将军嘛。啊,插入排序相比较于这两个来讲,嗯,算是挺不错的一个排序。 好,我们来看一下这个。什么是插入排序?所谓插入排序,说是将数组分为以排序跟未排序两部分,这不废话吗?在初始的时候以排序只有一个元素, 这不也是废话吗?就一样的就是一个数组拿到一个无序数组,那肯定是所以一个一个往后排吗?那关键在第二句,你看从未排序里面取第一个向前扫描已排序部分, 然后将比它大的元素向后移,直接找到合适的插入位置。这文绉绉的,不知道说什么意思啊?我们直接来看啊,跟刚刚一样,举个例子还是这个数组,我们来看这个数组,它是 八零七一九三六这个数组。 那什么叫,什么叫将比他大的元素都向后移动?一位老规矩,我们在排序的时候,我们肯定是从左往右啊,这么依次来排, 那么同样的,我现在拿到一个无限的数组,我给他一个下标啊,我给他下标,哎,我就从 i 开始,我往后排,那么我 i 只 i 的 下标为零,就是第一个元素的时候只有一个八,其他的我不看。现在只有一个八,那么只有一个元素的时候,那跟别的排序算法一样,那你只有一个八,我也没别的数跟你比较啊,所以 我也不知道啊,谁大谁小,所以这八就是有序的。然后我从他后面开始取啊,我从他后面, 我从紫色吧,紫色比较有韵味啊,卧槽,我给他下标为勾,那么我从勾开始往后取,那么我这个勾依次跟他前面的数来进行比较。啥意思?就说我勾, 然后这个位置就是勾减一,那么我勾跟勾减一比较,如果我勾比勾减一的位置大啊,就前一个位置我比我小,那我给他交换,那么这个时候就会变成零八七一九三六, 那么我勾从这边取,然后再往前就零了,就越界了,所以我从勾开始取的数字已经结束了,那么这两个位置我就认为 我就不用,我就不用再去进行比较了,那么我下一位我勾的位置就会由这边来到这边,他就是勾,然后他是勾减一, 那么同样的,我勾再跟勾减一去进行比较啊,七比八小,那么就会变成零七八一九三六, 那七再往前呢,七已经比零大了,所以这一步就 ok 了,这一步就 ok 了,那周而复始,我他就变成勾,那么我往前挪挪挪,那就会变成差一比八小,就往前挪一位,所以这一步挪完以后就会变成零一七 八九三六啊,那么就这样啊,一直挪挪挪,挪到这啊,就会发现一比零大,那我就不用再往前挪了啊,那同样的,然后我勾就会变到这边, 那这边就是九啊九,他就是他比所有的都大,他比八大,比七大,所以这一步是不用挪的,然后再下来,那么他就是勾,那么我就会往前挪,挪挪挪就会变成零一三七 八九六啊,然后他就变成勾,最后一步,这边就这么往前挪,挪挪挪就会挪到这个位置, 就会挪到这个位置,七八九,依次往前挪,那就变成 六七八九, ok, 这么周而复始,一直到勾达到数组最大值的时候啊,数组的长度减一,就是它的下标最大值的时候,那就会发现这整个数值就会变成有序的了, 就是他会选择一个数依次往前去比较,然后插入他合适的位置,所以这叫插入排序。你们看这个插入排序的,它的这个算法像什么呢?非常像,就是我们 打扑克牌啊,就是你跟别人玩斗地主打扑克牌的时候,你是不是从一个啊?这边假设是你,你每一步骤,这就好比是你手上已经有的牌啊,是已经有序的,这是你手上没有的牌,是无序的啊,就是勾。 那你每次从排队里面拿一张牌以后,你会依次便利你手里面的牌啊,然后给他插到他合适的位置,对吧?比如说你现在手里已经有牌一二三啊,然后给他插到他合适的位置,对吧?比如说你现在手里已经有牌一二三啊,然后给他插到他合适的位置 啊,摸到一张八,八就插在这个位置,然后又摸到一张六,那你六肯定是插在八前面的位置啊,那我就把六放在这个位置啊,这个跟我们平时的扑克 非常像啊,就是这个意思。 ok, 那 知道原理以后,我们就直接给他实现一下吧。写个代码实现一下 插入 sort, 接收一个无需的输入啊,老规矩,先访个刁民, 然后我们开始这个代码主体。首先我是不是还是要先去循环这个无需的输入啊?因为我拿它的数挨个去插入嘛,挨个的去插入,所以我肯定是挨个的去循环这个无需输入的每一个元素啊,那么 循环他,但是这个爱我就不从零开始,我得从一开始。为什么从一开始呢?因为我爱等于零的时候, 他前面没有数字跟他进行比较啊。我零的时候,我下标是第一位,那我第一个数字,我前面没有数字跟我比较,所以我等于零是没有意义的,我得从一开始下标,一也就第二个数字开始,起码我前面还有一个数字,我能跟他比较一下,然后我把他拿来比较的这个数字我给他定义成勾,也就是爱减一, 我代替一个勾,我就等于二减一,然后这个勾呢?注意 不能越减啊,勾得大于零,并且勾大于等于零,并且当我这个勾大于我勾加一时候的这个数字的时候, 我是不是就给他俩进行交换了?这个直接拿过来, 好,这个插入排序就写完了,非常短啊,给大家验证一下 啊,排序没问题,排序没问题啊,再来逐行解释一下这个代码为什么是这个样子。 首先我这个无序的数组 随便八零三五七,然后就用它来做这个无需的数字,那么我 i 从一开始就从它开始,我是 i, 对 不对?那我定一个勾等于 i 减一,那它是勾, 那么我这个勾我在负循环里面勾什么时,勾什么时候会停下呢?那就是当,要么就是当我前面的数字已经比我那个, 要么就是我前面的数比我小,要么就是我已经来到最前面的这一位,所以我负循环的第二个条件是我勾大于等于零啊,要么就是要么我勾大于等于零啊,那此时我这个勾已经在第零位了,并且, 并且我这个勾大于勾加一,勾加一,是不是就是 i, 那 我是不是比他大,所以我这两个数进行交换, 交换完以后是这样子,那我第二步的时候,我 i 是 不是来到了这个地方, 这是我的勾对不对?那我勾的话,我还是我勾的话,勾跟勾加一比较一下,就相当于说我拿三出来,我跟八比较,那我是不是比他小?所以这就是不是八三,然后勾减减,勾减减,那就来到了勾的这个位置, 那这个时候他是勾,这是勾加一,那我零跟三去比较,满足条件吗?不满足,因为我零比三小,所以他不用变, 那再下就变成零三八五七一,然后二加一,二就来到这个位置,然后勾就来到这个位置, 这是二,这是勾,这两勾比勾加一大,所以这个这个,这两交换完,这就是五,这就是八,然后勾减减,它变成勾, 第二个负循环,勾减减,它就变成勾,然后这两个交换码不交换,因为三比五小,所以这一轮比较完以后就是零三五八七一,然后再下一步 勾,这就是 i, 这就是勾,然后勾,勾比它大吗?比它大,所以这两个进行交换,这就是七, 这就是八,所以以此类推。周而复始啊,这最后一轮,那 i 是 一直交换,一直交换到头,周而复始,那么就完成了这个插入的排序。 其实插入排序的核心思想就是我从乱序的里面拿一个数进来,我插入到有序数组里面的一个位置,那么这个位置是哪呢?要么我前一个数字比我 比我小,那我知道,我不用再往前了,我就在这个地方插入,要么就是我到头了,我到头了,所有的数据都比我大,我到头了,那我就插在第一个位置啊,所以插入插入就是这个意思,就是 乱序中一个数比较,然后插入有序 中,这就是乱序的核心思想,是不是也很简单? 好了,这三个排序就已经全部说完了,插入、冒泡和选择都已经全部说完了,其实算法本身并不难,尤其是今天,都是以一些基础入门的算法为主啊。这个排序是非常简单的,但是听懂了不代表你就会写 算法这个东西他其实没什么技巧,就跟你高考时候刷试卷一样,就是靠无数的题目啊,无数的代码去给他一步一步熟练起来,就有空就多敲一敲,光听懂了没用,得自己用手去敲啊,有空就多敲一敲,然后这一次,呃,以这三个排序入门,然后下 一下一个视频,我会再挑几个比较有意思的排序,比如说什么堆牌啊,规定牌这些就是稍微,呃,稍微难一点,就是 作为一个境界吧。 ok, 那 么看到这里的话,非常感谢小伙伴看到这里。呃,还希望,如果能看到这里的话,还希望给个一见三年啊。你的鼓励就是我更新最大的动力,我们下一节课不见不散。我是薄荷拿铁,我们再见。

哈喽,大家好,我是麦斯,今天给大家讲解冒泡排序的项目。冒泡排序 bubble sorry 是一种简单的排序,其基本思想是每一趟凉凉比较相邻元素, 如果顺序不对就交换冒泡排序。每一趟都会将最大最小的数顶到最后,就像一个个气泡向上浮,冒出水面。具体步骤是以从小到大排序为例。 一、在一个长度为 n 的无序数组中比较第一个和第二个数,如果后面的数比前面的数小,就交换他们的顺序。二、对每两个相邻的数重复步骤,一直到 n 个数变利完毕, 最大的数被放在末尾。三、重复步骤一到二,嘣按减一次,每次都把尚未排序的数中最大的放在末 后尾。我们需要实现点击绿奇,先在列表内生成十个随机数,再按下空格键,列表内的元素被按照从小到大排序。首先创建列表 vs 用于存储十个一到一百的随机数。当小绿奇被点击时,先删除列表的全部项目, 重复执行十次。将一到一百的随机数加入列表,点击小绿旗列表,填入十个一到一百的随机数。接着实现从小到大的冒泡排序过程。当按下空格键时,比较列表中的相邻两项, 需要创建变量 i, 表示列表元素的序号。将变量 i 设为一,如果列表的第二加一项比列表的第二项小,那么需要交换这两项 列表的两项元素。做交换需要借助一个变量 temp, 先将列表的 d i 加一项存入变量 temp, 然后将列表的 d i 项放入列表的 d i 加一项,也就是将列表的 d i 加一项替换为列表的 d i 项。 最后将存入变量 temp 的列表第二加一项放入列表的第二项,也就是将列表的第二项替换为变量 temp, 这样列表第二加一项的元素和列表第二项的元素就交换成功了。接着将变量二增加一去判断列表后面相邻的两个元素。第一趟排序十个数,需要重复执行九次判断。第一趟 排序之后,确定最大值放在了最后。接下来第二趟排序只需判断剩下的九个数,需要重复执行八次判断。每执行完一趟排序, 能确定一个这趟排序的最大值放在右边,直到剩下最后两个数时重复执行一次判断后,所有数按照从小到大的顺序排好。需要创建变量 g 来表示每趟排序需要重复执行判断的次数,每趟两两,比较的次数。从九开始, 将变量 j 设为九,重复执行判断的次数改为变量 j。 执行完一趟排序后,将变量 j 减一,重复执行九趟排序十个数就会按照从小到大的顺序排好了。 运行程序,点击小绿旗列表,填入十个一到一百的随机数,按下空格键,列表中的十个数根据冒泡排序的规则从小到大排好。

猜猜这是什么算法?这就是最简单的排序,冒泡排序,今天我们就来看看他的具体逻辑算法。 我们先列出五个高度不一致的方块,将他们随机排序,然后我们从头开始比较相邻的方块,如果前面的方块高于后面的方块,我们则将他们两个交换位置,然后从开始的一对比较到最后一对, 经过一轮后,最后一个方块就一定是最高的,我们就可以不停地重复上述过程,直到没有任何一个方块需要交换为止。那么整个方块就会被我们用从小到大的排列方式给排列完成了,是不是非常简单呢?

冒泡排序跟选择排序很像,还记得他的口诀吗?外层循环 n 减一,内层循环 n 减一减 i, 两两比较做交换,它非常简单,就是比较相邻的两个元素挨个比,如果第一个比第二个大,就交换他们两个,直到排序完成。那么冒泡和选择排序的区别就在于,冒泡是相邻作比较,选择是全局比较。 ok, 这里给你介绍代码,答应出结果。下一次我们就来个逗逼排序。

小伙伴们大家好,这节课呢我们来看第十四题,题目是使用冒泡对数组进行排序,这一看就是冒泡排序,对不对?那冒泡排序呢?很多同学是很熟悉的,这里呢我们就直接来写了,一边写呢一边给大家来进行解释, 回到我们的开发者工具,在这里呢,我们先加一个注示,在注示里呢,我们把题目拿过来,题目呢是使用数组进行冒泡排序,其实解析呢就两个字,呃,就就是冒 泡排序。冒泡排序的关键点在于什么?在位置的调换,就是要调换数组中两个元素的位置,因为比如说我们有一个数组,我们这里 随便写一下啊,数多了一个一四三五七吧,然后再来一个二,好吧,那我们要分别拿掉两个元素,对两个元素进行比对,如果第一从小到大,这里要看是从小到大排序,还是从大到小排序都可以啊, 来看一下两个是否需要调换位置,逻辑上就是这个样子,所以叫位置的调换。这样我们定一个函数,专门用来做这个数值排序的,就是你传入任何一个数值呢,我都可以进行一个排序,这里呢我们传一个 numbers。 首先呢我们在这里做第一件事就是获取到数值的长度,用来做循环使用,我们可以来个 n, 愣死一个 啊, numbers 啊,这个呢就是把这个你传过来的数组扔进去,看一下数组的长度,然后我们进行一个循环循环,我们的数组里边呢,我们写个 n 就 行了,好吧,那只有一个参数, 然后我们这样的话,循环就是第一轮循环,取出其中的一个数字,但是我们要取两个数字,就像我们刚刚速度刚刚那个一样,你要取一和三,要取两个数字做对比的,对不对?谁比谁大,或者谁比谁小,所以我们要进行第二个循环,每轮循环呢,取到其中一个,第二我们循环这印一个什么呢? 认知好里边正常情况下,我们也传一个零到 n 吧,然后冒号,然后这样的话我们就能取到 a 和 g 了,然后我们再去判断,通过 numbers 里边的 g 进行一个 numbers 里边的 g 加一,哎, g 加一,然后做对做,哎,这加一啊,做对比,取出两个数字的对比啊,好看一下谁大谁小,是否需要调换位置。当然呢,这里边涉及到一个细节,就是我们第二轮循环,这里面不是要取到数字中的两个数字吗?这样吧,我们在下面先把这个数组写一下啊,我们写个 f, 然后冒号,下面呢我们呃定一个数组吧,数组呢我们随便定义,比如说五二 有一六,好,随便定一个数组,然后我们调用上面这个函数呢,会把这个数组给它传进去, data 给传递进去,对吧?然后最后呢,我们再把这个数组给打进去了,我们就可以看数组的结果了, 然后你看我这样一调用的话,把这个呃 data 传过来了之后,相当于把这个数组传递过去了,对吧?那我们通过这 取到第一个数,通过这加一取到第二个数,然后对第一个数和第二个数呢,做一个大小的对比,是否需要?需要调换位置对不对?然后这个时候设到一个问题,我们第二轮这个循环呀,你可以在 n 后面呢减去一个一, 为什么呢?因为整个数字长度是五,你得到的这个 n 呢?其实就是五,对于我们这个数字来说,但是你第一轮取到一个数字,呃,就是你取到一个二,再取到取到一个五,再取到一个二,事实上你能取掉两个数了,那再次循环的话,只需要循环 一、二三,除了第一轮循环,一轮两轮三轮四,只需要进行四轮循环就行了,是不是?所以这里面要减去一啊,不要那么多轮循环,然后我们再去减个 a, 为什么呢?因为你每循环一轮,证明最后假如说从小到大排序最后一个数字都是已经排序好的。比如说你取到五,跟他对比,跟他对比,跟他对比,跟他对比,最后一个数字一定都是排序好的 啊。你说最后一个数字你是可以不用动的,每一轮都会多一个数字,每一轮都会多一个数字,所以这里把轮数那个对应的数字给减去,这样的话可以减少循环次数来优化你的排序的这个资源的消耗,就是让你的排序变得更加高效。那这样 我们定一个 time 中间,中间值用来接收这个数字 number g 把,哎, number g, 把这个 g 呢赋值给了 temper, 然后下面呢?因为你他俩就是他比他大,我们从小到大排序要进行一个位置调换的,因为他大于他,说明你看这是不是在前面呀?这加一是不是在后面呀?既然第一个数比第二个数大,而且我们是从小到大排序,是不是需要调换位置呀?对不对?因为我们要把五放在二后面嘛, 所以我们先把这个五临时存给 temper, 然后再把 numbers 的 g 与 numbers 的 g 加一,做一个呃,赋值,此时 g 变成了 g 加一,也就是说原来的二 啊,你原原来我们说这样比对啊,这个是 j, 这是 j 加一,五是 j, 二是 j 加一,对不对?五是 j, 二是 j 加一,他俩需要调换位置,我们把这个五呢已经存给了 time, 然后再把这个二呢复制给原本的 j 加一, 复制个原本的 g 加一,所以 g 加一。现在,呃,复制原原本给那个 g, 呃,复制给了这个,然后它现在变成二了,然后我们再把 g 加一的那个五重新给复制回来,就相当于它俩一个位置的调换了,对不对?所以用 numbers, g 加一等于 temper。 哎,这样啊,这样做,他们就完成了一个位置的调换,然后因为你是循环嘛,不停地进行位置的调换,那这件事我们是不是就已经排序完了呀?好,现在我们运行看下,效果 好,大家可以看到,排序完了,变成一二五六九,是不是从小到大排序啊?没有任何问题啊,这个就是冒泡排序的一个实现,就是一个位置的调换, 不需要调换呢,那就跳过 if 呢,里面不再执行就跳过了,需要调换呢?那你就调换一下是不是?好,那对于这样一个冒泡排序呢,大家可能比较熟悉,我们就再来回顾一下。那这道题呢,我们就说到这里,感谢各位聆听,咱们下节再见。



大家好,我是老吴,欢迎观看 excel vba 入门开窍课程。这节课我们来讲数组的排序,数组的排序并不是在工作表里面进行排序,而是我们首先把工作表里的词,比如说这个单元格的区域,让他先形成一个数组,然后我们在数组内部进行 排序,排序好之后我们再把它倒出来。 ok, 我们来看这个效果啊,对他进行了生序排序。好,我们来看下代码, 这个代码使用的排序方法被称之为冒泡排序,他并不是 vba 做好的一个方法。我们之前学过单元格的排序,我们可以用 solt 这个冒泡排序呢,他是 一种算法啊,是一种编程的思维,我们在学习其他编程语言的时候呢,也可能会学到冒泡排序。我们先不看这个代码,我们首先在这个工作表里面,我用鼠标来演示一下他是怎么排序。 首先我们用二十二跟这个七进行对比,如果这个第一个数字比第二个数字大,那么就把他们两个进行对调,就像这样把他们对调 啊,然后我再用第二个数字跟第三个数字进行对比,如果第二个数字比第三个数字大,那么就对调,如果条件不成立,也就是小,那我就保持原有的状态不变。然后继续再用第三个数字跟第四个数字进行对比,如果第三个数字比第四个数字大,那就进行对调, 然后又把他们两个换个位置好,然后再用第四个跟第五个进行对比啊,这两个条件不成立啊,他比他小,所以不变好,再用第五个跟第六个进行对比,九十比二十七大,所以两者又对掉 好,这样五次对比下来之后呢,我们就把这个数组里面的最大的值,把它排到了最后面,好,接着循环回去啊。因为我们这边是使用了这个循环 好,所以他又用第一个数字跟第二个数字进行对比,然后逻辑是一样的,只要前面这个数字比后面这个数字大,就对调啊,这两个保持不变,然后这两个保持不变好,这两个保持不变好,这两个需要对调了啊,因为七十七比二十七大,又对调 好,然后再用这个和这个对比啊,他们两个保持不变啊。第二轮下来之后呢,我们就把这个倒数第二大的这个数字排到了这个倒数第二的位置好,然后再回去又是从第一个这样轮流对比过去,那这种轮番排序 一共要持续多少次?一共要持续五次就能把这个数组排序完。 ok, 我们先来看下代码好,首先把 a 三到 f 三这个单元格区域的值先形成一个数组。 a 啊,我这边使用了两个转字, 目的就是让这个横排的这个数值区域呢,转化成一个一位数字啊。现在 ar 就形成了一个一位数字好,然后进入了第一层循环,这个循环完全是为了让这个内存循环循环五次,这个内存循环循环一次,就相当于我们在这边 排序一轮,所以我外层循环呢,用这个 u 磅 ar 六减一,就是五一到五循环五次。所以你看我这个内存里面呢,并没有使用到这个 i 变量,所以他完全是一个让这个内存循环循环五次 是的一个工具而已。 ok, 然后进入内存循环,内存循环 j 等于 e twou 棒, ar 减一啊,一样的,也是让他循环五次,为什么呢?来看这地方示意图啊,一次对比两次对比三次,四次,五次,他六个数字呢,我们只要对比五次,就完成了一轮排序 啊,然后进行对比了,首先是这个 ar 一,因为 j 现在是一啊, ar 一是什么呢?二十二啊,然后对比的是 ar j 加一就是 ar 二,也就是跟这个地方进行对比啊, 二十二比七大吗?条件成立,两者就要兑换,我们在这个数组里面怎么来进行兑换呢?这个就是冒泡排序的核心,我们先把 ar 一,也就是二十二,我们先放到这个变量里面,让这个变量先接收这个 a ar 一的值,现在 ls 变成了二十二,然后我们再把 ar 二的值把它复制给 ar 一,也就是把这个七复制给这个 ar 一,好看一下, 好,现在 ar 一就变成了七,然后我们再用刚刚这个变量,因为现在这个变量是二十二了,然后二十二再复制给这个 ar 二啊,二十二,这样呢,他们两个就进行了对调好,所以这个变量呢,他完全是一个载体,如果我直接把 把这个 ar 二的值负值给了 ar 一,那么 ar 一的值就被冲掉了,这个代码就不记得这个 ar 一是什么东西了。我们先把这个 ar 一的值先给到这个变量,让他先接住,再把 ar 二负值给 ar 一,然后 我们再把这个值再复制给 ar 二啊,这样倒腾一次呢,这个数字就对掉了,然后再次循环好,这个时候 j 变成了二啊,也就是这个地方 ar 二比 ar 三大吗?啊,显然这个条件不成立,所以不会运行,下面的话,跳过, 好,继续,好,现在是 ar 三七十七,他比 ar 四大吗?条件成立啊,首先把这个七十七复制给这个变量,让他变成七十七, 然后我们再把 ar 四的值负值给 ar 三啊,就是这个六十六,把它放到这个 ar 三里面啊,就放过来了,然后我们再把刚刚得到的七十七再放到 ar 四里面, 他们两个就进行对调了。好,继续啊,现在接一次。是 ar 四比 ar 五大吗?条件不成立啊,所以不会运行,下面的话跳过 好,现在 j 是五, ar 五九十比 ar 六大吗?明显的他比较大,所以继续把九十先给到变量 ls。 好,然后再把这个二十七给到这个 ar 五啊,就放过来了。好,然后再把 ls 复制给 ar 六放过来啊,他们两个就对掉了。 好,一轮下来之后,我们就得到了一个最大的值,放到了这个数字的最尾端,然后就是再次循环啊,现在挨是二啊,循环到第二次了。 好,我们再快速的来看一下啊,这个时候他就不停的这样换。好,我们在这边做个断点。 好,这个时候嵌套循环结束了,这里面一共循环了五次,这个数组就已经进行了生序排序了。好,然后我们再把这个数组把它贴到这个单元格区里面。好,这个时候 就是一个生序排序,我们在初次学习冒泡排序的时候呢,有的时候这个逻辑还没有绕清楚啊,或者说还不够直观。好,我是怎么记住冒泡排序的呢?啊,我是想到了当年坐火车的一个场景,这是我画的一个火车的平面图啊,两 两边是座椅,中间是过道,这个过道非常窄,如果 a 想去下面, b 想去上面怎么办?硬挤可能是挤不过去的, 所以我们要分三步,首先 a 进入 wc 啊,让他先进入厕所里面好,然后 b 站到了 a 的位置好,接着 a 从厕所里出来,站到 b 的位置里面 啊,这样就完成了 a 和 b 的对调,这个做法呢,就跟我们这个代码是一模一样的,首先我把 ar j 复制给 ls, 这个变量就相当于 这个 a 先进入厕所里面好,然后 a r 接一加一,相当于这个 b 站到了 a 的位置,这个厕所 ls, 然后把它扔到了 b 的位置啊,这样两者就进行了对调,可能有一些九五后或者零零后呢,无法理解这种火车里面这种换位置,还要先进入 wc, 这么麻烦, 那你可能是没有坐过绿皮车,在我小时候的时候呢,我们是做绿皮车的啊,好,可以来看一下。好,我们当时上火车的时候呢,我们都不是从门里进去的啊,我们是爬窗户进去的,然后火车内部是什么情形呢? 好,火车内部是这样的,所以我们在通过火车的时候呢,我们必须让一个人先挪到另外一个位置,我们才能过去,否则你休想过去。但是这个火车里面存在一个中国最有趣的现象,就是个卖饮料的,这不管火车有多堵,他都能过去啊,这个是我百思不得其解的事情。看完这两张图,我们 再回来看下这个示意图,你就明白我的用意了吧,两者要对调,首先要找一个中间的媒介啊,这个媒介呢,就是这个 wc 啊,在代码里面呢,就是这个变量。 ok, 刚刚我们演示的是生序排序,如果是想降序排序应该怎么办呢? 其实很简单,我们只需要把这个地方呢换成小宇号就可以了啊,来测试一下啊,这样就这样去排序了。 好了,关于冒泡排序呢,还是需要大家先把这个代码写出来,然后认真看本地窗口里面变量的数值变化,来理解其中的逻辑。好了,那这节课呢,就讲到这里,感谢各位看官的支持,你的点赞是我继续创作的动力,关注我,下节课我们将学习新的内容。