Java-排序-TimSort源码分析

从很多年前学编程,开始入手就是排序算法,直到后来工作后,还真有很多时候会用到排序,开始甚至不知道Java工具已经提供高效率排序工具(扶额),后面发现后并抽空做了以下对比,以及分析源码为什么会如此

测试代码git
自己尝试实现了常见的 冒泡、选择、插入、快速排序工具,使用随机函数和算法生成随机不重复序列,并生成 Map{“k”,randomValue}这样格式的数组,

经测试10000和100的Map数组结果如下

start.0 size.1000  生成序列结果:
303 754 140 331 711 762 252 493 760 125 619 691 102 453 275 149 420 59 41 396 46 724 332 861 923 840 557 501 104 957 
16:07:24.冒泡排序  bubbleSort   大小:1000 比较次数:499500 交换次数:251722 耗时:70Ms 
16:07:24.选择排序  selectionSort    大小:1000 比较次数:499500 交换次数:986 耗时:27Ms 
16:07:24.插入排序  insertSort   大小:1000 比较次数:9592 交换次数:83907 耗时:8Ms 
16:07:24.快速排序  quickSort    大小:1000 比较次数:13916 交换次数:663 耗时:2Ms 
16:07:24.Java timSort   大小:1000 比较次数:8664 交换次数:未知 耗时:3Ms 
start.0 size.10000  生成序列结果:
1429 8172 1958 1650 5836 8210 994 9548 9693 862 4785 3551 8649 7260 9247 5902 3907 7744 4367 9047 9690 7601 7511 5486 9838 3390 569 5769 7414 1292 
16:07:26.冒泡排序  bubbleSort   大小:10000 比较次数:49995000 交换次数:24835242 耗时:2S 3Ms 
16:07:27.选择排序  selectionSort    大小:10000 比较次数:49995000 交换次数:9992 耗时:1S 277Ms 
16:07:27.插入排序  insertSort   大小:10000 比较次数:129001 交换次数:8278414 耗时:146Ms 
16:07:27.快速排序  quickSort    大小:10000 比较次数:217793 交换次数:6663 耗时:47Ms 
16:07:27.Java timSort   大小:10000 比较次数:120410 交换次数:未知 耗时:34Ms 

TimSort快在哪里?
尝试分析java源码
java.util.TimSort

static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c) {
        if (c == null) {
            Arrays.sort(a, lo, hi);
            return;
        }

        rangeCheck(a.length, lo, hi); //边界检查
        int nRemaining  = hi - lo;
        if (nRemaining < 2)  //小数组判断 只有一个或者空数组则 已经有序
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        if (nRemaining < MIN_MERGE) { //小数组判断 默认32 2^n次方
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c); //折半插入
            return;
        }

        /**
         * March over the array once, left to right, finding natural runs,
         * extending short natural runs to minRun elements, and merging runs
         * to maintain stack invariant.
         */
        TimSort<T> ts = new TimSort<>(a, c);
        int minRun = minRunLength(nRemaining); //介于16和32间的一个数来平分arr 分区段 最小长度
        do {
            // Identify next run
            int runLen = countRunAndMakeAscending(a, lo, hi, c);//获取连续数区段个数 比如 2,5,7,9 或者 9,7,5,2

            // If run is short, extend to min(minRun, nRemaining)
            if (runLen < minRun) {//连续变化 个数 < 最小分区长度
                int force = nRemaining <= minRun ? nRemaining : minRun;//最小分区长度
                binarySort(a, lo, lo + force, lo + runLen, c); //区段 二分插入排序 O(n log n) compares, but O(n^2) movement 
                runLen = force;
            }

            // Push run onto pending-run stack, and maybe merge
            ts.pushRun(lo, runLen); //有序区段加入ts集合
            ts.mergeCollapse();

            // Advance to find next run
            lo += runLen; //接下来排序下一个区段
            nRemaining -= runLen;
        } while (nRemaining != 0);

        // Merge all remaining runs to complete sort
        assert lo == hi;
        ts.mergeForceCollapse(); //合并所有 有序区段 完成排序
        assert ts.stackSize == 1;
    }

总之,是比较繁琐的实现方式,但是有其应得的价值,除去特定的数据场景外,自己实现的排序方式往往没有TimSort的排序效率和性能高,所以,这就是很多高级Java开发要求熟悉框架源码的理由嘛

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值