ディクショナリ ルックアップと配列のバイナリ サーチ ルックアップの間のトレードオフ ポイントを見つけたかったのです。コレクションのサイズに応じて、ディクショナリの一定時間のルックアップと、バイナリ検索の対数時間のルックアップを期待していました。
しかし、次の結果を見て驚きました。
私は驚いた: 1. 二分探索は、最初は対数的に成長し、その後、はるかに速く成長します。2. ハッシュは最初はかなり一貫していますが、その後ゆっくりと成長し始めます。3. 二分探索は、ハッシュ ルックアップより優れていることはありません。以下は私のコードです。私は何を間違えましたか?
class Program
{
static void Main(string[] args)
{
var r = new Random();
var targets = Enumerable.Range(0, 1000 * 1000).Select(_ => r.Next(int.MaxValue)).ToList();
for (int totalCount = 1; totalCount < 1000*1000*10; totalCount*=2)
{
var a = Enumerable.Range(0, totalCount).Select(_ => r.Next(int.MaxValue)).Distinct().Select(v => new thing(v)).OrderBy(t => t.value).ToArray();
var d = a.ToDictionary(t => t.value);
var watch = new System.Diagnostics.Stopwatch();
{
watch.Start();
var found = targets.Select(t => BinarySearch(t, a)).Where(t => t != null).Count();
watch.Stop();
Console.WriteLine(string.Format("found {0} things out of {2} in {1} ms with binary search", found, watch.ElapsedMilliseconds, a.Length));
}
{
watch.Restart();
var found = targets.Select(t => HashSearch(t, d)).Where(t => t != null).Count();
watch.Stop();
Console.WriteLine(string.Format("found {0} things out of {2} in {1} ms with hash search", found, watch.ElapsedMilliseconds, d.Keys.Count));
}
}
Console.ReadLine();
}
static thing HashSearch(int needle, Dictionary<int, thing> hash)
{
if (!hash.ContainsKey(needle))
return null;
return hash[needle];
}
static thing BinarySearch(int needle, thing[] sortedHaystack)
{
return BinarySearch(needle, sortedHaystack, 0, sortedHaystack.Length - 1);
}
static thing BinarySearch(int needle, thing[] sortedHaystack, int minimum, int maximum)
{
if (minimum > maximum)
return null;
var middle = (minimum + maximum) / 2;
if (needle == sortedHaystack[middle].value)
return sortedHaystack[middle];
if (needle < sortedHaystack[middle].value)
return BinarySearch(needle, sortedHaystack, minimum, middle - 1);
return BinarySearch(needle, sortedHaystack, middle + 1, maximum);
}
class thing
{
public int value;
public thing(int v)
{
value = v;
}
}
}