归并排序(Merge Sort)是一种基于分治法(Divide and Conquer)思想的经典排序算法,具有稳定性和O(n log n) 的时间复杂度。它通过递归将数组分解为更小的子数组,然后在排序的过程中合并这些子数组,最终形成有序序列。
1. 归并排序的核心思想
归并排序将数组分为两个部分,分别排序后再合并,具体过程如下:
1.1 分治思想
- 分解(Divide):将原始数组递归地划分为两个小数组,直到每个小数组的长度为1。
- 合并(Conquer):将已排序的小数组合并成更大的有序数组,直到最终形成完整的排序结果。
1.2 算法步骤
- 找到数组的中间点,将数组分为两部分。
- 递归地对左、右部分进行归并排序。
- 将两个已经排序的部分合并为一个有序数组。
2. 归并排序的特性
-
时间复杂度:
- 平均时间复杂度:O(n log n)
- 最佳时间复杂度:O(n log n)
- 最坏时间复杂度:O(n log n)
-
空间复杂度:O(n)(需要额外的临时数组存储合并结果)
-
稳定性:归并排序是稳定的,因为在合并时保持了相同元素的相对顺序。
3. 归并排序的代码实现
以下是用 Python 实现的归并排序算法:
3.1 基础实现
def merge_sort(arr):
if len(arr) <= 1: # 如果数组长度小于等于1,直接返回
return arr
# 分解
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 # 指针分别指向两个子数组的起始位置
# 按顺序合并两个数组
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
# 测试归并排序
if __name__ == "__main__":
array = [38, 27, 43, 3, 9, 82, 10]
print("原始数组:", array)
sorted_array = merge_sort(array)
print("排序后的数组:", sorted_array)
3.2 原地修改版本
如果需要节省空间,可以采用原地修改的方式进行归并排序:
def merge_sort_inplace(arr, left, right):
if left >= right:
return
mid = (left + right) // 2
# 分解
merge_sort_inplace(arr, left, mid)
merge_sort_inplace(arr, mid + 1, right)
# 合并
merge_inplace(arr, left, mid, right)
def merge_inplace(arr, left, mid, right):
# 创建临时数组存储合并结果
temp = []
i, j = left, mid + 1
# 按顺序合并两个部分
while i <= mid and j <= right:
if arr[i] <= arr[j]:
temp.append(arr[i])
i += 1
else:
temp.append(arr[j])
j += 1
# 将剩余元素添加到临时数组
while i <= mid:
temp.append(arr[i])
i += 1
while j <= right:
temp.append(arr[j])
j += 1
# 将临时数组的内容写回原数组
for i in range(len(temp)):
arr[left + i] = temp[i]
# 测试原地修改版归并排序
if __name__ == "__main__":
array = [38, 27, 43, 3, 9, 82, 10]
print("原始数组:", array)
merge_sort_inplace(array, 0, len(array) - 1)
print("排序后的数组:", array)
4. 归并排序的应用场景
归并排序适用于以下场景:
- 数据量较大,且对时间复杂度要求较高。
- 需要排序的数据无法放入内存(可以采用外部归并排序)。
- 对稳定性要求较高的排序任务。
5. 总结
归并排序是一种经典的分治算法,凭借其稳定性和高效的时间复杂度,在许多实际场景中被广泛应用。通过对算法的深入理解与实现,我们可以在复杂数据处理任务中灵活应用这种强大的排序方法。