This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace HashVsBinary | |
{ | |
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; | |
} | |
} | |
} | |
} |
The abnormalities are probably due to caching. There's two places where the slope changes. Those probably correspond to different layers of memory. Maybe first an L2 cache miss, and then an L3 cache miss.
I also implemented an iterative binary search:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static thing BinarySearch(int needle, thing[] sortedHaystack) | |
{ | |
var min = 0; | |
var max = sortedHaystack.Length - 1; | |
while (min <= max) | |
{ | |
var middle = (min + max) / 2; | |
if (needle == sortedHaystack[middle].value) | |
return sortedHaystack[middle]; | |
if (needle < sortedHaystack[middle].value) | |
{ | |
max = middle - 1; | |
} | |
else | |
{ | |
min = middle + 1; | |
} | |
} | |
return null; | |
} |
It did not perform significantly better. Hashtable was still always faster.
No comments:
Post a Comment