一、概念及其介绍
归并排序(Merge sort)是建立在归并操作上的一种有效、稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
二、适用说明
当有 n 个记录时,需进行 logn 轮归并排序,每一轮归并,其比较次数不超过 n,元素移动次数都是 n,因此,归并排序的时间复杂度为 O(nlogn)。归并排序时需要和待排序记录个数相等的存储空间,所以空间复杂度为 O(n)。
归并排序适用于数据量大,并且对稳定性有要求的场景。
三、过程图示
归并排序是递归算法的一个实例,这个算法中基本的操作是合并两个已排序的数组,取两个输入数组 A 和 B,一个输出数组 C,以及三个计数器 i、j、k,它们初始位置置于对应数组的开始端。
A[i] 和 B[j] 中较小者拷贝到 C 中的下一个位置,相关计数器向前推进一步。
当两个输入数组有一个用完时候,则将另外一个数组中剩余部分拷贝到 C 中。
3
自顶向下的归并排序,递归分组图示:
对第三行两个一组的数据进行归并排序
对第二行四个一组的数据进行归并排序
整体进行归并排序
def merge_sort(arr):
# 递归函数,对输入的数组进行归并排序
if len(arr) <= 1:
return arr # 如果数组长度小于等于1,直接返回
mid = len(arr) // 2 # 找到数组中间位置
left = merge_sort(arr[:mid]) # 递归地对左半部分进行归并排序
right = merge_sort(arr[mid:]) # 递归地对右半部分进行归并排序
return merge(left, right) # 合并左右两部分的结果
def merge(left, right):
# 辅助函数,合并两个有序数组
result = [] # 用于存储合并后的结果
i, j = 0, 0 # 初始化两个指针
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i]) # 将左侧较小元素加入结果
i += 1
else:
result.append(right[j]) # 将右侧较小元素加入结果
j += 1
result.extend(left[i:]) # 将剩余的左侧元素添加到结果数组
result.extend(right[j:]) # 将剩余的右侧元素添加到结果数组
return result # 返回合并后的有序数组
arr = [7, 2, 5, 1, 8, 4]
sorted_arr = merge_sort(arr)
print(sorted_arr) # 输出排序后的数组
当我们调用
merge_sort([7, 2, 5, 1, 8, 4])
时,会按照以下步骤执行归并排序:
- 初始数组为
[7, 2, 5, 1, 8, 4]
。- 进行第一次递归:
- 分成两个子数组
[7, 2, 5]
和[1, 8, 4]
。- 对左侧子数组
[7, 2, 5]
调用merge_sort()
进行递归。
- 再次进行递归拆分,得到子数组
[7]
、[2, 5]
。- 对
[2, 5]
进行递归拆分,得到子数组[2]
、[5]
。- 合并子数组
[2]
和[5]
,得到有序数组[2, 5]
。- 最后,合并子数组
[7]
和[2, 5]
,得到有序数组[2, 5, 7]
。- 对右侧子数组
[1, 8, 4]
也进行相同的递归拆分、合并操作。
- 拆分得到子数组
[1]
、[8, 4]
。- 继续拆分,得到子数组
[8]
、[4]
。- 合并
[8]
和[4]
,得到[4, 8]
。- 最后,合并
[1]
和[4, 8]
,得到[1, 4,
8]
。- 现在,我们已经获得了两个有序的子数组
[2, 5, 7]
和[1, 4, 8]
。- 最后一步是合并这两个有序数组:
- 从两个数组中各取出一个元素进行比较,将较小的元素添加到结果数组中。
- 在这种情况下,我们首先取出来的是2和1,所以将1添加到结果数组中。
- 然后,从原数组取出5和4,将4添加到结果数组。
- 重复上述过程,将剩余的所有元素添加到结果数组中。
- 最终,我们获得了完全排序的数组
[1, 2, 4, 5, 7, 8]
。