归并排序算法¶
算法简介¶
归并排序是一种高效的、基于分治法的排序算法。它将数组分成两半,分别对它们进行排序,然后将结果合并起来。归并排序是稳定的排序算法,适用于大型数据集。
算法步骤¶
- 将待排序数组分成两个大小相等的子数组
- 递归地对两个子数组进行排序
- 将两个已排序的子数组合并成一个有序数组
代码实现¶
def merge_sort(arr):
if len(arr) <= 1:
return arr
# 分割数组
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]
# 递归排序两半
left_half = merge_sort(left_half)
right_half = merge_sort(right_half)
# 合并两个已排序的半数组
return merge(left_half, right_half)
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
# 测试
arr = [5, 3, 8, 4, 2]
sorted_arr = merge_sort(arr)
print("排序后的数组:", sorted_arr)
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[] arr = {5, 3, 8, 4, 2};
int[] sorted = mergeSort(arr);
System.out.println("排序后的数组:");
for (int num : sorted) {
System.out.print(num + " ");
}
}
public static int[] mergeSort(int[] arr) {
if (arr.length <= 1) {
return arr;
}
// 分割数组
int mid = arr.length / 2;
int[] left = Arrays.copyOfRange(arr, 0, mid);
int[] right = Arrays.copyOfRange(arr, mid, arr.length);
// 递归排序两半
left = mergeSort(left);
right = mergeSort(right);
// 合并两个已排序的半数组
return merge(left, right);
}
private static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
int i = 0, j = 0, k = 0;
// 比较两个数组的元素并合并
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result[k++] = left[i++];
} else {
result[k++] = right[j++];
}
}
// 添加剩余元素
while (i < left.length) {
result[k++] = left[i++];
}
while (j < right.length) {
result[k++] = right[j++];
}
return result;
}
}
复杂度分析¶
- 时间复杂度:
- 最坏情况:O(n log n)
- 平均情况:O(n log n)
- 最好情况:O(n log n)
- 空间复杂度:O(n)(需要额外的空间来存储合并结果)
排序示例¶
让我们通过一个具体的例子来理解归并排序的工作原理。假设我们有一个数组:[5, 3, 8, 4, 2]
分解阶段¶
首先,我们递归地将数组分解为更小的子数组:
第一层分解:
第二层分解:
第三层分解:
现在我们有了单个元素的子数组:[5], [3], [8], [4], [2],这些都是已排序的(单个元素总是有序的)。
合并阶段¶
接下来,我们开始自底向上地合并这些子数组:
第一次合并:
合并 [4] 和 [2]:
然后合并 [8] 和 [2, 4]:
第二次合并:
合并过程详解:
比较 3 和 2:2 < 3,取 2
结果:[2]
比较 3 和 4:3 < 4,取 3
结果:[2, 3]
比较 5 和 4:4 < 5,取 4
结果:[2, 3, 4]
比较 5 和 8:5 < 8,取 5
结果:[2, 3, 4, 5]
剩余:[8]
最终结果:[2, 3, 4, 5, 8]
最终结果¶
排序完成后,我们得到有序数组:[2, 3, 4, 5, 8]
这个例子展示了归并排序的关键特点: - 分治法:将问题分解为更小的子问题 - 递归:对子问题应用相同的排序算法 - 合并:将已排序的子数组合并成一个更大的有序数组 - 稳定性:相等元素的相对顺序在排序后保持不变
动画演示¶
练习题¶
- 实现归并排序的原地(in-place)版本,减少空间复杂度
- 分析归并排序在链表上的实现与数组实现的区别
- 比较归并排序和快速排序的性能差异
- 实现自底向上的非递归归并排序