一句话概括归并排序算法:通过二分法将一组数据不断分割至最底层一个,然后依次从最底层向上每两组使用归并排序排出来。
归并排序算法步骤分两步(结合上图):1.是不断划分(二分法) 2.不断把划分后的数据一步步归并起来(方法是:先复制得到相同一个数组,建立三个指针,两个在二分的新数组中,一个在原数组里指定接下来要修改的位置,通过比较两指针的数字决定放谁到上面那个指针里)
复杂度:O(n log n)
先展示显示排序算法所需的测试类:
import java.lang.reflect.Method;
public class SortTestHelper {
public static void testSort(String sortClassName,Comparable[] arry)
{
try {
//告诉类名即可获取class对象
Class sortClass = Class.forName(sortClassName);
//指明方法名和参数列表就可以获取
//getDeclaredMethod()获取的是类自身声明的所有方法,包含public、protected和private方法。
//getMethod()获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。
Method sortMethod = sortClass.getDeclaredMethod("sort", new Class[]{Comparable[].class});
Object[] params = new Object[]{arry};
long startTime = System.currentTimeMillis();
//第一个参数是调用哪个对象实例的此方法,静态就写null,第二个为方法参数
sortMethod.invoke(null, params);
long overTime = System.currentTimeMillis();
System.out.println("耗时:"+(overTime-startTime+" ms!"));
judgeSorted(arry);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void judgeSorted(Comparable[] arry) {
for (int i = 0; i < arry.length-1; i++) {
if(arry[i].compareTo(arry[i+1])<0)
{
System.out.println("排序失败!");
return;
}
}
System.out.println("排序成功!");
}
public static void print(Object[] data) {
int n = data.length;
for(int i=0;i<n;i++)
{
System.out.print(data[i]+"--");
}
System.out.println();
}
public static Integer[] generateRandomArray(int n,int min, int max){
assert min>max;
Integer[] data = new Integer[n];
for (int i = 0; i < data.length; i++) {
data[i] = new Integer((int)Math.random()*(max-min+1)+min);
}
return data;
}
}
1.版本一:
public class MergeSort {
public static void sort(Comparable[] data,int l,int r){
int mid = (r-l)/2+l;
if(l>=r)
return;
sort(data,l,mid);
sort(data,mid+1,r);
MergeSort(data,l,r);
}
public static void sort(Comparable[] data){
sort(data,0,data.length-1);
}
private static void MergeSort(Comparable[] data, int l, int r) {
Comparable[] dataCopy = new Comparable[r-l+1];
for (int i = 0; i < dataCopy.length; i++) {
dataCopy[i] = data[l+i];
}
int mid = (l+r)/2;
int i=l,j=mid+1,k=l;
for (; k < dataCopy.length; k++) {
if(i>mid)
{
data[k]=dataCopy[j-l];
j++;
}
else if(j>r){
data[k]=dataCopy[i-l];
i++;
}
else{
if(dataCopy[i].compareTo(dataCopy[j])==1){
data[k]=dataCopy[j-l];
j++;
}
else if(dataCopy[i].compareTo(dataCopy[j])==-1){
data[k]=dataCopy[i-l];
i++;
}
}
}
}
}
2.优化一:
排序已经有序的数据,会发现插入排序(插入排序这时候会退化为 n 级别)比归并排序快很多。思考得出,可以把最后那个归并前进行if判断,如果arr[mid]>arr[mid+1]时才要进行归并!
public static void sort(Comparable[] data,int l,int r){
int mid = (r-l)/2+l;
if(l>=r)
return;
sort(data,l,mid);
sort(data,mid+1,r);
if(data[mid]>data[mid+1])
MergeSort(data,l,r);
}
3.优化二:当数据比较小的时候使用插入排序较好
public static void sort(Comparable[] data,int l,int r){
int mid = (r-l)/2+l;
if(r-l<15){
insertSort(arr,l,r);
return;
}
sort(data,l,mid);
sort(data,mid+1,r);
if(data[mid]>data[mid+1])
MergeSort(data,l,r);
}