1.原理
归并排序采用的是分治算法, 将已有的子序列合并, 得到完全有序的序列; 即先使每个子序列有序, 再使子序列段间有序. 若将两个有序表合并成一个有序表, 称为二路归并.
执行流程:
1. 不断地将当前序列平均分割成2个子序列
直到不能再分割(即序列中只剩1个元素)
2. 不断地将2个子序列合并成一个有序序列
直到最终只剩下1个有序序列
2.代码实现
要将两个排好序的子序列合并成一个子序列的方法: 每次都是从未比较的两个子序列的最小值中选择一个更小值
public class mergeSort{
public static void mergeSort(int[] array){
mergeSortInternal(array, 0, array.length);
}
private static void mergeSortInternal(int[] array, int low, int high){
if(low >= high-1){ //待排序区间是[low, high)
return; //递归出口
}
//这块是递归分割的过程, 将其分割到不能分割的地步然后开始合并
int mid = (low+high)/2;
mergeSortInternal(array, low, mid);
mergeSortInternal(array, mid, high);
//开始合并过程
merge(array, low, mid, high);
}
private static void merge(int[] array, int low, int mid, int high){ //合并过程
int i = low;
int j = mid;
int length = high - low;
int[] extra = new int[length]; //创建一个extra数组, 长度等于array数组长度
int k = 0;
//"下标为i<mid的区间和下标为j<high的区间"之间进行比较, 选择小的放入extra数组
while(i<mid && j<high){ //i表示具体要比较的数所对应的下标, mid表示下标的边界
//加入等于, 保证稳定性
if(array[i] <= array[j]){ //数组中具体的数进行比较
extra[k++] = array[i++]; //要将小的那个数放到extra数组中
}else{
extra[k++] = array[j++];
}
}
//将while大循环比较完之后剩余区间内(只剩余i<mid区间或j<mid区间)的元素再进行比较, 选择小的元素放到extra数组
while(i < mid){
extra[k++] = array[i++];
}
while(j <high){
extra[k++] = array[j++];
}
//从extra数组搬回array数组
for(int t = 0; t < length; t++){ //注意这里是length,代表extra数组长度,不是array数组的长度array.length
array[low + t] = extra[t]; //需要搬回原位置,从low开始
}
}
public static void main(String[] args){ //打印测试
int[] array = {5,6,13,51,8,7,4,21};
mergeSortInternal(array, 0, array.length);
for(int i = 0; i <= array.length - 1; i++){
System.out.print(array[i] + " ");
}
}
}
3.性能
时间复杂度 O(nlog(n)) 数据不敏感
空间复杂度 O(n) 数据不敏感
稳定