• ArrayList排序算法的源码


    ArrayList,排序方法的调用过程

    // 排序方法
        public void sort(Comparator<? super E> c) {
            final int expectedModCount = modCount;
            Arrays.sort((E[]) elementData, 0, size, c);
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }
    
        public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                    Comparator<? super T> c) {
            // 如果没有实现比较方法
            if (c == null) {
                sort(a, fromIndex, toIndex);
            } else {
                rangeCheck(a.length, fromIndex, toIndex);
                if (Arrays.LegacyMergeSort.userRequested)
                    legacyMergeSort(a, fromIndex, toIndex, c);
                else
                    TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
            }
        }
    
        public static void sort(Object[] a, int fromIndex, int toIndex) {
            rangeCheck(a.length, fromIndex, toIndex);
            //经查资料,这是个传统的归并排序,需要通过设置系统属性后,才能进行调用
            // System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
            if (Arrays.LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex);
            else
                ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
        }

    然后继续看下在没有实现Comparator接口的情况,传统归并排序的实现

    private static void legacyMergeSort(Object[] a,
                                            int fromIndex, int toIndex) {
            // 复制对应范围的数组
            Object[] aux = copyOfRange(a, fromIndex, toIndex);
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
        }
    
        // 使用插入排序进行优化的归并排序
        // dest为要排序的数组
        // off:负数,因为aux是复制a数组fromIndex-toIndex范围的数据,但位置从0开始,fromIndex-off则为aux开始的坐标
        private static void mergeSort(Object[] src,
                                      Object[] dest,
                                      int low,
                                      int high,
                                      int off) {
            int length = high - low;
    
            // Insertion sort on smallest arrays
            // 长度小于7,则使用插入排序
            if (length < INSERTIONSORT_THRESHOLD) {
                for (int i=low; i<high; i++)
                    for (int j=i; j>low &&
                            ((Comparable) dest[j-1]).compareTo(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;
    
            // 交换dest,src位置,这样就能排序src,然后合并到dest
            // 注意这个递归的开始,dest为要排序的数组a,所以最终a会合并成有序的数组
            mergeSort(dest, src, low, mid, -off);
            mergeSort(dest, src, mid, high, -off);
    
            // If list is already sorted, just copy from src to dest.  This is an
            // optimization that results in faster sorts for nearly ordered lists.
            // 如果说src排完序后,两个范围的src,刚好前一个小于后一个,则直接复制。
            // 例如两个范围【1,2】【3,4】,其实他们已经有序【1,2,3,4】
            if (((Comparable)src[mid-1]).compareTo(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 && ((Comparable)src[p]).compareTo(src[q])<=0)
                    dest[i] = src[p++];
                else
                    dest[i] = src[q++];
            }
        }
    
        /**
         * Swaps x[a] with x[b].
         */
        private static void swap(Object[] x, int a, int b) {
            Object t = x[a];
            x[a] = x[b];
            x[b] = t;
        }

    再看看当前默认使用的排序方法(没使用Comparable的情况)

    /**
         *
         * @param a 待排序的数组
         * @param lo 开始位置,包括当前位置
         * @param hi 结束位置,不包括当前位置
         * @param work
         * @param workBase
         * @param workLen
         */
        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
            // 排序的范围小于32的情况
            if (nRemaining < MIN_MERGE) {
                // 从lo位置开始,返回最长的递增序列长度,(下面有介绍)
                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;
        }

    具体看看里面的方法实现

        /**
         * 返回从lo开始最长递增序列
         * @param a 待排序的数组
         * @param lo 开始位置,包括当前位置
         * @param hi 结束位置,不包含当前位置
         * @return
         */
        private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
            assert lo < hi;
            int runHi = lo + 1;
            if (runHi == hi)
                return 1;
    
            // Find end of run, and reverse range if descending
            // 如果lo+1位置的数小于lo位置的数,就找出最长的递减序列,然后进行反转
            if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
                while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
                    runHi++;
                reverseRange(a, lo, runHi);
            } else {                              // Ascending
                while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)
                    runHi++;
            }
    
            // 返回递增的长度
            return runHi - lo;
        }
    
        // 反转
        private static void reverseRange(Object[] a, int lo, int hi) {
            hi--;
            while (lo < hi) {
                Object t = a[lo];
                a[lo++] = a[hi];
                a[hi--] = t;
            }
        }
    
        /**
         *  折半插入排序
         * @param a 待排序的数组
         * @param lo 开始位置,包括当前位置
         * @param hi 结束位置,不包含当前位置
         * @param start start以前为递增序列
         */
        private static void binarySort(Object[] a, int lo, int hi, int start) {
            assert lo <= start && start <= hi;
            if (start == lo)
                start++;
            // 从start开始遍历
            for ( ; start < hi; start++) {
                Comparable pivot = (Comparable) a[start];
    
                // Set left (and right) to the index where a[start] (pivot) belongs
                int left = lo;
                int right = start;
                assert left <= right;
                /*
                 * Invariants:
                 *   pivot >= all in [lo, left).
                 *   pivot <  all in [right, start).
                 */
                // 二分找lo到start(不包括start)范围内,找到pivot适合插入的位置
                while (left < right) {
                    int mid = (left + right) >>> 1;
                    if (pivot.compareTo(a[mid]) < 0)
                        right = mid;
                    else
                        left = mid + 1;
                }
                assert left == right;
    
                /*
                 * The invariants still hold: pivot >= all in [lo, left) and
                 * pivot < all in [left, start), so pivot belongs at left.  Note
                 * that if there are elements equal to pivot, left points to the
                 * first slot after them -- that's why this sort is stable.
                 * Slide elements over to make room for pivot.
                 */
                int n = start - left;  // The number of elements to move
                // Switch is just an optimization for arraycopy in default case
                // 如果只需后移2位或者1位,直接换值
                // 更多,则调用系统方法进行复制
                switch (n) {
                    case 2:  a[left + 2] = a[left + 1];
                    case 1:  a[left + 1] = a[left];
                        break;
                    default: System.arraycopy(a, left, a, left + 1, n);
                }
                // 后移成功后,赋值
                a[left] = pivot;
            }
        }

    没分析完。。。需要学习一波tim sort。。

  • 相关阅读:
    类型转换函数
    经典问题解析三
    函数调用操作符
    python xml_str转json
    SoapUI导入webService接口
    python两个字符串有变化值作对比
    jenkins编译源码和发布网站
    Jmeter上传文件
    Djiango数据库操作
    mongo常用sql
  • 原文地址:https://www.cnblogs.com/dj3839/p/8295311.html
Copyright © 2020-2023  润新知