zoukankan      html  css  js  c++  java
  • Arrays.sort的粗略讲解

    排序算法,基本的高级语言都有一些提供。C语言有qsort()函数,C++有sort()函数,java语言有Arrays类(不是Array)。用这些排序时,都可以写自己的排序规则。

      Java API对Arrays类的说明是:此类包含用来操作数组(比如排序和搜索)的各种方法。

    1.对基本数据类型的数组的排序

       说明:(1)Arrays类中的sort()使用的是“经过调优的快速排序法”;

          (2)比如int[],double[],char[]等基数据类型的数组,Arrays类之只是提供了默认的升序排列,没有提供相应的降序排列方法。

          (3)要对基础类型的数组进行降序排序,需要将这些数组转化为对应的封装类数组,如Integer[],Double[],Character[]等,对这些类数组进行排序。(其实还不如先进行升序排序,自己在转为将序)。

        用默认的升序对数组排序

       函数原型:static void sort(int[] a)   对指定的 int 型数组按数字升序进行排序。

           static void sort(int[] a, int fromIndex, int toIndex)  对指定 int 型数组的指定范围按数字升序进行排序。 

    源代码解释:

     /**
         * 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
         */

    第一部分:

    首先介绍排序里面会调用的插入排序,什么时候会调用这段代码,在代码的最后面有解释

    下面我来具体讲解这段代码,INSERTION_SORT_THRESHOLD是是否采用插入排序的阈值

    代码中设置为47,当小于排序长度小于47时,调用下面这块代码

    leftmost是boolean类型,如果是true表示是从第一个位置开始往后排序,如果不是,说明是从中间任意位置开始排序

    如果leftmost是true的时候,采用最原始的插入排序方法,

    如果是false的时候,采用优化的插入排序方法,pair insertion sort,每次对两个数据进行插入,提高了效率

    /**
         * Sorts the specified range of the array by Dual-Pivot Quicksort.
         *
         * @param a the array to be sorted
         * @param left the index of the first element, inclusive, to be sorted
         * @param right the index of the last element, inclusive, to be sorted
         * @param leftmost indicates if this part is the leftmost in the range
         */

     private static void sort(int[] a, int left, int right, boolean leftmost) {
            int length = right - left + 1;

            // Use insertion sort on tiny arrays
            if (length < INSERTION_SORT_THRESHOLD) {
                if (leftmost) {
                    /*
                     * Traditional (without sentinel) insertion sort,
                     * optimized for server VM, is used in case of
                     * the leftmost part.
                     */
                    for (int i = left, j = i; i < right; j = ++i) {
                        int ai = a[i + 1];
                        while (ai < a[j]) {
                            a[j + 1] = a[j];
                            if (j-- == left) {
                                break;
                            }
                        }
                        a[j + 1] = ai;
                    }
                } else {
                    /*
                     * Skip the longest ascending sequence.
                     */
                    do {
                        if (left >= right) {
                            return;
                        }
                    } while (a[++left] >= a[left - 1]);

                    /*
                     * Every element from adjoining part plays the role
                     * of sentinel, therefore this allows us to avoid the
                     * left range check on each iteration. Moreover, we use
                     * the more optimized algorithm, so called pair insertion
                     * sort, which is faster (in the context of Quicksort)
                     * than traditional implementation of insertion sort.

                     * 具体执行过程:上面的do-while循环已经排好的最前面的数据

                    *(1)将要插入的数据,第一个值赋值a1,第二个值赋值a2,

                    *(2)然后判断a1与a2的大小,使a1要大于a2

                    *(3)接下来,首先是插入大的数值a1,将a1与k之前的数字一一比较,直到数值小于a1为止,把a1插入到合适的位置,注意:这里的相隔距离为2

                    *(4)接下来,插入小的数值a2,将a2与此时k之前的数字一一比较,直到数值小于a2为止,将a2插入到合适的位置,注意:这里的相隔距离为1

                    *(5)最后把最后一个没有遍历到的数据插入到合适位置

                     */
                    for (int k = left; ++left <= right; k = ++left) {
                        int a1 = a[k], a2 = a[left];

                        if (a1 < a2) {
                            a2 = a1; a1 = a[left];
                        }
                        while (a1 < a[--k]) {
                            a[k + 2] = a[k];
                        }
                        a[++k + 1] = a1;

                        while (a2 < a[--k]) {
                            a[k + 1] = a[k];
                        }
                        a[k + 1] = a2;
                    }
                    int last = a[right];

                    while (last < a[--right]) {
                        a[right + 1] = a[right];
                    }
                    a[right + 1] = last;
                }
                return;
            }

    。。。。。。//这里只截取了长度小于INSERTION_SORT_THRESHOLD的时候,大于的时候比较难,没具体分析

    /**下面是INSERTION_SORT_THRESHOLD的解释

         * If the length of an array to be sorted is less than this
         * constant, insertion sort is used in preference to Quicksort.
         */

     private static final int INSERTION_SORT_THRESHOLD = 47;

    }

    第二部分:

    当要排队列长度小于QUICKSORT_THRESHOLD并且大于INSERTION_SORT_THRESHOLD时,用双基准快速排序方法,

    这部分的代码就是上面。。。。没有显示的部分,具体的原理同双基准快速排序

    第三部分:

    如果要排序的队列长读大于INSERTION_SORT_THRESHOLD,采用合并排序方法

     /**
         * If the length of an array to be sorted is less than this
         * constant, Quicksort is used in preference to merge sort.
         */
        private static final int QUICKSORT_THRESHOLD = 286;

    import java.util.Arrays;public class ArraysSort_11 {
        public static void main(String args[])
        {
            int[] a={1,4,-1,5,0};
            Arrays.sort(a);
            //数组a[]的内容变为{-1,0,1,4,5}
            for(int i=0;i<a.length;i++)
                System.out.print(a[i]+"  ");
        }
    }

    2.对复合数据类型的数据的排序

       函数原型:  (1)public static<T> void sort(T[] a,Comparator c)  根据指定比较器产生的顺序对指定对象数组进行排序。

            (2)public static<T> void sort(T[] a,int fromIndex,int toIndex,Comparator c)  根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。 

      说明:这个两个排序算法是“经过调优的合并排序”算法。

    源码:

    其中的两个API

     public static <T> void sort(T[] a, Comparator<? super T> c) {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, c);
        }

    ​public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                    Comparator<? super T> c) {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex, c);
            else
                TimSort.sort(a, fromIndex, toIndex, c);
        }



    核心代码调用的是相同的代码

    如果:LegacyMergeSort.userRequested为真时:

    执行下面代码:

    这里c可以为null,如果为null,则调用默认的比较器进行比较,否则调用用户指定的比较器进行比较。

    下面是改进版的合并排序

    执行步骤如下:

    (1)如果比较的长度小于INSERTIONSORT_THRESHOLD插入排序的阈值,直接调用传统的插入排序进行比较

    (2)当大于插入排序的阈值时,采用合并排序算法,这里有个改进的地方,加亮部分,如果已经排好序的,不再进行比较,而是直接复制过去,提高效率

     private static void mergeSort(Object[] src,
                                      Object[] dest,
                                      int low, int high, int off,
                                      Comparator c) {
            int length = high - low;

            // Insertion sort on smallest arrays
            if (length < INSERTIONSORT_THRESHOLD) {
                for (int i=low; i<high; i++)
                    for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
            }

            // Recursively sort halves of dest into src
            int destLow  = low;
            int destHigh = high;
            low  += off;
            high += off;
            int mid = (low + high) >>> 1;
            mergeSort(dest, src, low, mid, -off, c);
            mergeSort(dest, src, mid, high, -off, c);

            // If list is already sorted, just copy from src to dest.  This is an
            // optimization that results in faster sorts for nearly ordered lists.
            if (c.compare(src[mid-1], src[mid]) <= 0) {
               System.arraycopy(src, low, dest, destLow, length);
               return;
            }

            // Merge sorted halves (now in src) into dest
            for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
                if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
                    dest[i] = src[p++];
                else
                    dest[i] = src[q++];
            }
        }
    如果LegacyMergeSort.userRequested为假时,

    调用TimSort.sort方法,如果c为null,还是调用上面的方法,

    否则调用比较器进行比较

      代码实例:

    package aa;import java.util.Arrays;import java.util.Comparator;public class Arraysort {
        Point[] arr;
        
        Arraysort(){
            arr=new Point[4];    //定义对象数组arr,并分配存储的空间
            for(int i=0;i<4;i++)
                arr[i]=new Point();
        }
        
        public static void main(String[] args) {
            
            Arraysort sort=new Arraysort();
            sort.arr[0].x=2;sort.arr[0].y=1;    //初始化,对象数组中的数据
            sort.arr[1].x=2;sort.arr[1].y=2;
            sort.arr[2].x=1;sort.arr[2].y=2;
            sort.arr[3].x=0;sort.arr[3].y=1;
      
            Arrays.sort(sort.arr, new MyComprator());    //使用指定的排序器,进行排序
            for(int i=0;i<4;i++)    //输出排序结果
                System.out.println("("+sort.arr[i].x+","+sort.arr[i].y+")");
        }
    }class Point{
        int x;
        int y;
    }//比较器,x坐标从小到大排序;x相同时,按照y从小到大排序class MyComprator implements Comparator {
        public int compare(Object arg0, Object arg1) {
            Point t1=(Point)arg0;
            Point t2=(Point)arg1;
            if(t1.x != t2.x)
                return t1.x>t2.x? 1:-1;
            else
                return t1.y>t2.y? 1:-1;
        }
    }

      执行输出:

     

     

  • 相关阅读:
    2021-01-27:如何把文件从服务器复制到本地,用什么命令?
    2020-01-26:mysql8.0做了什么改进?
    2020-01-25:redis中,哨兵如何选举?
    2020-01-24:手写代码:快速排序。
    2021-01-23:LFU手撸,说下时间复杂度和空间复杂度。
    2021-01-22:java中,HashMap的写流程是什么?
    2021-01-21:java中,HashMap的读流程是什么?
    2020-01-20:mysql中,一张表里有3亿数据,未分表,要求是在这个大表里添加一列数据。数据库不能停,并且还有增删改操作。请问如何操作?
    2021-01-19:mysql中,一张表里有3亿数据,未分表,其中一个字段是企业类型,企业类型是一般企业和个体户,个体户的数据量差不多占50%,根据条件把个体户的行都删掉。请问如何操作?
    USB Type-C设备是否需要CC逻辑芯片 ------ 转载
  • 原文地址:https://www.cnblogs.com/wzyxidian/p/5211631.html
Copyright © 2011-2022 走看看