双枢轴快排(JDK7快排)(译文)

双枢轴快排算法html

Vladimir Yaroslavskiy算法

iaroslavski@mail.ru编程

初版:2009-02-16数组

最后更新:2009-09-11编程语言

译者:黑狗 Email:blackdog@gmail.com性能

介绍测试

在计算机科学中数据排序是最基础的一个问题,尤为是数组对象是原生的,例如整型,字节,浮点等等。因为排序方法在计算机系统和其余数据处理系统中扮演了重要的角色,咱们对寻找比现存算法更好的算法就显得兴趣十足。咱们使用了大量的开销最大的操做来比较排序算法。这些操做(比较和交换)的效率受排序技术的影响。快排算法是一个高效的,被普遍使用的排序过程,他须要C*n*ln(n)次操做。这里的n指数组的大小。问题关键在于找到一个最小系数C的算法。这里有许多尝试用于改进快排算法中的古典不变式:ui

1.      从数组找找到一个元素,成为枢轴spa

2.      从新排列元素,使小于枢轴的元素置于前,大于的置于后(相等的能够在任何一边)。在这样操做之后,枢轴元素就落到了他的最终位置。指针

3.      递归的处理大于和小于枢轴的子数组。

HoareHelmanKnuthSedgewick以及其余的一些科学家将大多数精力都花费在具体的“划分和优胜”算法实现。或者是尝试根据特定的枢轴元素的选择来提升性能。但他们都使用了古典的划分方案——将枢轴划分为两个部分。

咱们能够向你们展现使用两个枢轴元素(或者说将数组划分为三部分)是更加高效的,特别是在大数组的状况下。咱们推荐一种新的算法——双枢轴快排方案。在这种状况下,他比已知的这些实现方案更快。双枢轴快排算法经过不一样的输入和原生数据类型来进行研究。和古典的快排算法,以及JDK6.0平台上的快排实现比起来,他在交换操做上是有优点的。

 

新的双枢轴快排算法

         新的快排算法用两个枢轴元素P1P2将数组T[]a划分为三个部分。(所以,他须要三个指针LKG,和leftright——用于标记递归的首尾数组)这里的T指代的是原生数据类型(例如整型,浮点,字节,字符,双精度,长整型和短整型)。正如Figure 1所示:

         这个算法执行如下的步骤:

1.      对于小数组(长度小于27),使用插入排序。

2.      选择两个枢轴元素P1P2。好比咱们可使用第一个元素a[left]做为P1a[right]做为P2

3.      P1必须小于P2,不然交换。所以,他被分为了一下几个部分

a)        Part I使用使用标记left+1L-1的元素。他们小于P1

b)        Part II使用标记LK-1的元素。他们大于等于P1,小于或等于P2

c)        Part III使用标记G+1right-1。他们大于P2

d)        Part IV使用标记KG,包含剩下的须要检查的元素

4.      Part IV中的下一个元素a[K]和数周元素P1P2进行比较,记录相应的part I,IIIII的位置。

5.      指针L,KG根据相应的指向而变换

6.      K小于等于G时重复执行4-5

7.      枢轴元素P1Part I的尾部元素交换,P2part III的首部元素交换

8.      对于part IIIIII递归调用,重复执行1-7

数学证实

         双枢轴快排的平均比较次数为2*n*ln(n),平均交换次数为0.8*n*ln(n)。而古典快排算法分别为2*n*ln(n)1*n*ln(n)。完整的数学研究已经完成,并将拷贝到此处(待定)。(坑死爹!找了个没完成的论文!次凹!谁给我提供一个连接啊!

比较和总况

         新的双枢轴快排算法拥有如下的优点:

l  对于原始数据类型,将数组划分为三部分比古典的方法更高效。和古典快排,JDK6中的快排比起来,数组越大新的算法在比较上的性能就越好。例如,咱们采用了以下的数据量进行试验:2000000个随机整型元素分别使用双枢轴,古典和JDK6快排执行50次,并分析其总时间。他们分别花费16.5,1.920.3秒。对于整型的双枢轴方法能够被简单的调整后,完成另外一种数值,字符串和其余可比较的类型。

l  咱们所推荐的双枢轴方法在古典的指定采样数组和重复元素数组的表现也更加快捷。在这些状况下,双枢轴快排在执行了全部的测试状况以后,比JDK6快排快。双枢轴耗费55JDK6耗费100

l  这种算法对于特殊的过程当中,经过枢轴元素P1P2的选择还有其余的改进。咱们不选取a[left]a[right]元素,而是选择两个中间元素。在任意数据源的状况下,这种修正并无使双枢轴快排的属性更糟糕:

Int    third            =  arrayLength / 3;

P1  =  a[left  +  third];

P2  =  a[right  -  third];

         咱们能够将这种算法的特征概括以下:

l  省时

l  采用“划分和优胜”策略

l  采用双枢轴而不是单枢轴

l  可用于数据分析的更搞笑的排序过程

l  双枢轴算法将会被推荐在下一个版本的JDK发布版中。

 

JAVA编程语言的实现

public static void sort(int[] a){

        sort(a,0,a.length);

}

 

public static void sort(int[] a, int fromIndex, int toIndex){

    rangeCheck(a.length, fromIndex, toIndex);

    dualPivotQuicksort(a, fromIndex, toIndex – 1, 3);

}

 

private static void rangeCheck(int length, int fromIndex, int toIndex){

    if (fromIndex > toIndex) {

        throw new IlleagalArgumentException(“fromIndex > toIndex”);

    }

    if (fromIndex < 0) {

        throw new ArrayIndexOutOfBoundsException(fromIndex);

    }

    if (toIndex > length) {

        throw new ArrayIndexOutOfBoundsException(toIndex);

    }

}

 

private static void swap(int[] a, int I, int j) {

    int temp = a[i];

    a[i] = a[j];

    a[j] = temp;

}

 

private static void dualPivortQuicksort(int[] a, int left, int right, int div) {

    int len = right – left;

    if (len < 27) {    //  insertion sort for tiny array

        for (int i = left  + 1; i <= right; i++) {

            for (int j = i; j > left && a[j] < a[j – 1]; j--) {

                swap(a, j, j - 1);

…………….代码就不贴了,你们百度一下或者看JDK 7  Arrays.sort就是了,搞不懂在论文里写那么全的代码作什么

 

实验结果

咱们已经进行了大量的测试,这里是执行的时间:

Server VM:

...

后面的就不译了,都是引用神马的

附上我找到的原文连接,坑死爹啊,求人帮我找官方一点的论文,我没找到啊,又很差意思给做者email。这一篇一点都不严谨!比JDK6的快排论文差太远了!

http://wenku.baidu.com/view/f9d8978702d276a200292ef4.html

相关文章
相关标签/搜索