public class MergeSort {
/**
* 归并排序,归并array[l,r]
* @param array
* @param l
* @param r
*/
public static void mergeSort(int array[] ,int l,int r){
if(l>=r){
return ;
}
int mid = (l+r)/2;
//双路归并
mergeSort(array, l, mid);
mergeSort(array, mid+1, r);
//归并,使array[l,mid]与array[mid+1,r]两部分合并为一个有序的数组:array[l,r]
merge(array,l,mid,r);
}
/**
* 合并有序数组array[l,mid]与array[mid+1,r]为一个有序的数组:array[l,r]
* @param array
* @param l
* @param mid
* @param r
*/
private static void merge(int[] array, int l, int mid, int r) {
//暂存待合并的数组aux[0,r]=array[l,r];
int[] aux = Arrays.copyOfRange(array, l, r+1);
int i=l,j=mid+1;//两个有序数组的起始值分别为i,j
//对array的[l,r]重新赋值,形成有序数组
for(int k=l;k<=r;k++){
//第一个有序数组的元素已经全部在array里排好,将第二个数组的元素全部依次赋值
if(i>mid){
array[k]=aux[j-l];j++;
}else if(j>r){//第二个有序数组array[mid+1,r]的元素已经全部在array里排好,将第一个数组的元素全部依次赋值
array[k]=aux[i-l];i++;
}else if(aux[i-l]<aux[j-l]){//将两个有序数组中小的值重新赋值给对应的array[k]
array[k]=aux[i-l];i++;
}else{
array[k]=aux[j-l];j++;
}
}
}
public static void main(String[] args) {
int[] array = new int [10];
for(int i=0;i<10;i++){
array[i]=(int)(Math.random()*10);
}
mergeSort(array, 0, array.length-1);
System.out.println(Arrays.toString(array));
}
}
2.优化思路1:在归并两个已经有序的数组的时候,应该先判断arr[l...mid]的最大的元素与arr[mid+1...r]的最小的元素的大小,即判断arr[mid]与arr[mid+1]的大小,前者小于后者这说明两个有序数组不用再归并就已经有序了。
优化思路2:随着归并 的进行,整个数组越来越有序,而插入排序在数组近乎有序的时候几乎可以退化为O(n)级别的排序,所以可以当数组规模小到一定程度的时候,采用插入排序,就可以加快排序速度。
package com.cl.mergesort;
import com.cl.insertsort.InsertionSort;
import com.cl.utils.SortTestHelper;
public class MergeSort {
public static void sort(Comparable[] arr){
__mergeSort(arr,0,arr.length-1);
}
/**
* 对arr[l...r]的范围进行排序
* @param arr
* @param l
* @param r
*/
private static void __mergeSort(Comparable[] arr, int l, int r) {
/* if(l>=r){//处理的出局为1个或空
return ;
}*/
//优化2:规模只需要处理16个元素
if(r-l<=15){
InsertionSort.sort(arr,l,r);
return ;
}
//l+r可能会溢出
int mid = (l+r)/2;
__mergeSort(arr,l,mid);
__mergeSort(arr,mid+1,r);
//优化1:arr[mid]<arr[mid+1]说明已经有序了,不用再归并
if(arr[mid].compareTo(arr[mid+1])>0)
__merge(arr,l,mid,r);
}
/**
* 将arr[l...mid]与arr[mid+1...r]归并
* @param arr
* @param l
* @param mid
* @param r
*/
private static void __merge(Comparable[] arr, int l, int mid, int r) {
Comparable[] aux = new Comparable[r-l+1];
/* for(int i=l;i<=r;i++){
aux[i-l]=arr[i];
}*/
System.arraycopy(arr,l,aux,0,(r-l+1));
int i=l,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].compareTo(aux[j-l])<0){
arr[k]=aux[i-l];
i++;
}else{
arr[k]=aux[j-l];
j++;
}
}
}
public static void main(String[] args) {
int n = 50000;
/*Integer[] arr = SortTestHelper.generateRandomArray(n,0,n);
Integer[] arr2 = SortTestHelper.copyIntArray(arr);
SortTestHelper.testSort("com.cl.mergesort.MergeSort",arr);
SortTestHelper.testSort("com.cl.insertsort.InsertionSort",arr2);
*/
Integer[] arr = SortTestHelper.generateNearlyOrderedArray(n,10);//产生近乎有序的数组
Integer[] arr2 = SortTestHelper.copyIntArray(arr);
SortTestHelper.testSort("com.cl.mergesort.MergeSort",arr);
SortTestHelper.testSort("com.cl.insertsort.InsertionSort",arr2);
}
}