1.基本类型(以int为例)

源码中的快速排序,主要做了以下几个方面的优化:
  1)当待排序的数组中的元素个数较少时,源码中的阀值为7,采用的是插入排序。尽管插入排序的时间复杂度为0(n^2),但是当数组元素较少时,插入排序优于快速排序,因为这时快速排序的递归操作影响性能。
  2)较好的选择了划分元(基准元素)。能够将数组分成大致两个相等的部分,避免出现最坏的情况。例如当数组有序的的情况下,选择第一个元素作为划分元,将使得算法的时间复杂度达到O(n^2).
  3)根据划分元 v ,形成不变式 v* (
源码中选择划分元的方法:

 1)当数组大小为 size=7 时 ,取数组中间元素作为划分元。int n=m>>1;(此方法值得借鉴)。
 2)当数组大小size大于7小于等于40时,取首、中、末三个元素中间大小的元素作为划分元。
 3)当数组大小 size>40 时 ,从待排数组中较均匀的选择9个元素,选出一个伪中数做为划分元。
 普通的快速排序算法,经过一次划分后,将划分元排到素组较中间的位置,左边的元素小于划分元,右边的元素大于划分元,而没有将与划分元相等的元素放在其附近,这一点,在Arrays.sort()中得到了较大的优化。

举例:15、93、15、41、6、15、22、7、15、20
   举例:15、93、15、41、6、15、22、7、15、20

  因size大于7小于等于40 ,所以在15、6、和20 中选择v = 15 作为划分元。
  经过一次换分后: 15、15、7、6、41、20、22、93、15、15. 与划分元相等的元素都移到了素组的两边。
  接下来将与划分元相等的元素移到数组中间来,形成:7、6、15、15、15、15、41、20、22、93.
  最后递归对两个区间进行排序[7、6]和[41、20、22、93].,所以在15、6、和20 中选择v = 15 作为划分元。
2.Object类型

优化的归并排序既快速(nlog(n))又稳定。
  对于对象的排序,稳定性很重要。比如成绩单,一开始可能是按人员的学号顺序排好了的,现在让我们用成绩排,那么你应该保证,本来张三在李四前面,即使他们成绩相同,张三不能跑到李四的后面去。
  而快速排序是不稳定的,而且最坏情况下的时间复杂度是O(n^2)。
  另外,对象数组中保存的只是对象的引用,这样多次移位并不会造成额外的开销,但是,对象数组对比较次数一般比较敏感,有可能对象的比较比单纯数的比较开销大很多。归并排序在这方面比快速排序做得更好,这也是选择它作为对象排序的一个重要原因之一。
  排序优化:实现中快排和归并都采用递归方式,而在递归的底层,也就是待排序的数组长度小于7时,直接使用冒泡排序,而不再递归下去。
  分析:长度为6的数组冒泡排序总比较次数最多也就1+2+3+4+5+6=21次,最好情况下只有6次比较。而快排或归并涉及到递归调用等的开销,其时间效率在n较小时劣势就凸显了,因此这里采用了冒泡排序,这也是对快速排序极重要的优化。
  
快排部分代码如下:

package com.util;

public class ArraysPrimitive {
    private ArraysPrimitive() {}

/**
     * 对指定的 int 型数组按数字升序进行排序。
     */
    public static void sort(int[] a) {
        sort1(a, 0, a.length);
    }

/**
     * 对指定 int 型数组的指定范围按数字升序进行排序。
     */
    public static void sort(int[] a, int fromIndex, int toIndex) {
        rangeCheck(a.length, fromIndex, toIndex);
        sort1(a, fromIndex, toIndex - fromIndex);
    }

private static void sort1(int x[], int off, int len) {
        /*
         * 当待排序的数组中的元素个数小于 7 时,采用插入排序 。
         *
         * 尽管插入排序的时间复杂度为O(n^2),但是当数组元素较少时, 插入排序优于快速排序,因为这时快速排序的递归操作影响性能。
         */
        if (len < 7) {
            for (int i = off; i < len + off; i++)
                for (int j = i; j > off && x[j - 1] > x[j]; j--)
                    swap(x, j, j - 1);
            return;
        }
        /*
         * 当待排序的数组中的元素个数大于 或等于7 时,采用快速排序 。
         *
         * Choose a partition element, v
         * 选取一个划分元,V
         *
         * 较好的选择了划分元(基准元素)。能够将数组分成大致两个相等的部分,避免出现最坏的情况。例如当数组有序的的情况下,
         * 选择第一个元素作为划分元,将使得算法的时间复杂度达到O(n^2).
         */
        // 当数组大小为size=7时 ,取数组中间元素作为划分元。
        int m = off + (len >> 1);
        // 当数组大小 7<size<=40时,取首、中、末 三个元素中间大小的元素作为划分元。
        if (len > 7) {
            int l = off;
            int n = off + len - 1;
            /*
             * 当数组大小  size>40 时 ,从待排数组中较均匀的选择9个元素,
             * 选出一个伪中数做为划分元。
             */
            if (len > 40) {
                int s = len / 8;
                l = med3(x, l, l + s, l + 2 * s);
                m = med3(x, m - s, m, m + s);
                n = med3(x, n - 2 * s, n - s, n);
            }
            // 取出中间大小的元素的位置。
            m = med3(x, l, m, n); // Mid-size, med of 3
        }

//得到划分元V
        int v = x[m];

// Establish Invariant: v* (<v)* (>v)* v*
        int a = off, b = a, c = off + len - 1, d = c;
        while (true) {
            while (b <= c && x[b] <= v) {
                if (x[b] == v)
                    swap(x, a++, b);
                b++;
            }
            while (c >= b && x[c] >= v) {
                if (x[c] == v)
                    swap(x, c, d--);
                c--;
            }
            if (b > c)
                break;
            swap(x, b++, c--);
        }
        // Swap partition elements back to middle
        int s, n = off + len;
        s = Math.min(a - off, b - a);
        vecswap(x, off, b - s, s);
        s = Math.min(d - c, n - d - 1);
        vecswap(x, b, n - s, s);
        // Recursively sort non-partition-elements
        if ((s = b - a) > 1)
            sort1(x, off, s);
        if ((s = d - c) > 1)
            sort1(x, n - s, s);
    }

/**
     * Swaps x[a] with x[b].
     */
    private static void swap(int x[], int a, int b) {
        int t = x[a];
        x[a] = x[b];
        x[b] = t;
    }

/**
     * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
     */
    private static void vecswap(int x[], int a, int b, int n) {
    for (int i=0; i<n; i++, a++, b++)
        swap(x, a, b);
    }

/**
     * Returns the index of the median of the three indexed integers.
     */
    private static int med3(int x[], int a, int b, int c) {
        return (x[a] < x[b] ? (x[b] < x[c] ? b : x[a] < x[c] ? c : a)
                : (x[b] > x[c] ? b : x[a] > x[c] ? c : a));
    }

/**
     * Check that fromIndex and toIndex are in range, and throw an
     * appropriate exception if they aren't.
     */
    private static void rangeCheck(int arrayLen, int fromIndex, int toIndex) {
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex
                    + ") > toIndex(" + toIndex + ")");
        if (fromIndex < 0)
            throw new ArrayIndexOutOfBoundsException(fromIndex);
        if (toIndex > arrayLen)
            throw new ArrayIndexOutOfBoundsException(toIndex);
    }
}

1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133

归并部分代码如下:

package com.util;

import java.lang.reflect.Array;

public class ArraysObject {
    private static final int INSERTIONSORT_THRESHOLD = 7;

private ArraysObject() {}

public static void sort(Object[] a) {
        //java.lang.Object.clone(),理解深表复制和浅表复制
        Object[] aux = (Object[]) a.clone();
        mergeSort(aux, a, 0, a.length, 0);
    }

public static void sort(Object[] a, int fromIndex, int toIndex) {
        rangeCheck(a.length, fromIndex, toIndex);
        Object[] aux = copyOfRange(a, fromIndex, toIndex);
        mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
    }

/**
     * Src is the source array that starts at index 0
     * Dest is the (possibly larger) array destination with a possible offset
     * low is the index in dest to start sorting
     * high is the end index in dest to end sorting
     * off is the offset to generate corresponding low, high in src
     */
    private static void mergeSort(Object[] src, Object[] dest, int low,
            int high, int off) {
        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 &&
                        ((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;
        /*
         *  >>>:无符号右移运算符
         *  expression1 >>> expresion2:expression1的各个位向右移expression2
         *  指定的位数。右移后左边空出的位数用0来填充。移出右边的位被丢弃。
         *  例如:-14>>>2;  结果为:1073741820
         */
        int mid = (low + high) >>> 1;
        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.
        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++];
        }
    }

/**
     * Check that fromIndex and toIndex are in range, and throw an appropriate
     * exception if they aren't.
     */
    private static void rangeCheck(int arrayLen, int fromIndex, int toIndex) {
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex
                    + ") > toIndex(" + toIndex + ")");
        if (fromIndex < 0)
            throw new ArrayIndexOutOfBoundsException(fromIndex);
        if (toIndex > arrayLen)
            throw new ArrayIndexOutOfBoundsException(toIndex);
    }

public static <T> T[] copyOfRange(T[] original, int from, int to) {
        return copyOfRange(original, from, to, (Class<T[]>) original.getClass());
    }

public static <T, U> T[] copyOfRange(U[] original, int from, int to,
            Class<? extends T[]> newType) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        T[] copy = ((Object) newType == (Object) Object[].class)
                ? (T[]) new Object[newLength]
                : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, from, copy, 0,
                Math.min(original.length - from, newLength));
        return copy;
    }

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

1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113

辅助理解

package com.lang;

public final class System {
    //System 类不能被实例化。
    private System() {}
    //在 System 类提供的设施中,有标准输入、标准输出和错误输出流;对外部定义的属性
    //和环境变量的访问;加载文件和库的方法;还有快速复制数组的一部分的实用方法。
    /**
     * src and dest都必须是同类型或者可以进行转换类型的数组.
     * @param      src      the source array.
     * @param      srcPos   starting position in the source array.
     * @param      dest     the destination array.
     * @param      destPos  starting position in the destination data.
     * @param      length   the number of array elements to be copied.
     */
    public static native void arraycopy(Object src, int srcPos, Object dest,
            int destPos, int length);
}

1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

package com.lang.reflect;

public final class Array {
    private Array() {}

//创建一个具有指定的组件类型和维度的新数组。
    public static Object newInstance(Class<?> componentType, int length)
            throws NegativeArraySizeException {
        return newArray(componentType, length);
    }

private static native Object newArray(Class componentType, int length)
            throws NegativeArraySizeException;
}

Arrays.sort()的底层实现的更多相关文章

  1. Java的Arrays.sort()方法到底用的什么排序算法

    暂时网上看过很多JDK8中Arrays.sort的底层原理,有些说是插入排序,有些说是归并排序,也有说大于域值用计数排序法,否则就使用插入排序...其实不全对.让我们分析个究竟: 1 // Use Q ...

  2. 5.4 集合的排序(Java学习笔记)(Collections.sort(),及Arrays.sort()底层分析)

    1.Comparable接口 这个接口顾名思义就是用于排序的,如果要对某些对象进行排序,那么该对象所在的类必须实现 Comparabld接口.Comparable接口只有一个方法CompareTo() ...

  3. java源码分析:Arrays.sort

    仔细分析java的Arrays.sort(version 1.71, 04/21/06)后发现,java对primitive(int,float等原型数据)数组采用快速排序,对Object对象数组采用 ...

  4. Arrays.sort源代码解析

    Java Arrays.sort源代码解析 Java Arrays中提供了对所有类型的排序.其中主要分为Primitive(8种基本类型)和Object两大类. 基本类型:采用调优的快速排序: 对象类 ...

  5. Java Arrays.sort源代码解析

    前提: 当用到scala的sortWith,发现: def sortWith(lt: (A, A) ⇒ Boolean): List[A] // A为列表元素类型 根据指定比较函数lt进行排序,且排序 ...

  6. Arrays.sort和Collections.sort实现原理解析

    Arrays.sort和Collections.sort实现原理解析 1.使用 排序 2.原理 事实上Collections.sort方法底层就是调用的array.sort方法,而且不论是Collec ...

  7. JAVA基础系列:Arrays.sort()

    JDK 1.8  java.util.Arrays.class(rt.jar) 1. Collections.sort方法底层就是调用的Arrays.sort方法. 2. Java Arrays中提供 ...

  8. Arrays.sort实现原理

    Collections.sort方法底层就是调用的array.sort方法 比较器的方式 TimSort static void sort(Object[] a, int lo, int hi, Ob ...

  9. Arrays.sort(arr)是什么排序

    在学习过程中观察到Arrays.sort(arr)算法可以直接进行排序,但不清楚底层的代码逻辑是什么样子,记得自己之前在面试题里面也有面试官问这个问题,只能说研究之后发现还是比较复杂的,并不是网上说的 ...

随机推荐

  1. linux shell 脚本攻略学习4

    1.cat命令详解 cat 是concatnate(拼接)的简写. 语法: cat file1 file2 file3 .... 作用:将文件内容拼接在一起进行输出 具体应用: 1).压缩空白行 加上 ...

  2. React(0.13) 服务端渲染的两个函数

    1.React.renderToString 函数,  参数是组件,返回一个字符串 <!DOCTYPE html> <html> <head> <title& ...

  3. 创建 maven maven-archetype-quickstart 项目抱错问题解决方法

    问题: eclipse装m2eclipse的时候装完后创建项目的时候报错: Unable to create project from archetype org.apache.maven.arche ...

  4. go test命令參数问题

    go test命令參数问题 在使用go test对go代码进行单元測试的时候,遇到关于命令參数的问题.google了一下,没有找到非常好的说明,其实就是一些细节而已. 问题是这种,在进行单元測试的时候 ...

  5. Sails入门指南

    1.全局观:sails理念,框架结构 2.试用sails的scaffolding工具,创建model,创建controller, 3.启动server,试用blueprint, 4.进阶: 4.0 数 ...

  6. oracle数据库rman异地恢复

    自己想做两组rac之间的data guard,由于datafile,controlfile,甚至是archivelog都是存放在asm上的,直接复制数据有点不现实,asm磁盘总归都是要用的,所以想从a ...

  7. apache提示没有设置 max-age or expires解决办法

    大家看到这个就应该知道只要设置 max-age or expires就行了.下面说的方法是在设置 apache下的方法: 产生要开启 代码如下 复制代码 LoadModule headers_modu ...

  8. 常用的apache commons工具,直接使用,便于快速开发

    详情 :http://commons.apache.org/ Components Description Latest Version Released Attributes Runtime API ...

  9. Ubuntu 13.10 安装软件失败后出现的问题——已安装 post-installation 脚本 返回了错误号 1

    安装Oracle-java7-installer失败后,再次重新安装后出现错误-- dpkg: error processing oracle-java7-installer (--configure ...

  10. 设置eclipse/myeclipse的智能提示

    打开eclipse/myeclipse选择 window-->Preferences-->JAVA-->Editor-->单击Content Assist–>在右边找到A ...