java二路快排很慢

来源:3-7 双路快速排序法

Grant_Lian

2018-11-18

老师,以下是我二路快排的java代码

public class quickSortTwoway {
    public quickSortTwoway() {};
    public static void quickSort(Integer[] arr) {
        __quickSort(arr, 0, arr.length - 1);
    }
    private static void __quickSort(Integer[] arr, int l, int r) {
        if(l >= r) return;
        int p = __partition(arr, l, r);
        __quickSort(arr, l, p - 1);
        __quickSort(arr, p + 1, r);
    }
    private static int __partition(Integer[] arr, int l, int r) {
        swap(arr, l, (int)(Math.random() * (r - l + 1)) + l);
        Integer pivot = arr[l];
        int p1 = l + 1, p2 = r;
        while(true) {
            while(p1 <= r && arr[p1].compareTo(pivot) < 0) p1++;
            while(p2 >= l + 1 && arr[p2].compareTo(pivot) > 0) p2--;
            if(p1 >= p2) break;
            swap(arr, p1, p2);
            p1++;
            p2--;
        }
        swap(arr, p2, l);
        return p2;
    }
    private static void swap(Integer[] arr, int i, int j) {
        Integer tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

代码听完您的课以后自己实现了一遍,但是发现二路很慢,我的结果如下:

Test for random array, size = 1000000 , random range [0, 1000000]
quickSortTwoway : 228ms
quickSortNaive : 0ms

Test for nearly ordered array, size = 1000000 , swap time = 100
quickSortTwoway : 211ms
quickSortNaive : 0ms

但是我用普通naive的快排,可以很快完成,请问老师为啥呢?还是我代码出了问题?

我跑了您的github上的代码,测试了merge,quicksort,quicksort2way,结果如下:

Test for random array, size = 1000000 , random range [0, 1000000]
MergeSort : 475ms
QuickSort2Ways : 358ms
QuickSort : 402ms

Test for nearly ordered array, size = 1000000 , swap time = 100
MergeSort : 119ms
QuickSort2Ways : 48ms
QuickSort : 218ms

Test for random array, size = 1000000 , random range [0,10]
MergeSort : 354ms
QuickSort2Ways : 205ms
java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at bobo.algo.SortTestHelper.testSort(SortTestHelper.java:81)
	at bobo.algo.Main.main(Main.java:52)
Caused by: java.lang.StackOverflowError
	at bobo.algo.QuickSort.sort(QuickSort.java:36)
	at bobo.algo.QuickSort.sort(QuickSort.java:41)
	at bobo.algo.QuickSort.sort(QuickSort.java:42)

您的naive quick sort在有大量重复元素的时候会溢出,但是quicksort2way没事, 感觉很奇怪,您的quicksort naive也有时间,我的就是0ms,和ide有关吗?您的代码我在eclipse里面跑的,我自己在terminal里面写的

更新,老师我听了三路快排后实现了一遍,发现三路快排更慢,不知道啥原因,以下是结果:

Test for random array, size = 1000000 , random range [0, 1000000]
quickSortTwoway : 245ms
quickSortNaive : 0ms
quickSortThreeway : 604ms

Test for nearly ordered array, size = 1000000 , swap time = 100
quickSortTwoway : 219ms
quickSortNaive : 0ms
java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at SortTestHelper.testSort(SortTestHelper.java:80)
        at Main.main(Main.java:38)
Caused by: java.lang.StackOverflowError
        at quickSortThreeway.__quickSort(quickSortThreeway.java:9)
        at quickSortThreeway.__quickSort(quickSortThreeway.java:10)
写回答

1回答

liuyubobobo

2018-11-18

首先,在完全随机的数据下,二路快排和三路快排就是会比一路快排慢,通过代码也能看出来,明显二路快排和三路快排有更多的判断:)


从你的测试结果来看,其实也没有慢那么多,只是毫秒级别的差异而已。至于在我的计算机上,quicksort naive也有时间,是因为我露可用的机子是非常慢的,是13年的mac air低配版:)


在有大量重复元素的时候,你运行naive quick sort会溢出,这恰恰就是naive quick sort的问题!也正是我们要引入二路快排以及三路快排的原因!因为对于有大量重复的元素,对于naive quick sort来说,会使得每次分割的pivot极度不平衡(会偏向数组的一段),导致递归深度近乎等于数组中的数据个数(n),从而导致系统栈溢出!而二路快排和三路快排,恰恰就是在解决这个问题:)


也正是因为这个原因,naive quick sort只有在完全随机的数据下才能有很好的表现,否则会很糟糕,导致在大多数标准库中,是不会使用naive的快拍的:)


可以稍微调小一下数据规模,应该可以看到在近乎有序和有大量重复数据的情况下,如果系统栈不溢出,naive quick sort也会很慢:)


加油!:)

0
1
Grant_Lian
非常感谢!
2018-11-18
共1条回复

算法与数据结构(C++版) 面试/评级的算法复习技能包

课程专为:短时间内应对面试、升职测评等艰巨任务打造

11187 学习 · 1614 问题

查看课程