归并排序 (Merge Sort)
归并排序是一种稳定的排序算法,采用分治法策略,将已有序的子序列合并,得到完全有序的序列。
算法原理
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
时间复杂度
O(n log n)
空间复杂度
O(n)
稳定性
稳定
算法步骤
- 把长度为n的输入序列分成两个长度为n/2的子序列
- 对这两个子序列分别采用归并排序
- 将两个排序好的子序列合并成一个最终的排序序列
代码实现
public class MergeSort {
public static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
// 找到中点
int mid = (left + right) / 2;
// 递归排序左半部分
mergeSort(arr, left, mid);
// 递归排序右半部分
mergeSort(arr, mid + 1, right);
// 合并两个已排序的部分
merge(arr, left, mid, right);
}
}
// 合并两个已排序的子数组
private static void merge(int[] arr, int left, int mid, int right) {
// 计算两个子数组的大小
int n1 = mid - left + 1;
int n2 = right - mid;
// 创建临时数组
int[] leftArr = new int[n1];
int[] rightArr = new int[n2];
// 复制数据到临时数组
for (int i = 0; i < n1; i++) {
leftArr[i] = arr[left + i];
}
for (int j = 0; j < n2; j++) {
rightArr[j] = arr[mid + 1 + j];
}
// 合并临时数组回到原数组
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (leftArr[i] <= rightArr[j]) {
arr[k] = leftArr[i];
i++;
} else {
arr[k] = rightArr[j];
j++;
}
k++;
}
// 复制leftArr的剩余元素
while (i < n1) {
arr[k] = leftArr[i];
i++;
k++;
}
// 复制rightArr的剩余元素
while (j < n2) {
arr[k] = rightArr[j];
j++;
k++;
}
}
// 测试方法
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
System.out.println("排序前:");
printArray(arr);
mergeSort(arr, 0, arr.length - 1);
System.out.println("排序后:");
printArray(arr);
}
static void printArray(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
}
应用场景
- 外部排序:当数据量太大无法全部加载到内存时,归并排序是理想选择
- 链表排序:归并排序在链表排序中表现优异
- 稳定排序需求:当需要保持相等元素的相对顺序时
- 并行计算:归并排序的分治特性使其适合并行处理
优缺点
优点
- 稳定排序算法
- 时间复杂度稳定为O(n log n)
- 适合大数据量排序
- 适合外部排序
缺点
- 需要额外的O(n)空间
- 对于小数组,性能不如插入排序
- 不是原地排序算法