比較するのは次の3つ。
- radix sort(WikipediaのRadix sortとstereopsisのradix tricksを参考にして書いたコード)
- comb sort(WikipediaのComb sortを参考に書いたコード、というかほぼそのまま)
- quick sort(.NET Framework 3.5のArray.Sort)
using System;ksksts / junk / source — bitbucket.org
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace SortBenchmark
{
class Program
{
static void Main(string[] args)
{
for (var size = 1000; size <= 1000000; size *= 10)
Run(size);
}
static void Run(int size)
{
Console.WriteLine("size: {0}", size);
var count = 10;
var sw = new Stopwatch();
var radixSortTicks = 0L;
var combSortTicks = 0L;
var arraySortTicks = 0L;
for (var c = 0; c < count; c++)
{
var random = new Random(c);
var list = new UInt32[size];
for (var n = 0; n < list.Length; n++)
list[n] = (UInt32)random.Next(Int32.MinValue, Int32.MaxValue);
// radix sort
var radixSortResult = (IList<UInt32>)list.Clone();
sw.Reset();
sw.Start();
RadixSort(radixSortResult);
sw.Stop();
radixSortTicks += sw.ElapsedTicks;
// comb sort
var combSortResult = (IList<UInt32>)list.Clone();
sw.Reset();
sw.Start();
CombSort(combSortResult);
sw.Stop();
combSortTicks += sw.ElapsedTicks;
// Array.Sort
var arraySortResult = list.ToArray();
sw.Reset();
sw.Start();
Array.Sort(arraySortResult);
sw.Stop();
arraySortTicks += sw.ElapsedTicks;
// correctness
for (var n = 0; n < size; n++)
{
if (radixSortResult[n] != arraySortResult[n])
Console.WriteLine("radixSortResult[{0}]: {1}, arraySortResult[{0}]: {2}", n, radixSortResult[n], arraySortResult[n]);
if (combSortResult[n] != arraySortResult[n])
Console.WriteLine("combSortResult[{0}]: {1}, arraySortResult[{0}]: {2}", n, combSortResult[n], arraySortResult[n]);
}
}
Console.WriteLine("radix sort: {0} ({1:F})", radixSortTicks / count, radixSortTicks / (double)arraySortTicks);
Console.WriteLine("comb sort: {0} ({1:F})", combSortTicks / count, combSortTicks / (double)arraySortTicks);
Console.WriteLine("Array.Sort: {0} ({1:F})", arraySortTicks / count, arraySortTicks / (double)arraySortTicks);
}
static void RadixSort(IList<UInt32> list)
{
var tables = new int[sizeof(UInt32)][];
for (var p = 0; p < tables.Length; p++)
tables[p] = new int[0xFF + 1];
// histgramming
foreach (var x in list)
{
var y = x;
for (var p = 0; p < tables.Length; p++)
{
tables[p][(y + 1) & 0xFF]++;
y = y >> 8;
}
}
// sum the histgrams
foreach (var table in tables)
{
table[0] = 0;
for (var n = 1; n < table.Length; n++)
table[n] += table[n - 1];
}
// read/write histgram, copy
IList<UInt32> array = new UInt32[list.Count];
Action swap = () => { var temp = list; list = array; array = temp; };
for (var p = 0; p < tables.Length; p++)
{
var table = tables[p];
foreach (var x in list)
{
var y = (x >> p * 8) & 0xFF;
array[table[y]] = x;
table[y]++;
}
swap();
}
}
static void CombSort(IList<UInt32> list)
{
const double shrinkFactor = 1.247330950103979; // 1.0 / (1.0 - 1.0 / Math.Pow(Math.E, Math.PI));
var gap = list.Count;
var swapped = true;
while (gap > 1 || swapped)
{
if (gap > 1)
gap = (int)(gap / shrinkFactor);
swapped = false;
for (int i = 0; i + gap < list.Count; i++)
{
if (list[i].CompareTo(list[i + gap]) > 0)
{
var t = list[i];
list[i] = list[i + gap];
list[i + gap] = t;
swapped = true;
}
}
}
}
}
}
結果は次の通り。
適当に比較したときは処理時間がArray.Sortの2倍以上で話にならないと思っていたけど、要素数が膨大になるにつれてそれなりに差が小さくなってきて少し嬉しい。
comb sortは遅いけどバブルソートの改良版と考えるとそれなりに良いような気がする。
size: 1000
radix sort: 3541 (2.88)
comb sort: 27689 (22.50)
Array.Sort: 1230 (1.00)
size: 10000
radix sort: 20451 (1.68)
comb sort: 417744 (34.33)
Array.Sort: 12167 (1.00)
size: 100000
radix sort: 207950 (1.45)
comb sort: 5288921 (36.95)
Array.Sort: 143143 (1.00)
size: 1000000
radix sort: 2081360 (1.30)
comb sort: 65056745 (40.50)
Array.Sort: 1606207 (1.00)
0 件のコメント:
コメントを投稿