【发布时间】:2014-09-21 20:45:34
【问题描述】:
我想测试不同排序算法的执行时间,我发现了一个有趣的问题。当我多次运行程序时,比如说插入排序,前一两次比后面的时间花费更多的时间。这种情况发生在数组的大小很大时,不同的大小对执行时间的影响也不同。
public static void insertSort(int[] array){
for(int i = 1; i<array.length; i++){
int current = array[i];
int j = i-1;
while((j>=0)&&(array[j]>current)){
array[j+1] = array[j];
array[j] = current;
j--;
}
}
}
public static void multiTimes(int size){
Random r = new Random();
int a[] = new int[size];
int b[] = new int[size];
for(int j = 0; j<size; j++)
a[j] = r.nextInt(size);
long startTime, endTime = 0;
b = Arrays.copyOf(a, a.length);
startTime=System.nanoTime();
insertSort(b);
endTime=System.nanoTime();
System.out.println("Insert "+(endTime-startTime)+" ns");
b = Arrays.copyOf(a, a.length);
startTime=System.nanoTime();
insertSort(b);
endTime=System.nanoTime();
System.out.println("Insert "+(endTime-startTime)+" ns");
b = Arrays.copyOf(a, a.length);
startTime=System.nanoTime();
insertSort(b);
endTime=System.nanoTime();
System.out.println("Insert "+(endTime-startTime)+" ns");
b = Arrays.copyOf(a, a.length);
startTime=System.nanoTime();
insertSort(b);
endTime=System.nanoTime();
System.out.println("Insert "+(endTime-startTime)+" ns");
b = Arrays.copyOf(a, a.length);
startTime=System.nanoTime();
insertSort(b);
endTime=System.nanoTime();
System.out.println("Insert "+(endTime-startTime)+" ns");
b = Arrays.copyOf(a, a.length);
startTime=System.nanoTime();
insertSort(b);
endTime=System.nanoTime();
System.out.println("Insert "+(endTime-startTime)+" ns");
}
尺寸:100
插入 77908 ns
插入 82573 ns
插入 75109 ns
插入 76508 ns
插入 91902 ns
插入 78840 ns
每次执行时间都差不多。
尺寸:1000:
插入 6256400 ns
插入 5674659 ns
插入 188938 ns
插入 188004 ns
插入 187071 ns
插入 186605 ns
尺寸:2000:
插入 7961037 ns
插入 6590889 ns
插入 793538 ns
插入 793072 ns
插入 793072 ns
插入 792138 ns
我们可以看到,对于 1000、2000 或更大的大小,结果是相当有趣的。前两次的执行时间大约是后面执行的30倍(size = 1000)。
注意:
- 语言:Java JDK7; IDE:日食;平台:Win8.1;
- 对于每种尺寸,都进行了许多实验,结果非常相似。虽然执行时间有一定的随机性,但无法解释为什么前两次相似,比后面的时间长 30 倍以上。
- 一个可能的原因可能是阵列已经在数据缓存中,因此以后的执行花费的时间更少。我不确定是否还有其他原因。
PS: 在我测试了插入排序之后,我发现它在快速排序中甚至令人困惑。
public static void quickSort(int a[], int left, int right){
if(right<=left)
return;
int temp[] = new int[right-left+1];
for(int i = left; i<=right; i++)
temp[i-left] = a[i];
int pivot = a[left];
int subr = right, subl = left;
for(int i = left+1; i<=right;i++){
if(temp[i-left]>pivot)
a[subr--] = temp[i-left];
else
a[subl++] = temp[i-left];
}
a[subl] = pivot;
quickSort(a, left, subl-1);
quickSort(a, subr+1, right);
}
大小 = 1000:
QS 888240 ns
问题 2218734 ns
问题 2179547 ns
问题 2132896 ns
QS 2146890 ns
QS 2212670 ns
大小 = 500:
QS 432924 ns
QS 406799 ns
QS 941889 ns
QS 1103302 ns
QS 1101436 纳秒
Qs 1086042 ns
当大小在 [200, 2000] 左右时,前几次比后面几次花费的时间更少,这与插入排序相反。当大小增加到超过 2000 时,它类似于插入排序中的场景,在这种情况下,稍后执行花费的时间更少。
【问题讨论】:
-
不是完全重复,但非常密切相关的是这个问题:How do I write a correct micro-benchmark in Java?
标签: java sorting time execution