1. 自顶向下递归
将数组分组,在将每组进行分组,一直分下去,最后分道每组一个元素,这一个元素可以看作是有序的。然后向上归并。然后上一组在排序。排完序,在归并。一直到第一轮。
如数组:1 2 3 4 5 6 7 8
第一轮: 1 2 3 4 | 5 6 7 8 分成两组
第二轮: 1 2 | 3 4 | 5 6 | 7 8 每组在分成两组
第三轮: 1 | 2 | 3 | 4 | 5 | 6| 7 | 8 每组在分成两组
每轮分组的时间复杂度都为O(logn), 而每组的排序的时间复杂度为O(n), 综合时间复杂度为O(nlog), 每组排完序之后,向上归并。分组的过程是递归的
需要注意的地方
1. 归并排序是以空间换时间的方式排序。除了原数组外,还的为每一个分组提供一个辅助数组。
2. 边界问题,要规定好左中右三个边界,即是三个数组的索引值。这里指定l=0(left), mid 数组中间位置的前一个位置。r=数组的长度-1(right)
3. 归并排序最重要的地方是制定三个索引值,即每组的的起始索引,为i,j。还有就是当前分组的父分组的起始索引k。
代码:
package com.fgy.learn;
/**
* Created by snow_fgy on 2019/4/5.
*/
public class MergeSort2 {
//获取随机数组
public int[] getReadom(int n, int random) {
int [] a = new int[n];
for (int i = 0; i < n; i++){
a[i] = (int) (Math.random() * random);
}
return a;
}
public void mergeSort(int [] arr) {
mergeSortInner(arr, 0, arr.length - 1);
// for (int i : arr) {
// System.out.print(i + " ");
// }
// System.out.println();
}
//进行递归后分组,分组完毕后进行归并
private void mergeSortInner(int [] arr, int l, int r) {
//做左边界已经大于等于一个分组的有边界了,证明现在的分组为一个元素,则往下已经分不了组和归并了,则排序完成。
/**
if (r-l <= 10) {
insertSort2(arr);
return;
}
/
if (l >= r) {
return;
}
//获取中间位置
int mid = (l + r) / 2;
mergeSortInner(arr, l, mid);
mergeSortInner(arr, mid + 1, r);
//分组完毕,开始归并
/**优化:
*if(arr[mid] > arr[mid+1]) {
* merge(arr,l, mid, r);
*}
*/
merge(arr,l, mid, r);
}
private void merge(int [] arr, int l, int mid, int r){
//创建辅助数组
int [] aux = new int[r-l+1];
//为辅助数组赋值
for (int i = l; i <= r; i++){
aux[i-l] = arr[i];
}
//三个索引值
int i = l;
int j = mid + 1;
for (int k = l; k <= r; k++) {
//判断边界
if (i > mid) {
arr[k] = aux[j-l];
j++;
} else if (j > r) {
arr[k] = aux[i-l];
i++;
} else if (aux[i-l] < aux[j-l]) {
arr[k] = aux[i-l];
i++;
} else {
arr[k] = aux[j-l];
j++;
}
}
}
public void shellSort(int [] a){
int temp;
int j;
for (int increment = a.length / 2; increment > 0; increment /= 2) {
for (int i = increment; i < a.length; i ++) {
temp = a[i];
for (j = i - increment; j >= 0; j -= increment) {
if (temp < a[j]) {
a[j + increment] = a[j];
}else {
break;
}
}
a[j + increment] = temp;
}
}
// for (int i : a) {
// System.out.print(i + " ");
// }
// System.out.println();
}
public void insertSort2(int [] a){
for (int i = 1; i < a.length; i++) {
int temp = a[i];
for (int j = i; j > 0 && a[j] > a[j-1]; j--) {
a[j] = a[j-1];
}
a[i] = temp;
}
// for (int i : a) {
// System.out.print(i + " ");
// }
// System.out.println();
}
public static void main(String[] args) {
MergeSort2 sort = new MergeSort2();
Sort sort1 = new Sort();
int[] arr = sort.getReadom(1000, 10000);
int[] arr2 = arr.clone();
int[] arr3 = arr.clone();
long time1 = System.currentTimeMillis();
sort.mergeSort(arr);
long time2 = System.currentTimeMillis();
System.out.println("mergeSort: " + (time2 - time1) / 1000.0 + "s");
sort.insertSort2(arr2);
long time3 = System.currentTimeMillis();
System.out.println("insertSort2: " + (time3 - time2) / 1000.0 + "s");
sort.shellSort(arr3);
long time4 = System.currentTimeMillis();
System.out.println("shellSort: " + (time4 - time3) / 1000.0 + "s");
}
}