您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java如何实现归并排序算法
## 一、归并排序概述
归并排序(Merge Sort)是一种基于**分治法**(Divide and Conquer)的高效排序算法,由约翰·冯·诺伊曼在1945年首次提出。其核心思想是将原始数组递归地分成两半,分别排序后再合并成一个有序数组。时间复杂度稳定为O(n log n),是处理大规模数据时的优选算法之一。
### 算法特点
- **稳定性**:保持相等元素的原始顺序
- **空间复杂度**:O(n)(需要额外存储空间)
- **适用场景**:链表排序、外部排序(大数据文件)
## 二、算法实现步骤
### 1. 分解阶段
将当前数组从中间位置分成左右两个子数组,递归地对子数组进行分解,直到每个子数组只包含一个元素(天然有序)。
```java
void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2; // 防止整数溢出
mergeSort(arr, left, mid); // 递归左半部分
mergeSort(arr, mid + 1, right); // 递归右半部分
merge(arr, left, mid, right); // 合并已排序的子数组
}
}
将两个已排序的子数组合并为一个有序数组:
void merge(int[] arr, int left, int mid, int right) {
// 创建临时数组
int[] temp = new int[right - left + 1];
int i = left; // 左子数组起始索引
int j = mid + 1; // 右子数组起始索引
int k = 0; // 临时数组索引
// 比较两个子数组元素
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 复制剩余元素
while (i <= mid) temp[k++] = arr[i++];
while (j <= right) temp[k++] = arr[j++];
// 将临时数组拷贝回原数组
System.arraycopy(temp, 0, arr, left, temp.length);
}
public class MergeSort {
public static void sort(int[] arr) {
if (arr == null || arr.length < 2) return;
mergeSort(arr, 0, arr.length - 1);
}
private static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 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[] temp = new int[right - left + 1];
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
}
while (i <= mid) temp[k++] = arr[i++];
while (j <= right) temp[k++] = arr[j++];
System.arraycopy(temp, 0, arr, left, temp.length);
}
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7};
System.out.println("排序前: " + Arrays.toString(arr));
sort(arr);
System.out.println("排序后: " + Arrays.toString(arr));
}
}
当子数组规模较小时(通常n < 15),插入排序的实际性能更好:
private static final int INSERTION_THRESHOLD = 7;
private static void mergeSort(int[] arr, int left, int right) {
if (right - left <= INSERTION_THRESHOLD) {
insertionSort(arr, left, right);
return;
}
// ...原有逻辑
}
在递归过程中复用同一个临时数组:
public static void sort(int[] arr) {
int[] temp = new int[arr.length];
mergeSort(arr, 0, arr.length - 1, temp);
}
如果左半部分最大值 <= 右半部分最小值,则无需合并:
if (arr[mid] <= arr[mid + 1]) return;
指标 | 值 |
---|---|
时间复杂度 | O(n log n) |
空间复杂度 | O(n) |
稳定性 | 稳定 |
最佳情况 | O(n log n) |
最差情况 | O(n log n) |
算法 | 平均时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|
快速排序 | O(n log n) | O(log n) | 不稳定 |
堆排序 | O(n log n) | O(1) | 不稳定 |
归并排序 | O(n log n) | O(n) | 稳定 |
Arrays.sort()
对对象数组的排序采用TimSort(归并排序的优化变种)因为合并过程需要临时存储两个子数组的元素,无法在原数组上直接交换。
使用迭代代替递归,从大小为1的子数组开始两两合并:
public static void bottomUpMergeSort(int[] arr) {
int n = arr.length;
int[] temp = new int[n];
for (int size = 1; size < n; size *= 2) {
for (int left = 0; left < n - size; left += 2 * size) {
int mid = left + size - 1;
int right = Math.min(left + 2 * size - 1, n - 1);
merge(arr, left, mid, right, temp);
}
}
}
归并排序凭借其稳定的O(n log n)时间复杂度,成为处理大规模数据的重要工具。虽然需要额外空间,但其清晰的实现逻辑和优秀的稳定性使其在诸多场景下不可替代。理解归并排序不仅有助于掌握分治思想,也为学习更复杂的算法(如外部排序、MapReduce等)奠定了基础。 “`
文章共计约1650字,包含: 1. 算法原理说明 2. 分步骤代码实现 3. 完整可运行示例 4. 多种优化方案 5. 复杂度分析 6. 实际应用场景 7. 常见问题解答 8. 格式化的对比表格 所有代码均采用Java语法实现并附带详细注释。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。