我正在閱讀有關Sedgewick「算法」中排序的章節。一路上,我寫了3個基本的排序算法:選擇,插入和shell排序。該書說,儘管所有三者都具有二次最壞情況的複雜性,但shell的排序應該比插入排序隨機數據快得多。在這本書中,他們獲得了600倍的性能提升。插入排序比shell排序快得多
,但我得到以下乘數我的筆記本電腦(幾乎不與數組大小的增加改變):
- 選擇:5.5X
- 插入:1個
- 殼:1.8倍!
困擾我的問題是 - 爲什麼shell排序幾乎比插入排序慢兩倍?
我想,我的shellort實現有些問題。但我幾乎從書上抄了一遍:
class ShellSort extends Sort {
//precalculate sequence: 1, 4, 13, 40, 121, 364, 1093, ...
//(3^20 - 1)/2 is enough for any array I sort
private static final int[] SEQUENCE = new int[20];
static {
for(int i = 1; i <= SEQUENCE.length; i++)
SEQUENCE[i - 1] = (int)(Math.pow(3, i) - 1)/2;
}
public void sort(int[] a) {
int length = a.length;
int seqLen = SEQUENCE.length;
int nth;
int j;
for(int seqi = seqLen - 1; seqi >= 0; seqi--) {
if(SEQUENCE[seqi] < length/3) {
nth = SEQUENCE[seqi];
for(int n = 0; n < length; n+=nth) {
j = n;
while(j > 0 && a[j] < a[j - nth]) {
exch(a, j, j-nth);
j -= nth;
}
}
}
}
}
}
這些代碼的休息,希望他們的機器上運行測試誰(與JVM熱起來加倍數組大小測試有對結果沒有顯著的影響,所以這個簡單的測試已經足夠N>〜200 000)。
主:
int N = 500_000;
Random rand = new Random();
int[] a = new int[N];
for(int i = 0; i < N; i++)
a[i] = rand.nextInt();
//insertion sort
int[] aCopy = Arrays.copyOf(a, a.length);
long start = System.nanoTime();
new InsertionSort().sort(aCopy);
System.out.println("insert:\t" + (System.nanoTime() - start));
//shell sort
aCopy = Arrays.copyOf(a, a.length);
start = System.nanoTime();
new ShellSort().sort(aCopy);
System.out.println("shell:\t" + (System.nanoTime() - start));
插入排序和排序類:
class InsertionSort extends Sort {
public void sort(int[] a) {
int length = a.length;
int j;
int x;
for(int i = 1; i < length; i++) {
j = i;
x = a[i];
while(j > 0 && x < a[j-1]) {
a[j] = a[--j];
}
a[j] = x;
}
}
}
abstract class Sort {
abstract public void sort(int[] a);
protected static final void exch(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
這將是一個好主意,遵循這裏的指導 - [如何在Java中編寫正確的微基準?](http://stackoverflow.com/questions/504103/how-do-i-write- a-correct-micro-benchmark-in-java) - 在將太多的權重放入結果之前。 – Dukeling
在證明它們是** [具有統計顯着性](http://en.wikipedia.org/wiki/Statistical_significance)**之前,千萬不要試圖解釋實證結果。 – amit
我在jvm「加熱」的基礎上運行了所有代碼,並獲得了相同的結果。原因是 - 內部循環很快得到了JIT,並且沒有引入重要的GC開銷。 – Oroboros102