java中Arrays.sort()实现原理 - Go语言中文社区

java中Arrays.sort()实现原理


先在网上找到一些说法:

        java中Arrays.sort使用了两种排序方法,快速排序和优化的合并排序。

        快速排序主要是对哪些基本类型数据(int,short,long等)排序, 而合并排序用于对对象类型进行排序。
        使用不同类型的排序算法主要是由于快速排序是不稳定的,而合并排序是稳定的。这里的稳定是指比较相等的数据在排序之后仍然按照排序之前的前后顺序排列。对于基本数据类型,稳定性没有意义,而对于对象类型,稳定性是比较重要的,因为对象相等的判断可能只是判断关键属性,最好保持相等对象的非关键属性的顺序与排序前一直;另外一个原因是由于合并排序相对而言比较次数比快速排序少,移动(对象引用的移动)次数比快速排序多,而对于对象来说,比较一般比移动耗时。

        补充一点合并排序的时间复杂度是n*logn, 快速排序的平均时间复杂度也是n*logn,但是合并排序的需要额外的n个引用的空间 ......


自定义比较接口:

sort(T[] a, Comparator<? super T> c)

class Dog{  
    int size;  
    int weight;  
   
    public Dog(int s, int w){  
        size = s;  
        weight = w;   
    }  
}  
   
class DogSizeComparator implements Comparator<Dog>{  
   
    @Override  
    public int compare(Dog o1, Dog o2) {  
        return o1.size - o2.size;  
    }  
}  
   
class DogWeightComparator implements Comparator<Dog>{  
   
    @Override  
    public int compare(Dog o1, Dog o2) {  
        return o1.weight - o2.weight;  
    }  
}  
   
public class ArraySort {  
   
    public static void main(String[] args) {  
        Dog d1 = new Dog(2, 50);  
        Dog d2 = new Dog(1, 30);  
        Dog d3 = new Dog(3, 40);  
   
        Dog[] dogArray = {d1, d2, d3};  
        printDogs(dogArray);  
   
        Arrays.sort(dogArray, new DogSizeComparator());   
        printDogs(dogArray);  
   
        Arrays.sort(dogArray, new DogWeightComparator());     
        printDogs(dogArray);  
    }  
   
    public static void printDogs(Dog[] dogs){  
        for(Dog d: dogs)  
            System.out.print("size="+d.size + " weight=" + d.weight + " ");  
   
        System.out.println();  
    }  
}

为何使用"super"
        如果使用 "Comparator < T > c" 那是很简单易懂的,但是sort的第2个参数里面的 < ? super T > 意味着比较器所接受的类型可以是T或者它的超类. 为什么是超类呢? A:这允许使用同一个比较器对不同的子类对象进行比较。

基本类型源码:

/**
     * Sorts the specified array into ascending numerical order.
     *
     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
     * offers O(n log(n)) performance on many data sets that cause other
     * quicksorts to degrade to quadratic performance, and is typically
     * faster than traditional (one-pivot) Quicksort implementations.
     *
     * @param a the array to be sorted
     */
    public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

从名字可见的确是快排。

对象类型源码:

 public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
    }

ComparableTimSort.sort:

static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;

        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) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi);
            binarySort(a, lo, hi, lo + initRunLen);
            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.
         */
        ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
        int minRun = minRunLength(nRemaining);
        do {
            // Identify next run
            int runLen = countRunAndMakeAscending(a, lo, hi);

            // 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);
                runLen = force;
            }

            // Push run onto pending-run stack, and maybe merge
            ts.pushRun(lo, runLen);
            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;
    }

这里发现如果元素少于MIN_MERGE=32采用binarySort(二分排序);后面还有些判断bulabula,最后采用mergeForceCollapse(归并排序)。

真实情况还要看JDK版本,这里我用的是JDK8

4. 小结
与Arrays.sort()相关的信息总结如下:

  1. 通用: super 类

  2. 策略设计模式(strategy pattern);

  3. 归并排序(merge sort): 时间复杂度 n*log(n);

  4. Java.util.Collections#sort(List < T > list, Comparator < ? super T > c)与Arrays.sort 使用类似的思想.


转载于:https://my.oschina.net/liujiest/blog/671292

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_34152820/article/details/91956042
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-04-12 04:51:06
  • 阅读 ( 636 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢