排序笔记_4(自上而下、自底而上的归并排序)

来源:互联网 发布:大连理工大学网络教育 编辑:程序博客网 时间:2024/05/02 02:22
/*** * 归并排序(分治思想的典型应用): *  * 分为自上而下(递归)和自下而上(非递归,比较适合用链表组织的数据)的算法 *  * 特点: *  * 保证将任意长度为N的数组排序所需的时间和NlogN成正比; * 处理有百万、千万级别的元素个数的数组不成问题。 *  * 缺点: *  * 需要的额外空间和N成正比。 *  * 改进方案: * ①对小规模的子数组使用插入排序 * ②测试数组是否有序 * (加一个判断条件,如果a[mid]小于a[mid+1],我们就认为是有序的, * 从而跳过merge()方法,这个改动不会影响递归的调用,但是运行时间就变成线性的了。) *  * 自上而下(递归): * 将一个大问题分割成小问题分别解决,然后用所有小问题的答案解决大问题的答案。 *  * 自下而上(非递归): * 先归并那些微型数组,然后再成对归并得到的子数组,直到将整个数组归并到一块。 * (基本思想:首先进行两两归并,把每个元素看成一个大小为1的子数组, * 然后是四四归并,将两个大小为2的数组归并成一个有4个元素的数组, * 然后是八八归并,一直下去。) */package com.chapter_two;/*** * 自顶向下的归并排序 *  * @author LuodiJack *  */public class Merge {    @SuppressWarnings("rawtypes")    private static Comparable[] aux;// 辅助数组    /***     * 原地归并的抽象方法: 将两个有序数组归并成更大的有序数组。     *      * @param a     *            需要归并的数组。     * @param low     *            数组的下界,实际的索引值。     * @param mid     *            数组的中部,实际的索引值。     * @param high     *            数组的上界,实际的索引值。     */    @SuppressWarnings("rawtypes")    private static void merge(Comparable[] a, int low, int mid, int high) {        int i = low;        int j = mid + 1;        for (int k = low; k <= high; k++) {            aux[k] = a[k];        }        for (int k = low; k <= high; k++) {            if (i > mid) {// 右边剩下,将右边赋值给数组。                a[k] = aux[j++];            } else if (j > high) {// 左边剩下,将左边赋值给数组。                a[k] = aux[i++];            } else if (Template.less(aux[i], aux[j])) {// 左边的小,就取左边的。                a[k] = aux[i++];            } else {// 右边的小,就取右边的。                a[k] = aux[j++];            }        }    }    /***     * 自顶向下的归并排序函数     *      * @param a     *            需要排序的数组     *      */    @SuppressWarnings("rawtypes")    public static void sort(Comparable[] a) {        aux = new Comparable[a.length];// 一次性的分配辅助空间        sort(a, 0, a.length - 1);    }    @SuppressWarnings("rawtypes")    private static void sort(Comparable[] a, int low, int high) {        if (high <= low) {            return;        }        int mid = low + (high - low) / 2;        sort(a, low, mid);// 对左边的归并排序        sort(a, mid + 1, high);// 对右边的归并排序        merge(a, low, mid, high);// 合并两边的数组    }}
package com.chapter_two;/*** * 自底而上的归并排序 *  * @author LuodiJack *  */public class MergeBU {    @SuppressWarnings("rawtypes")    private static Comparable[] aux;// 辅助数组    /***     * 原地归并的抽象方法: 将两个有序数组归并成更大的有序数组。     *      * @param a     *            需要归并的数组。     * @param low     *            数组的下界,实际的索引值。     * @param mid     *            数组的中部,实际的索引值。     * @param high     *            数组的上界,实际的索引值。     */    @SuppressWarnings("rawtypes")    private static void merge(Comparable[] a, int low, int mid, int high) {        int i = low;        int j = mid + 1;        for (int k = low; k <= high; k++) {            aux[k] = a[k];        }        for (int k = low; k <= high; k++) {            if (i > mid) {// 右边剩下,将右边赋值给数组。                a[k] = aux[j++];            } else if (j > high) {// 左边剩下,将左边赋值给数组。                a[k] = aux[i++];            } else if (Template.less(aux[i], aux[j])) {// 左边的小,就取左边的。                a[k] = aux[i++];            } else {// 右边的小,就取右边的。                a[k] = aux[j++];            }        }    }    /***     * 自底向上的归并排序函数     *      * @param a     *            需要排序的数组     *      */    @SuppressWarnings("rawtypes")    public static void sort(Comparable[] a) {// 进行两两归并        int N = a.length;        aux = new Comparable[a.length];// 一次性的分配辅助空间        for (int sz = 1; sz < N; sz = sz + sz) {// sz子数组大小            for (int low = 0; low < N - sz; low += sz + sz) {// low: 子数组索引                merge(a, low, low + sz - 1, Math.min(low + sz + sz - 1, N - 1));            }        }    }}
0 0