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回答
-
首先,在完全随机的数据下,二路快排和三路快排就是会比一路快排慢,通过代码也能看出来,明显二路快排和三路快排有更多的判断:)
从你的测试结果来看,其实也没有慢那么多,只是毫秒级别的差异而已。至于在我的计算机上,quicksort naive也有时间,是因为我露可用的机子是非常慢的,是13年的mac air低配版:)
在有大量重复元素的时候,你运行naive quick sort会溢出,这恰恰就是naive quick sort的问题!也正是我们要引入二路快排以及三路快排的原因!因为对于有大量重复的元素,对于naive quick sort来说,会使得每次分割的pivot极度不平衡(会偏向数组的一段),导致递归深度近乎等于数组中的数据个数(n),从而导致系统栈溢出!而二路快排和三路快排,恰恰就是在解决这个问题:)
也正是因为这个原因,naive quick sort只有在完全随机的数据下才能有很好的表现,否则会很糟糕,导致在大多数标准库中,是不会使用naive的快拍的:)
可以稍微调小一下数据规模,应该可以看到在近乎有序和有大量重复数据的情况下,如果系统栈不溢出,naive quick sort也会很慢:)
加油!:)
012018-11-18
相似问题