归并排序遵循分治原则先将数组不断的递归二分打散,打散后再进行二二组合。原理如下数组:
分[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]
治:[2,1],[4,3],6,5],[8,7]
治:[4,3,2,1],[8,7,6,5]
治:[8,7,6,5,4,3,2,1]
如图所示,分治过程中先分后治,这里我们就用到了递归。所以他的空间需求较大。并且在该算法中还含有一个用来记录位置的缓存数组。
排序时间复杂度为:Nlog2N。
/** * 归并排序 * @author DHH * */ public class Select extends Example { /** * 归并排序 */ //缓存数组用来排序的时候存储排序前的位置。 private static Comparable[] b; /** * 排序方法,对外接口 */ public void sort(Comparable[] a){ b=new Comparable[a.length]; sort( a,0,a.length-1); } /** * 分治中的分方法,并且递归安排好治的顺序 * @param a * @param lo * @param hi */ public void sort(Comparable[] a,int lo,int hi){ int mid=(hi+lo)/2; if(hi<=lo) return; //mid+1为起步,因为两位数的时候java向下取整,会有mid=lo的情况,无限递归。 sort(a,lo,mid); sort(a,mid+1,hi); sort(a,lo,mid,hi); } /** * 分治中的治方法, * @param a * @param lo * @param hi */ public void sort(Comparable[] a,int lo,int mid,int hi){ //mid必须是+1为起步,因为数组只有两位数时mid可能会等于lo,有相同数字相比的情况,无法正常排序。 int i=lo; int j=mid+1; //迁移数组 for(int k=lo;k<=hi;k++){ b[k]=a[k]; } for(int k=lo;k<=hi;k++){ // if(i>mid){ a[k]=b[j++]; }else if(j>hi){ a[k]=b[i++]; }else if(b[i].compareTo(b[j])>0){ a[k]=b[i++]; }else{ a[k]=b[j++]; } } } /** * 测试方法 * @param args */ public static void main(String[] args) { DATA[] dataArray=new DATA[15]; dataArray[0]=new DATA(16); dataArray[1]=new DATA(6); dataArray[2]=new DATA(15); dataArray[3]=new DATA(8); dataArray[4]=new DATA(11); dataArray[5]=new DATA(23); dataArray[6]=new DATA(75); dataArray[7]=new DATA(4); dataArray[8]=new DATA(11); dataArray[9]=new DATA(60); dataArray[10]=new DATA(71); dataArray[11]=new DATA(24); dataArray[12]=new DATA(56); dataArray[13]=new DATA(31); dataArray[14]=new DATA(42); System.out.println(Arrays.toString(dataArray)); Select select=new Select(); select.sort(dataArray); System.out.println(Arrays.toString(dataArray)); } }