我一直在尝试使用quicksort并学习如何测试程序的速度。有一点对我没有意义。我尝试实现了一个在Java中使用尾递归的快速排序算法。它通常运行得更快。但后来我才知道Java不支持尾调用优化。为什么它会跑得更快呢?
这是代码。
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
public class QuicksortCompare
{
private final static Random rand = new Random();
private static final int MIN_LENGTH = 10;
private static final int MAX_LENGTH = 1000;
private static final int MIN_VAL = -1000;
private static final int MAX_VAL = 1000;
public static void main(String[] args)
{
/*long[] avgTimes = {0, 0};
System.out.println("press enter to start");
Scanner in = new Scanner(System.in);
in.nextLine();*/
for(;;)
{
int[] arr1 = generateRandomArray(MIN_LENGTH, MAX_LENGTH, MIN_VAL, MAX_VAL);
int[] arr2 = Arrays.copyOf(arr1, arr1.length);
long startTime = System.nanoTime();
quicksortNormal(arr1, 0, arr1.length-1);
long endTime = System.nanoTime();
long duration = endTime-startTime;
System.out.print("normal: "+duration+" ns\t");
startTime = System.nanoTime();
quickSortTailRecurse(arr2, 0, arr2.length-1);
endTime = System.nanoTime();
duration = endTime-startTime;
System.out.println("special: "+duration+" ns\tlength: "+arr1.length);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(QuicksortCompare.class.getName()).log(Level.SEVERE, null, ex);
}
} }
public static int[] generateRandomArray(int minLength, int maxLength, int minVal, int maxVal)
{
int[] arr = new int[minLength+rand.nextInt((maxLength-minLength)+1)];
populateArray(arr, minVal, maxVal);
return arr;
}
public static void populateArray(int arr[], int min, int max)
{
for(int i = 0; i < arr.length; i++)
arr[i] = min+rand.nextInt((max-min)+1);
}
private static void quickSortTailRecurse(int[] arr, int lo, int hi){
if(lo >= hi) return;
int p = partition(arr, lo, hi);
if((p - lo ) <= (hi-p)){
quickSortTailRecurse(arr, lo, p);
quickSortTailRecurse(arr, p+1, hi);
}else {
quickSortTailRecurse(arr, p+1, hi);
quickSortTailRecurse(arr, lo, p);
}
}
public static void quicksortNormal(int[] a, int p, int r)
{
if(p<r)
{
int q = partition(a,p,r);
quicksortNormal(a,p,q);
quicksortNormal(a,q+1,r);
}
}
public static void quicksortSmallSide_old(int[] a, int p, int r)
{
while(p<r)
{
int q = partition(a,p,r);
if(q-p < r-q)
{
quicksortSmallSide(a,p,q);//may supposed to be q-1
p = q+1;
}
else
{
quicksortSmallSide(a,q+1,r);
r = q-1;
}
}
}
private static int partition(int[] a, int p, int r) {
int x = a[p];
int i = p-1 ;
int j = r+1 ;
while (true) {
i++;
while ( i< r && a[i] < x)
i++;
j--;
while (j>p && a[j] > x)
j--;
if (i < j)
swap(a, i, j);
else
return j;
}
}
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
以下是探查者:
这是一些输出:
run:
normal: 42000 ns special: 39000 ns length: 35
normal: 1240000 ns special: 1202000 ns length: 829
normal: 336000 ns special: 37000 ns length: 63
normal: 358000 ns special: 179000 ns length: 839
normal: 102000 ns special: 62000 ns length: 322
normal: 72000 ns special: 61000 ns length: 393
normal: 11000 ns special: 10000 ns length: 75
normal: 26000 ns special: 27000 ns length: 210
normal: 134000 ns special: 58000 ns length: 337
normal: 91000 ns special: 94000 ns length: 393
normal: 66000 ns special: 70000 ns length: 551
normal: 107000 ns special: 115000 ns length: 805
normal: 54000 ns special: 57000 ns length: 386
normal: 21000 ns special: 24000 ns length: 197
normal: 29000 ns special: 37000 ns length: 250
normal: 117000 ns special: 122000 ns length: 932
normal: 199000 ns special: 205000 ns length: 963
normal: 31000 ns special: 147000 ns length: 148
normal: 16000 ns special: 16000 ns length: 136
normal: 193000 ns special: 191000 ns length: 959
normal: 107000 ns special: 199000 ns length: 634
objc[712]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/bin/java and /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.
Profiler Agent: Waiting for connection on port 5140 (Protocol version: 15)
Profiler Agent: Established connection with the tool
Profiler Agent: Local accelerated session
normal: 674000 ns special: 864000 ns length: 450
normal: 24424000 ns special: 1798000 ns length: 186
normal: 3561000 ns special: 2434000 ns length: 678
normal: 2112000 ns special: 2148000 ns length: 908
normal: 1595000 ns special: 1582000 ns length: 739
normal: 2179000 ns special: 2248000 ns length: 936
normal: 1025000 ns special: 997000 ns length: 447
normal: 1185000 ns special: 1161000 ns length: 574
normal: 1507000 ns special: 2678000 ns length: 741
...
normal: 1554000 ns special: 1534000 ns length: 656
normal: 366000 ns special: 318000 ns length: 152
normal: 138000 ns special: 132000 ns length: 67
normal: 1146000 ns special: 1095000 ns length: 478
BUILD STOPPED (total time: 5 minutes 33 seconds)
答案 0 :(得分:4)
Java不保证尾部调用优化。
JVM实现可能仍然会这样做,但Java代码不能依赖它来获得正确性。