归并排序(1)

来源:互联网 发布:胡适知乎 编辑:程序博客网 时间:2024/05/22 03:33

归并排序

归并基于递归/分治思想,与之同样基于分治思想的是快排。归并排序的特点是能保证任意长度为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);        }    }}
原创粉丝点击