思路
将数组对半分到长度为 1 为止,再逆向合并,合并的过程中进行排序。将轮数减少到了 logn。
代码
public class MergeSort{
public static void mergeSort(int[] arr){
mergeSort(arr, 0, arr.length - 1);
}
private static void mergeSort(int[] arr, int start, int end) {
if(start < end){
int mid = (start + end) >>> 1;
mergeSort(arr, start , mid);
mergeSort(arr, mid + 1, end);
merge(arr, start, mid, end);
}
}
private static void merge(int[] arr, int start, int mid, int end) {
int[] tmp = new int[end - start + 1];
int p1 = start, p2 = mid + 1, p = 0;
while(p1 <= mid && p2 <= end)
tmp[p ++] = arr[p1] <= arr[p2] ? arr[p1 ++] : arr[p2 ++];
while(p1 <= mid)
tmp[p++] = arr[p1++];
while(p2 <= end)
tmp[p++] = arr[p2++];
for(int i = 0; i < tmp.length; i++)
arr[start + i] = tmp[i];
}
public static void main(String[] args){
int[] array ={5,8,6,3,9,4,2,1,7};
mergeSort(array);
System.out.println(Arrays.toString(array));
}
}
复杂度分析
时间复杂度
轮数为 logn,每一轮都要对整个数组进行操作(虽然分成了很多小块,但合起来就是整个数组),时间复杂度 O(nlogn)。最好最坏,情况不变。
空间复杂度
单次归并操作开辟的最大空间是 n(最后一次),空间复杂度O(n)。
以前创建的空间会随归并结束而释放。
稳定性分析
稳定
while(p1 <= mid && p2 <= end) {
//下面是 <= 就会稳定,如果只是 < 就不稳定了
if (arr[p1] <= arr[p2])
tmp[p++] = arr[p1++];
else
tmp[p++] = arr[p2++];
}
优势
与快速排序相比,稳定,时间复杂度保持在 O(nlogn)
是外部排序法,数据量太大,无法直接在内存内排序,可以依赖外部存储设备。
适用场景
需要稳定性,数据量大