【发布时间】:2013-02-10 20:01:35
【问题描述】:
我要解决的问题:使用 guid 字符串作为 Dictionary(string, someObject) 的键,我希望 完美 对键进行散列...
不确定我是否遗漏了什么...当我使用字典构造函数运行以下测试时,仅传递大小分配我每次运行都会得到 +- 10 次冲突。当我传入 IEqualityComparer 时,只需在字符串上调用 gethashcode,我的测试就顺利通过了!在某些情况下使用 x = 10 次迭代进行多次运行,并且 y 高达一百万!我认为字典正在调整哈希函数,尤其是在处理字符串时?我的机器上没有反射器 :( 所以今晚我不能检查...如果您注释掉交替的字典初始化,您会看到...测试在我的 i7 上运行相对较快。
[TestMethod]
public void NearPerfectHashingForGuidStrings()
{
int y = 100000;
int collisions = 0;
//Dictionary<string, string> list = new Dictionary<string, string>(y, new GuidStringHashing());
Dictionary<string, string> list = new Dictionary<string, string>(y);
for (int x = 0; x < 5; x++)
{
Enumerable.Range(1, y).ToList().ForEach((h) =>
{
list[Guid.NewGuid().ToString()] = h.ToString();
});
var hashDuplicates = list.Keys.GroupBy(h => h.GetHashCode())
.Where(group => group.Count() > 1)
.Select(group => group.Key).ToList();
hashDuplicates.ToList().ForEach(v => Debug.WriteLine( x + "--- " + v));
collisions += hashDuplicates.Count();
list.Clear();
}
Assert.AreEqual(0, collisions);
}
public class GuidStringHashing : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return GetHashCode(x) == GetHashCode(y);
}
public int GetHashCode(string obj)
{
return obj.GetHashCode();
}
}
【问题讨论】:
-
这根本不可能。对于 32 位中的每个 128 位 GUID,您不能拥有唯一的哈希。
-
@SLaks 确实有道理,但如果我只指定 100000 个项目并运行测试几百次,那么“基本上”它每次都能通过?
-
我的意思是使用传入的 IEqualityComparer 测试可以通过,现在每次使用字典中的默认散列函数都会失败,这更符合您的鸽子评论。由于 int32 哈希码,我预计在 2,147,483,647 个项目之后至少会发生 1 次冲突,但我只根据测试处理 100000,因此应该有可能在该域空间上获得“接近”完美的哈希,当我洗有点震惊时在字符串上调用 gethashcode 比默认的字典哈希要好得多
-
另外,有趣的是:en.wikipedia.org/wiki/Birthday_attack。根据接近末尾的表格,对于 32 位哈希函数,一次冲突概率超过 50% 所需的哈希码数量仅为 77,000。如果有 100,000,您可能会发生多次冲突。
-
Matthew Watson 完全正确;你的期望与现实完全脱节。我有一张在 n 32 位散列后发生不止一次冲突的概率图:blogs.msdn.com/b/ericlippert/archive/2010/03/22/… - 正如你所看到的,只有 10000 个散列时发生一次冲突的可能性已经超过 1%,而在100000.