`

归并排序

阅读更多

归并排序原理:将数组二分,然后对二分后的数组继续使用归并排序...当分解后数组元数足够小时(为1),说明每个数组已经排序好,然后将二分的数组通过某个算法合并成已经排好序的数组,直至整个数组都排序好序。

 

时间复杂度:最优O(n),最坏O(nlogn),平均O(nlogn)

 

归并排序jdk源码优化方案:

1. 当分解后的数组元素个数小于7时,改用插入排序

2. 当二分后的已经排好序的两个数组,左边的最大值小于等于右边最小值时,不需要再合并

3. 复制一份源数组,在归并两个已排序数组时,只要将源数据按顺序移到目标数组中,可以避免在同一个数组整体移动产生开销,达到线性时间,以空间换时间

 

public static final int INSERTIONSORT_THRESHOLD = 7;

 

public static <T extends Comparable<T>> int compare(T a, T b) {
    if (a == null){
        return b == null ? 0 : -1;
    }
    if (b == null){
        return 1;
    }
    return a.compareTo(b);
}

 

/**
 * @description 归并排序
 * @param src 待排数组
 * @param dest 排序后的数组
 * @param offset 开始位置
 * @param end 结束位置
 */
public static <T extends Comparable<T>> void mergeSort(T[] src, T[] dest, int offset, int end) {
    int size = end - offset;
    //当数组元素个数小于7时,插入排序性能最好
    if (size < INSERTIONSORT_THRESHOLD) {
        insertSort(dest, offset, end);
        return;
    }
    int mid = (offset + end) >>> 1;
    //递归将左半部分未排序的数据,排好序后放入源数组中
    mergeSort(dest, src, offset, mid);
    //递归将右半部分未排序的数据,排好序后放入源数组中
    mergeSort(dest, src, mid, end);
    //左边最大数比右边最小数小,说明数组已经排好序,直接拷贝到目标数组中
    if (compare(src[mid - 1], src[mid]) <= 0) {
        System.arraycopy(src, offset, dest, offset, size);
        return;
    }
    //按顺序将源数据拷贝到目标数组中
    for (int i = offset, p = i, q = mid; i < end; ++i) {
        if (q >= end || p < mid && compare(src[p], src[q]) <= 0) {
            dest[i] = src[p++];
        } else {
            dest[i] = src[q++];
        }
    }
}

/**
 * @description 归并排序
 * @param data
 */
public static <T extends Comparable<T>> void mergeSort(T[] data) {
    if (data != null && data.length > 1){
        //复制一份数组做交换空间
        T[] src = (T[]) data.clone();
        mergeSort(src, data, 0, data.length);
    }
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics