归并排序(1)

归并排序

归并基于递归/分治思想,与之同样基于分治思想的是快排。归并排序的特点是能保证任意长度为N的数组的排序时间复杂度都是O(NlogN)

归并排序分为两步,归并排序,我们先从归并开始说起。

归并

原地归并

将两个有序数组进行归并,我们首先会想到的就是建立一个新的数组,然后将元素一个一个放入新数组之中。但是,对于一个大数组来说,归并的次数非常多,每次都新建一个临时数组是非常糟糕的。所以我们希望能在原地进行归并。通过内存交换的手摇算法以后再说

原地归并的抽象方法

//aux是全局变量
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
        // copy to aux[]
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k]; 
        }
        // merge back to a[]
        int i = lo, j = mid+1;
        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++];
        }
    }

排序

自顶向下的归并排序Top-Down

自顶向下的归并排序是分治法思想的一个最典型的例子。不断递归,将一个数组不断细化,直到剩余数组只有一个元素。由于一个元素是一定有序的,递归回溯,变为两个分别有序的单个数组元素,将两者归并为一个含有两个元素的数组,并不断重复,直到整个数组有序。

public static void sort(Comparable[] a) {
    Comparable[] aux = new Comparable[a.length];//一次性开辟空间
    sort(a, aux, 0, a.length-1);//开始排序
}

private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
    if (hi <= lo) return;
    int mid = lo + (hi - lo) / 2;//划分中间元素
    sort(a, aux, lo, mid);
    sort(a, aux, mid + 1, hi);
    merge(a, aux, lo, mid, hi);//从两个单独元素开始归并
}

自底向上的归并排序Button-Up

自底向上的归并排序与T-P归并算法相反,BU归并算法从两个大小为1的数组开始,先两两归并,四四归并,不断翻倍。

public static void sort(Comparable[] a) {
    int n = a.length;
    Comparable[] aux = new Comparable[n];
    for (int len = 1; len < n; len *= 2) {
        for (int lo = 0; lo < n-len; lo += len+len) {
            int mid  = lo+len-1;
            int hi = Math.min(lo+len+len-1, n-1);
            merge(a, aux, lo, mid, hi);
        }
    }
}

你可能感兴趣的:(排序算法)