时间复杂度 O(nlogn)!
过程:
利用递归与分治的技术将数据序列划分为越来越小的半子表,再对半子表排序,最后再用递归方法将排好序的半子表合并成越来越大的有序序列。
public class MergeSort {
public static void mergeSort(int[] arr){
if(arr == null || arr.length < 2 ){ //检验数组合法性
return;
}
makeProcess(arr,0,arr.length-1);
}
public static void makeProcess(int[] arr,int L,int R){
if(L == R){
return; //如果相等,当前只剩一个数,直接返回,顺序执行下面的代码。
}
// int mid = (L + R) >> 1; //效果是(L+R)/2,但是存在L+R溢出的可能,这种写法不安全;所以用L+(R-L)/2不会溢出
int mid = L + ((R - L) >> 1); //位运算比算术运算快,但是右移在负数为奇数时候和除以2是不一样的
makeProcess(arr, L, mid); //对数组左半边进行排序
makeProcess(arr, mid+1, R); //对数组右半边进行排序
merge(arr,L,mid,R); //左右两边分别有序后,整体排序,这里是外排
}
public static void merge(int[] arr,int L,int mid,int R){
int[] help = new int[R - L + 1]; //辅助数组,用来存储排好序的元素
int i= 0;
int p1 = L;
int p2 = mid + 1;
while(p1 <= mid && p2 <= R){
help[i++] = arr[p1] > arr[p2] ? arr[p2++] : arr[p1++]; //将更小的元素放入help中
}
//下面的越界情况只会发生一种,不会两种都发生
while(p1 <= mid){ //右边已经全部放入help中,将左边剩下的放入
help[i++] = arr[p1++];
}
while(p2 <= R){ //左边已经全部放入help中
help[i++] = arr[p2++];
}
//将help数组赋给原数组,使原数组有序
for(int j=0;j<help.length;j++){
arr[L + j] = help[j];
// System.out.print(arr[j] + ",");
}
}
public static void main(String[] args) {
int[] arr = {8,4,3,9,6,7};
mergeSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
}
}
额外空间复杂度是O(N)!
可以变成O(1),但是非常难,不需要掌握,可以搜“归并排序内部缓存法”!