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

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JavaArrays.sort()方法使用的是快速排序算法,它是一种分治算法,将一个大问题分成两个小问题,然后递归地解决这些小问题,最后将结果合并起来。快速排序的基本思想是选取一个基准元素,将数组小于基准元素的元素放在基准元素的左边,大于基准元素的元素放在基准元素的右边,然后对左右两个子数组分别进行快速排序,直到整个数组有序。在实现过程,快速排序使用了双指针的思想,即左指针和右指针,通过交换元素的位置来实现排序。快速排序的时间复杂度为O(nlogn),是一种高效的排序算法。 ### 回答2: javaarrays.sort是用来对数组进行排序的方法,其原理是基于快速排序算法实现的。快速排序算法是一种分治思想的算法,通过不断地将待排序的序列分为两个子序列,其一个子序列的所有元素都比另一个子序列的所有元素小,然后再对每个子序列分别进行排序,最终完成整个序列的排序。在具体实现时,快速排序算法采用了递归和指针技术来实现,算法的基本思路如下: 1.选取基准元素 快速排序算法的第一步是选取一个基准元素,通常情况下是在待排序序列的第一个元素或任意一个元素选择。 2.分割 选定基准元素后,将序列的其他元素分成两个部分,一部分是小于等于基准元素的元素,另一部分是大于基准元素的元素。 3.递归 递归地对小于等于基准元素的子序列和大于基准元素的子序列进行排序,直到序列被分割成只有一个元素为止。 4.合并 将所有子序列的元素合并成为一个有序序列,排序完成。 在java,由于不同类型的数组排序的实现方式不同,因此在arrays.sort方法采用了不同的底层实现算法,包括基于归并排序和基于双轴快速排序的算法。在大多数情况下,javaarrays.sort方法采用的是双轴快速排序算法,它相比于一般的快速排序算法,具有更好的性能表现。双轴快速排序算法的基本思路是在分割阶段,将待排序序列分成两部分,一部分是小于等于基准元素的元素,另一部分是大于基准元素的元素。在javaarrays.sort方法在实现双轴快速排序算法时,采用了基于三向切分的分割方法,它可以处理存在大量重复元素的数组,从而提高排序的效率。在java实现的双轴快速排序算法,对于长度小于47的子序列,会采用插入排序算法进行排序。 ### 回答3: JavaArrays.sort()方法是对一个数组进行排序的静态方法。该方法可以对含有基本数据类型和String类型的数组进行排序。排序是将一个无序的数组进行按照一定规则排序的过程。 JavaArrays.sort()方法采用了快速排序算法。具体来说,这种排序法是一种基于分治的排序算法,它采用了递归的思想,在待排序的序列选择一个元素作为基准,然后将小于基准的元素放在左侧,大于基准的元素放在右侧,最后将左侧和右侧分别快速排序之后进行合并。 快速排序算法的时间复杂度为O(nlogn),是非常高效的排序算法。JavaArrays.sort()方法默认采用的就是快速排序算法,但是在Java 7之后,如果要对基本类型的数组进行排序,由于有些排序算法更适合处理某些类型的数据,在使用Arrays.sort()方法的时候实际上会采用双轴快速排序算法。 对于String类型的数组排序,Arrays.sort()方法默认采用的是Timsort算法。Timsort算法适用于大多数实际情况,因为它能在保持与归并排序一样的稳定性和与快速排序类似的速度之间实现很好的平衡。Timsort是从归并排序和插入排序的优点发展出来的。 总之,JavaArrays.sort()方法是一种非常高效的排序算法,它采用了快速排序算法或Timsort算法来实现。对于基本类型的数组,还可以使用双轴快速排序算法进行排序。无论哪种排序算法,都能够快速地对数组进行排序,适用于各种实际场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值