自顶向下归并排序

一 算法

1 归并排序示意图

2原地归并排序轨迹

3 自顶向下的归并排序中归并结果轨迹

4 改进了小规模数组排序方法后的自顶向下的归并排序的可视化轨迹

二 代码

package sort;

import common.StdIn;
import common.StdOut;

/**
 * @className: Merge
 * @description: 自顶向下的归并排序
 * @date: 2021/2/27
 * @author: cakin
 */
public class Merge {

    public Merge() {
    }

    /**
     * 功能描述:原地归并
     *
     * @param a   待排序数组
     * @param aux 辅助数字
     * @param lo  下界
     * @param mid 下界和上界的中间位置
     * @param hi  上界限
     * @author cakin
     * @date 2021/2/27
     */
    private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
        // 前缀条件: a[lo .. mid] 和 a[mid+1 .. hi] 都是排好序的
        assert isSorted(a, lo, mid);
        assert isSorted(a, mid + 1, hi);

        // 初始化辅助数组
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k];
        }

        // i:左半边元素,j:右半边元素
        int i = lo, j = mid + 1;
        // 将排好序的元素放会 a 数组
        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++]; // 右半边的当前元素大于等于左半边的当前元素,取左半边元素
        }

        // 验证数组是否排好序
        assert isSorted(a, lo, hi);
    }

    /**
     * 功能描述:自顶向下的归并排序,将数组a[lo..hi]排序
     *
     * @author cakin
     * @date 2021/2/27
     * @param a   待排序数组
     * @param aux 辅助数字
     * @param lo  下界
     * @param hi  上界限
     * @return
     * @description:
     */
    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); // 归并结果
    }

    /**
     * 功能描述:自顶向下的归并排序,对a进行排序
     *
     * @author cakin
     * @date 2021/2/27
     * @param a 待排序数组
     */
    public static void sort(Comparable[] a) {
        Comparable[] aux = new Comparable[a.length];
        sort(a, aux, 0, a.length - 1);
        assert isSorted(a);
    }


    /**
     * 功能描述:v 是否小于 w
     *
     * @param v 待比较元素第一个元素
     * @param w 待比较元素第二个元素
     * @return boolean true:小于 false:大于等于
     * @author cakin
     * @date 2021/2/26
     */
    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    /**
     * 功能描述:数组的是否已排好序
     *
     * @author cakin
     * @date 2021/2/26
     * @param a 数组
     * @return boolean true:排好序 false:没排好序
     */
    private static boolean isSorted(Comparable[] a) {
        return isSorted(a, 0, a.length - 1);
    }

    /**
     * 功能描述:下标lo开始到下表hi结束的数组区间是否排好序
     *
     * @author cakin
     * @date 2021/2/26
     * @param a 数组
     * @param lo 索引的下界
     * @param hi 索引的上界
     * @return boolean true:排好序 false:没排好序
     */
    private static boolean isSorted(Comparable[] a, int lo, int hi) {
        for (int i = lo + 1; i <= hi; i++)
            if (less(a[i], a[i - 1])) return false;
        return true;
    }

    /**
     * 功能描述:打印数组
     *
     * @author cakin
     * @date 2021/2/26
     * @param a 待打印的数组
     */
    private static void show(Comparable[] a) {
        for (int i = 0; i < a.length; i++) {
            StdOut.println(a[i]);
        }
    }

    /**
     * 功能描述:自顶向下的归并排序测试
     *
     * @author cakin
     * @date 2021/2/27
     * @param
     * @return
     * @description:
     */
    public static void main(String[] args) {
        String[] a = StdIn.readAllStrings();
        Merge.sort(a);
        show(a);
    }
}

三 测试

F:\Algorithm\target\classes>java sort.Merge < tiny.txt
A
E
E
L
M
O
P
R
S
T
X


F:\Algorithm\target\classes>java sort.Merge < words3.txt
all
bad
bed
bug
dad
dim
dug
egg
fee
few
for
gig
hut
ilk
jam
jay
jot
joy
men
nob
now
owl
rap
sky
sob
tag
tap
tar
tip
wad
was
wee
yes
yet
zoo

四 说明

自顶向下归并排序的时间复杂度和NlgN成正比。

五 各种排序算法性能测试

1 代码

package sort;


import common.StdOut;
import common.StdRandom;
import common.Stopwatch;


/**
* @ClassName: SortCompare
* @Description: 各种排序算法性能测试
* @Date: 2021/2/26
* @Author: cakin
*/
public class SortCompare {
    /**
     * 功能描述:算法alg使用的时间
     *
     * @param alg 算法名称
     * @param a   数组
     * @return double 算法使用时间
     * @author cakin
     * @date 2021/2/26
     */
    public static double time(String alg, Comparable[] a) {
        Selection selection = new Selection();
        Insertion insertion = new Insertion();
        Shell shell = new Shell();
        Merge merge = new Merge();


        Stopwatch timer = new Stopwatch();
        if (alg.equals("Selection")) {
            selection.sort(a);
        }
        if (alg.equals("Insertion")) {
            insertion.sort(a);
        }
        if (alg.equals("Shell")) {
            shell.sort(a);
        }
        if (alg.equals("Merge")) {
            merge.sort(a);
        }


        return timer.elapsedTime();
    }


    /**
     * 功能描述:使用 alg 将T个长度为N的数组排序
     *
     * @param alg 算法
     * @param N   数组长度
     * @param T   进行N次排序
     * @return 排序总时长
     * @author cakin
     * @date 2021/2/26
     */
    public static double timeRandomInput(String alg, int N, int T) {
        double total = 0.0;
        Double[] a = new Double[N];
        for (int t = 0; t < T; t++) {
            // 进行一次测试(生成一个数组并排序)
            for (int i = 0; i < N; i++) {
                a[i] = StdRandom.uniform();
            }
            total += time(alg, a);
        }
        return total;
    }


    /**
     * 功能描述:比较各种排序算法的性能
     *
     * @param args 命令行
     * @author cakin
     * @date 2021/2/26
     */
    public static void main(String[] args) {
        String alg1 = "Selection"; // 选择排序
        String alg2 = "Insertion"; // 插入排序
        String alg3 = "Shell"; // 希尔排序
        String alg4 = "Merge"; // 自顶向下归并排序
        int N = 1000;
        int T = 1000;
        double t1 = timeRandomInput(alg1, N, T); // Selection的总时间
        double t2 = timeRandomInput(alg2, N, T); // Insertion的总时间
        double t3 = timeRandomInput(alg3, N, T); // Shell的总时间
        double t4 = timeRandomInput(alg4, N, T); // Merge的总时间


        StdOut.printf("For %d random Doubles  %s is %.2f \n", N, alg1, t1);
        StdOut.printf("For %d random Doubles  %s is %.2f\n", N, alg2, t2);
        StdOut.printf("For %d random Doubles  %s is %.2f\n", N, alg3, t3);
        StdOut.printf("For %d random Doubles  %s is %.2f \n", N, alg4, t4);
    }
}

2 测试结果 

For 1000 random Doubles  Selection is 1.54
For 1000 random Doubles  Insertion is 1.68
For 1000 random Doubles  Shell is 0.20
For 1000 random Doubles  Merge is 0.45

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值