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

/***
 * 归并排序(分治思想的典型应用):
 * 
 * 分为自上而下(递归)和自下而上(非递归,比较适合用链表组织的数据)的算法
 * 
 * 特点:
 * 
 * 保证将任意长度为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));
            }
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值