0.033秒的藝術 ---- Radix Sort
僅供個人學習使用,請勿轉載,勿用於任何商業用途。
之前的一篇文章裡,討論過關於快速排序的問題,最近又研究了一下各種排序演算法,無意間看到Radix Sort,測試了一下猜猜結果如何?借用GameDev上一位老兄的話說“fast like hell”!
Radix Sort(基排序)可以說是最被人們忽視的排序演算法,學校裡講排序時通常只會提到幾種出名的比較排序方法,連演算法導論也只是稍稍提了一下,沒有給出具體實現步驟。這裡有關於radix sort的具體演算法,原理應該比quick sort還簡單,這裡有C++版本的實現代碼,同樣非常簡潔,以下是C#版:
private Int64[] array;
private Int64[] tempArray;
private int[] count = new int[256];
private int[] offsetTable = new int[256];
public void RadixSort()
{
Radix(0, array, tempArray);
Radix(1, tempArray, array);
Radix(2, array, tempArray);
Radix(3, tempArray, array);
Radix(4, array, tempArray);
Radix(5, tempArray, array);
Radix(6, array, tempArray);
Radix(7, tempArray, array);
}
private void Radix(int byteIndex, Int64[] source, Int64[] dest)
{
Array.Clear(count, 0, 256);
int byteOffset = byteIndex * 8;
for (int i = 0; i < elementCount; i++)
{
byte radixValue = (byte)(source[i] >> byteOffset);
count[radixValue]++;
}
offsetTable[0] = 0;
for (int i = 1; i < 256; i++)
{
offsetTable[i] = offsetTable[i - 1] + count[i - 1];
}
for (int i = 0; i < elementCount; i++)
{
int index = offsetTable[(byte)(source[i] >> byteOffset]++;
dest[index] = source[i];
}
}
當然,radix sort也並不是沒有缺點,首先,待排序的值最好是整數;其次,需要佔用額外的記憶體,而大多數比較排序演算法都可以原地排序;最後,待排資料量最好在10k以下(對於不同的硬體,這個值有可能變化)。
下面是用Q6600(2.4G,4 core)對Int64進行排序得出的結果:
quick sort radix sort
1k 1ms 0ms
2k 1ms 0ms
5k 2ms 1ms
10k 4ms 2ms
50k 18ms 13ms
100k 38ms 35ms
500k 212ms 654ms
可以看到對於10k以下的資料量,radix sort優勢非常明顯,特別是2k以下時,已經快到無法正確測出時間了。注意,這裡用的是Int64,對radix sort來說,需要用8個pass完成排序,對Int32來說,則只要4個pass,理論上速度還會快一倍。不幸的是當資料量曾大時,radix sort效能出現了戲劇性的變化,沒有做具體分析,但猜想應該是受CPU緩衝大小影響的原因。我在另外一台非常古老的P4 2.4(L2 512k)機器上做測試,資料大於10k時,radix sort的優勢就不太明顯了。
結論:對於大部分遊戲來說,渲染隊列的數量都不會超過10k,通常在2~3k左右,因此,嘗試使用radix sort來進行排序是非常值得的。