归并排序

117 阅读2分钟
package sort;


import utils.Utils;

import java.lang.reflect.Array;
import java.util.Arrays;

public class MergeSort{

    public <T extends Comparable<T>> void sort(T[] arr) {
        sort(arr,0,arr.length-1);
    }

    private <T extends Comparable<T>> void sort(T[] arr, int l, int r) {

        //finalConditon
        if (l==r)
            return;

        int mid=l+(r-l)/2;
        sort(arr,l,mid);
        sort(arr,mid+1,r);

        //左半部分、右半部分分别排序好。然后合并
        merge(arr,l,mid,r);
    }
    private <T extends Comparable<T>>  void merge(T[] arr, int l, int mid, int r) {
        /* 复制一份数组,设置三个索引位置。logN merge完成*/
        int i=l;
        int j=mid+1;
        T[] arr1=Arrays.copyOf(arr,arr.length);

        /* doesnt work because Object cant cast to Comparable,T is a Comparable */ //this way works:T[] arr1=(T[]) Array.newInstance(arr.getClass().getComponentType(),arr.length);

        //T[] arr1= (T[])new Object[arr.length];
        System.arraycopy(arr,0,arr1,0,arr.length);

        for (int k = l; k <=r; k++) {
            if (i>mid){
                arr[k]=arr1[j++];
            }
            else if (j>r)
                arr[k]=arr1[i++];

            else if (arr1[i].compareTo(arr1[j])<0)
                arr[k]=arr1[i++];
            else
                arr[k]=arr1[j++];
        }

    }

    public static void main(String[] args) {
        Integer[] arr= Utils.generateIntArray(1000);
        System.out.println(Arrays.toString(arr)
        );
        new MergeSort().sort(arr);
        System.out.println(Arrays.toString(arr)
        );

    }
}

归并的改进点:

当需要排序的数组<=15时候,使用插入排序。这点改进将会给排序带来巨大的提升。说明算法没有好坏,每个算法都有其用武之地。根据不同的数量级确定不同的算法。

10000个数据排序的耗时对比:sort.MergeSortTime:110、sort.MergeSortPlusWithInsertionTime:7

//finalConditon
        /*if (l==r)
            return;*/
        if ((r-l)<=15){
            for (int i = l+1; i < r+1; i++) {
                for (int j=i;j>l&&arr[j].compareTo(arr[j-1])<0;j--){
                    swap(arr,j,j-1);
                }
            }
            return;
        }

自下而上的归并排序

以上归并算法依赖于数组的下标随机访问,但是如果需要排序的数据不是数组,而是链表,就需要另一种归并方式。

  @Override
    public <T extends Comparable<? super T>> void sort(T[] arr) {
        for (int sz=1;sz<=arr.length;sz=sz*2){
            //按顺序把sz个元素分别排序。
            // 处理两处边界越界问题。1、i+sz-1 要小于n-1;2、(i+sz+sz-1)<n-1;
            for (int i=0;i<arr.length;i=i+sz+sz-1){
                merge(arr,i,i+sz-1,Math.min(i+sz+sz-1,arr.length-1));
            }
        }
    }