|
1 | 1 | ## 1. 归并排序算法思想
|
2 | 2 |
|
3 | | -> 归并排序(Merge Sort)基本思想: |
| 3 | +> **归并排序(Merge Sort)基本思想**: |
4 | 4 | >
|
5 | 5 | > 采用经典的分治策略,先递归地将当前序列平均分成两半。然后将有序序列两两合并,最终合并成一个有序序列。
|
6 | 6 |
|
7 | 7 | ## 2. 归并排序算法步骤
|
8 | 8 |
|
9 | | -- 初始时,将待排序序列中的 `n` 个记录看成 `n` 个有序子序列(每个子序列总是有序的),每个子序列的长度均为 `1`。 |
10 | | -- 把当前序列组中有序子序列两两归并,完成一遍之后序列组里的排序序列个数减半,每个子序列的长度加倍。 |
11 | | -- 对长度加倍的有序子序列重复上面的操作,最终得到一个长度为 `n` 的有序序列。 |
| 9 | +1. **分割过程**:先递归地将当前序列平均分成两半,直到子序列长度为 `1`。 |
| 10 | + 1. 找到序列中心位置 `mid`,从中心位置将序列分成左右两个子序列 `left_arr`、`right_arr`。 |
| 11 | + 2. 对左右两个子序列 `left_arr`、`right_arr` 分别进行递归分割。 |
| 12 | + 3. 最终将数组分割为 `n` 个长度均为 `1` 的有序子序列。 |
| 13 | +2. **归并过程**:从长度为 `1` 的有序子序列开始,依次进行两两归并,直到合并成一个长度为 `n` 的有序序列。 |
| 14 | + 1. 使用数组变量 `arr` 存放归并后的有序数组。 |
| 15 | + 2. 使用两个指针 `left_i`、`right_i` 分别指向两个有序子序列 `left_arr`、`right_arr` 的开始位置。 |
| 16 | + 3. 比较两个指针指向的元素,将两个有序子序列中较小元素依次存入到结果数组 `arr` 中,并将指针移动到下一位置。 |
| 17 | + 4. 重复步骤 `3`,直到某一指针到达子序列末尾。 |
| 18 | + 5. 将另一个子序列中的剩余元素存入到结果数组 `arr` 中。 |
| 19 | + 6. 返回归并后的有序数组 `arr`。 |
12 | 20 |
|
13 | 21 | ## 3. 归并排序动画演示
|
14 | 22 |
|
15 | | - |
| 23 | + |
| 24 | + |
| 25 | +1. 初始序列为 `[6, 2, 1, 3, 7, 5, 4, 8]`。 |
| 26 | +2. 将序列分解为 `[6, 2, 1, 3]`,`[7, 5, 4, 8]`。 |
| 27 | +3. 将序列分解为 `[6, 2]`,`[1, 3]`,`[7, 5]`,`[4, 8]`。 |
| 28 | +4. 将序列分为为 `[6]`,`[2]`,`[1]`,`[3]`,`[7]`,`[5]`,`[4]`,`[8]`。 |
| 29 | +5. 将序列看做是 `8` 个长度为 `1` 的子序列,即 `[6]`,`[2]`,`[1]`,`[3]`,`[7]`,`[5]`,`[4]`,`[8]`。 |
| 30 | +6. 第 `1` 趟排序:将子序列中的有序子序列两两归并,归并后的子序列为:`[2, 6]`,`[1, 3]`,`[5, 7]`,`[4, 8]`。 |
| 31 | +7. 第 `2` 趟排序:将子序列中的有序子序列两两归并,归并后的子序列为:`[1, 2, 3, 6]`,`[4, 5, 7, 8]`。 |
| 32 | +8. 第 `3` 趟排序:将子序列中的有序子序列两两归并,归并后的子序列为:`[1, 2, 3, 4, 5, 6, 7, 8]`。得到长度为 `n` 的有序序列,排序结束。 |
16 | 33 |
|
17 | 34 | ## 4. 归并排序算法分析
|
18 | 35 |
|
19 | | -- 归并排序算法的时间复杂度等于归并趟数与每一趟归并的时间复杂度成绩。子算法 `merge(left_arr, right_arr):` 的时间复杂度是 $O(n),ドル因此,归并排序算法总的时间复杂度为 $O(nlog_2n)$。 |
20 | | -- 归并排序方法需要用到与参加排序的序列同样大小的辅助空间。因此算法的空间复杂度为 $O(n)$。 |
21 | | -- 因为在两个有序子序列的归并过程中,如果两个有序序列中出现相同元素,`merge(left_arr, right_arr):` 算法能够使前一个序列中那个相同元素先被复制,从而确保这两个元素的相对次序不发生改变。所以归并排序算法是 **稳定排序算法**。 |
| 36 | +- **时间复杂度**:$O(n \times \log_2n)$。归并排序算法的时间复杂度等于归并趟数与每一趟归并的时间复杂度乘积。子算法 `merge(left_arr, right_arr):` 的时间复杂度是 $O(n),ドル因此,归并排序算法总的时间复杂度为 $O(n \times \log_2 n)$。 |
| 37 | +- **空间复杂度**:$O(n)$。归并排序方法需要用到与参加排序的序列同样大小的辅助空间。因此算法的空间复杂度为 $O(n)$。 |
| 38 | +- **排序稳定性**:归并排序算法是一种 **稳定排序算法**。 |
| 39 | + - 因为在两个有序子序列的归并过程中,如果两个有序序列中出现相同元素,`merge(left_arr, right_arr):` 算法能够使前一个序列中那个相同元素先被复制,从而确保这两个元素的相对次序不发生改变。 |
| 40 | + |
22 | 41 |
|
23 | 42 | ## 5. 归并排序代码实现
|
24 | 43 |
|
25 | 44 | ```Python
|
26 | 45 | class Solution:
|
27 | | - def merge(self, left_arr, right_arr): |
| 46 | + def merge(self, left_arr, right_arr):# 归并过程 |
28 | 47 | arr = []
|
29 | | - while left_arr and right_arr: |
30 | | - if left_arr[0] <= right_arr[0]: |
31 | | - arr.append(left_arr.pop(0)) |
| 48 | + left_i, right_i = 0, 0 |
| 49 | + while left_i < len(left_arr) and right_i < len(right_arr): |
| 50 | + # 将两个有序子序列中较小元素依次插入到结果数组中 |
| 51 | + if left_arr[left_i] < right_arr[right_i]: |
| 52 | + arr.append(left_arr[left_i]) |
| 53 | + left_i += 1 |
32 | 54 | else:
|
33 | | - arr.append(right_arr.pop(0)) |
34 | | - while left_arr: |
35 | | - arr.append(left_arr.pop(0)) |
36 | | - while right_arr: |
37 | | - arr.append(right_arr.pop(0)) |
38 | | - return arr |
39 | | - |
40 | | - def mergeSort(self, arr): |
41 | | - size = len(arr) |
42 | | - if size < 2: |
| 55 | + arr.append(right_arr[right_i]) |
| 56 | + right_i += 1 |
| 57 | + |
| 58 | + while left_i < len(left_arr): |
| 59 | + # 如果左子序列有剩余元素,则将其插入到结果数组中 |
| 60 | + arr.append(left_arr[left_i]) |
| 61 | + left_i += 1 |
| 62 | + |
| 63 | + while right_i < len(right_arr): |
| 64 | + # 如果右子序列有剩余元素,则将其插入到结果数组中 |
| 65 | + arr.append(right_arr[right_i]) |
| 66 | + right_i += 1 |
| 67 | + |
| 68 | + return arr # 返回排好序的结果数组 |
| 69 | + |
| 70 | + def mergeSort(self, arr): # 分割过程 |
| 71 | + if len(arr) <= 1: # 数组元素个数小于等于 1 时,直接返回原数组 |
43 | 72 | return arr
|
44 | | - mid = len(arr) // 2 |
45 | | - left_arr, right_arr = arr[0: mid], arr[mid:] |
46 | | - return self.merge(self.mergeSort(left_arr), self.mergeSort(right_arr)) |
| 73 | + |
| 74 | + mid = len(arr) // 2 # 将数组从中间位置分为左右两个数组。 |
| 75 | + left_arr = self.mergeSort(arr[0: mid]) # 递归将左子序列进行分割和排序 |
| 76 | + right_arr = self.mergeSort(arr[mid:]) # 递归将右子序列进行分割和排序 |
| 77 | + return self.merge(left_arr, right_arr) # 把当前序列组中有序子序列逐层向上,进行两两合并。 |
47 | 78 |
|
48 | 79 | def sortArray(self, nums: List[int]) -> List[int]:
|
49 | 80 | return self.mergeSort(nums)
|
|
0 commit comments