1.思路
将数组从中间分成前后两个数组,然后继续将前后两个数组从中间划分为更小的数组,直到分成每个数组只有一个元素,此时相当于每个数组都是有序数组,在将两个大小为1的数组合并成一个大小为2的,在把大小为2的数组合并成4的…直到全部小的数组合并起来。所以归并排序的代码其实就是一个分解数组的方法加上一个合并两个有序数组的方法。
2.图解
3.代码实现
递归:
public int[] mergeSort(int[] arr, int left, int right) {
// 如果left == right表示只有一个元素,则不用递归排序
if (left < right) {
// 把大数组分成两个数组
int mid = (left + right) / 2;
// 对左半部分进行排序
arr = mergeSort(arr, left, mid);
// 对右半部分进行排序
arr = mergeSort(arr, mid + 1, right);
// 进行合并
merge(arr, left, mid, right);
}
return arr;
}
// 合并方法,将两个有序数组合并,[left,mid]为一个数组,[mid+1,right]为另一个数组
public 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++];
// 把临时数组赋值到原数组
for (int value : temp) {
arr[left++] = value;
}
}
非递归:
public static void mergeSort2(int[] arr) {
if (arr == null || arr.length < 2) return;
int n =arr.length;
// 刚开始合并的数组是1,接着是2,接着是4....
for (int i = 1; i < n; i += i) {
int left = 0;
int mid = left + i - 1;
int right = i + mid;
while (right < n) {
merge(arr, left, right, mid);
left = right + 1;
mid = left + i - 1;
right = mid + i;
}
// 还有一些遗漏的数组没合并,因为不可能每个子数组的大小都刚好为i
if (mid < n) {
merge(arr, left, n - 1, mid);
}
}
}
4.性质
①时间复杂度:O(nlogn) ②空间复杂度:O(n) ③非原地排序 ④稳定排序