清溪算法君老号 2020-04-24
归并算法是在分治的思想下,将数组递归的分为两半,分别排序后,再归并成
整个数组。所谓分治,即分而治之。
优点:对于长度为 N 的数组,无论规模多大,排序所需时间总和 NlogN 成正比。
缺点:排序所需额外空间和 N 成正比。
注意:归并排序的核心不是交换数据。
package mysort; //归并类 class Merge { //定义一个临时辅助数组 private static Comparable[] aux; //对外提供排序方法 public static void sort(Comparable[] a){ //初始化辅助数组(注意不要减1) aux=new Comparable[a.length]; sort(a,0,a.length-1); } //内部真正起到排序作用的方法 private static void sort(Comparable[] a,int lo,int hi){ //边界条件 if(hi<=lo) { return; } int mid=lo+(hi-lo)/2; //将左半边排序 sort(a,lo,mid); //将右半边排序 sort(a,mid+1,hi); //归并 merge(a,lo,mid,hi); } //归并,向上的过程 private static void merge(Comparable[] a,int lo,int mid,int hi){ //定义左右两边的游标 int i=lo,j=mid+1; //把值全部复制过去 for(int k=lo;k<=hi;k++){ aux[k]=a[k]; } //比较两边大小并输出回原数组 for(int k=lo;k<=hi;k++){ //左边输出完了,开始只取右边元素 if(i>mid) { a[k]=aux[j++]; } //右边输出完了,开始只取左边元素 else if(j>hi){ a[k]=aux[i++]; } //比较两边,此为小者在右边的情况 else if (less(aux[j],aux[i])){ a[k]=aux[j++]; } //相等或较大则取左边 else { a[k]=aux[i++]; } } } //此方法用于判断前者是否小于后者 private static boolean less(Comparable m, Comparable n){ return m.compareTo(n)<0; } //此方法用于对外提供展示方法 public static void show(Comparable[] a){ for(Comparable c:a){ System.out.print(c+" "); } } } public class demo{ public static void main(String[] args) { Integer[] a={9,5,1,1,6,5,0,8,9}; Merge.sort(a); Merge.show(a); } }
自顶向下的归并算法过程是将数组递归到底层,进行两两比较,再向上合并。
而自底向上的归并排序则直接将数组元素进行比较,然后两两归并,四四归并,八八归并,直到合成一个数组。
private static void sort(Comparable[] a){ //sz为子数组的大小:1、2、4、8、16... for(int sz=1;sz<a.length;sz+=sz){ //lo为子数组大小,可能剩下来的边角料必然小于子数组大小。 for(int lo=0;lo<a.length-sz;lo+=2*sz){ //取最小是为了防止越界,因为数组长度不一定是2的幂。 merge(a,lo,lo+sz-1,Math.min(lo+2*sz-1,a.length-1)); } } }
要知道时间复杂度只是描述一个增长趋势,复杂度为O的排序算法执行时间不一定比复杂度为O长,因为在计算O时省略了系数、常数、低阶。实际上,在对小规模数据进行排序时,n2的值实际比 knlogn+c还要小。