作为一名对技术充满热情的学习者,我一直以来都深刻地体会到知识的广度和深度。在这个不断演变的数字时代,我远非专家,而是一位不断追求进步的旅行者。通过这篇博客,我想分享我在某个领域的学习经验,与大家共同探讨、共同成长。请大家以开放的心态阅读,相信你们也会在这段知识之旅中找到启示。
前言
我们继续学习下一个排序,归并排序,这是一个重要的排序,排序思想也很重要,这种排序也很高效,希望同学们可以认真阅读。
一、什么是归并排序
归并排序(Merge Sort)是一种高效的排序算法,采用分治
的策略来对数组或列表进行排序。基本思想是将原始数组分成若干子数组,对每个子数组进行排序,然后将它们合并成一个全部有序的数组
。
归并排序算法的主要步骤如下:
- 分解:递归地将当前数组分成两个长度差不多的子数组。
- 解决:递归地对子数组进行归并排序,如果子数组长度是 1 或者更小,则不需要继绀做分解,因为长度为 1 的数组自然而然就是有序的。
- 合并:将两个有序的子数组合并成一个有序的数组。
拿一个简单的数组 [38, 27, 43, 3, 9, 82, 10]
举例,归并排序的过程如下:
-
- 分解数组为
[38, 27, 43, 3]
和[9, 82, 10]
。
- 分解数组为
-
- 继续分解
[38, 27, 43, 3]
为[38, 27]
和[43, 3]
,以及将[9, 82, 10]
分解为[9, 82]
和[10]
。
- 继续分解
-
- 进一步分解
[38, 27]
为[38]
和[27]
,[43, 3]
为[43]
和[3]
,以及[9, 82]
为[9]
和[82]
。因为每个数组只有一个元素,开始合并。
- 进一步分解
-
- 合并
[38]
和[27]
成[27, 38]
,合并[43]
和[3]
成[3, 43]
,以及[9]
和[82]
成[9, 82]
。
- 合并
-
- 将两个有序数组
[27, 38]
和[3, 43]
合并成一个有序数组[3, 27, 38, 43]
,将[9, 82]
和[10]
合并成[9, 10, 82]
。
- 将两个有序数组
-
- 最终,将
[3, 27, 38, 43]
和[9, 10, 82]
合并成最终的有序数组[3, 9, 10, 27, 38, 43, 82]
。
- 最终,将
归并排序需要额外的内存空间来存储临时数组,所以它不是一个原地排序算法。不过,归并排序特别适合处理大数据集,并且是稳定的排序算法,即具有相等键值的元素经排序后其相对位置不变。
归并排序算法的时间复杂度为 O(n log n),其中 n 是数组或列表中元素的数量。
这个复杂度来自于两个主要步骤:
-
分解步骤:数组被一分为二,直到每个子数组只有一个元素。分解数组的过程是对数阶的,即每次操作减少一半的问题规模,所以分解步骤大约需要 log n 层递归。
-
合并步骤:在每一层递归中,都要合并子数组。虽然每层的合并操作涉及到整个数组,但由于有 log n 层,合并操作的总时间复杂度是线性对数阶的,即 O(n log n)。
总结起来:归并排序的时间复杂度主要由多次的切分(对数阶次数,即 log n)和在每个切分阶段执行的合并操作(每次操作需要线性时间,即 n)决定,所以总体上是 O(n log n)。这使得归并排序在最坏、平均和最好情况下的时间复杂度都是 O(n logn),这是一种非常稳定的性能表现。
二、练习
简单练习
考虑以下整数数组:
[29, 10, 14, 37, 13]
让我们用归并排序一步步排序这个数组。
Step 1: 分割数组
首先,将整个数组分割成更小的部分,直到每个部分仅包含一个元素:
- 初始数组:
[29, 10, 14, 37, 13]
- 分割为两部分:
[29, 10]
和[14, 37, 13]
- 继续分割:
[29]
,[10]
,[14]
,[37, 13]
- 最后分割
[37, 13]
为:[37]
和[13]
Step 2: 合并与排序
现在开始合并这些单个元素,组成排序好的子数组:
- 合并
[29]
和[10]
得到[10, 29]
- 合并
[37]
和[13]
得到[13, 37]
- 由于
[14]
已经是排序好的,它可以直接与[13, 37]
合并为[13, 14, 37]
现在,我们有 [10, 29]
和 [13, 14, 37]
,要合并它们成为一个排序好的大数组。
Step 3: 最终合并
- 取
[10]
和[13]
中较小的数,所以[10]
是第一个。 [29]
与[13]
比较,选择[13]
为下一个数,接着是[14]
。[29]
下一个与[37]
比较,我们选[29]
。- 最后的数是
[37]
。
合并后的数组是:[10, 13, 14, 29, 37]
较难练习
让我们对以下数组进行排序:
[34, -42, 0, 15, -9, 27, 51, 3, 12, 18]
Step 1: 分割数组
首先,分割数组直到每个子数组都是单个元素:
- 初始数组:
[34, -42, 0, 15, -9, 27, 51, 3, 12, 18]
- 分割数组为两部分:
[34, -42, 0, 15, -9]
和[27, 51, 3, 12, 18]
- 继续分割前半部分:
[34, -42]
和[0, 15, -9]
- 继续分割后半部分:
[27, 51]
和[3, 12, 18]
- 继续分割,直到每个子数组只