参考: https://www.bilibili.com/video/BV1Ax411U7Xx
2路归并排序:分治+合并
分治:对于n个数,我们认为每个单独的数是有序的,对于两个有序的子序列,两两归并;得到[n/2]个长度为2的有序子序列,然后再两两归并;如此重复,直到得到一个长度为n的有序序列。
合并:对于一个大序列中的两个有序子序列,按照从小到大的顺序合并(归并排序)。先拆成两个小序列,再从小到大逐一合并到原数组。
算法实现:
// 归并
public static void merge(int arr[], int l, int m, int r){
// 先拆成两个有序子序列
int leftSize = m - l;
int rightSize = r - m + 1;
int left[] = new int[leftSize];
int right[] = new int[rightSize];
for(int i=0;i<leftSize;i++){
left[i] = arr[l + i];
}
for(int i=0;i<rightSize;i++){
right[i] = arr[m + i];
}
// 归并排序
// 三个指针:i指向left数组的最小元素,j指向right数组的最小元素,k指向arr数组的最下方元素。
// 两个过程:比较填充阶段、某一个数组填充完毕后直接填充另一数组阶段
int i = 0, j = 0, k = l;
while(i < leftSize && j < rightSize){
if(left[i] < right[j]){
arr[k] = left[i];
k++;
i++;
}else{
arr[k] = right[j];
k++;
j++;
}
}
if(i != leftSize){
while(i < leftSize){
arr[k] = left[i];
k++;
i++;
}
}else{
while(j < rightSize){
arr[k] = right[j];
k++;
j++;
}
}
}
// 分治
public static void mergeSort(int arr[], int l, int r){
//递归出口,单个元素一定是有序序列。
if(l == r) return;
//递归过程:拆分后归并
//m要和归并时的m指向(归并时m指向拆分后的右边第一个元素)保持一致
int m = (l + r + 1) / 2;
mergeSort(arr, l , m-1);
mergeSort(arr, m , r);
merge(arr, l , m , r);
}
public static void main(String[] args){
int[] arr = {4,7,9,1,3,3,5,2};
mergeSort(arr, 0, arr.length-1);
for(int i:arr){
System.out.println(i);
}
}