C# guid tostring作为字典键的近似完美哈希

C# guid tostring作为字典键的近似完美哈希,c#,.net,C#,.net,我试图解决的问题:使用guid字符串作为字典的键(string,someObject),我希望对键进行完美的哈希 不确定我是否遗漏了什么。。。当我使用dictionary构造函数运行下面的测试时,仅传入大小分配,每次运行时我会得到+-10个冲突。当我传入IEqualityComparer时,只要在字符串上调用gethashcode,我就可以让测试顺利通过!在某些情况下,使用x=10次迭代进行多次运行,y最多可达一百万次!我以为字典正在调整哈希函数,尤其是在处理字符串时?我的机器上没有反射器:(所

我试图解决的问题:使用guid字符串作为字典的键(string,someObject),我希望对键进行完美的哈希

不确定我是否遗漏了什么。。。当我使用dictionary构造函数运行下面的测试时,仅传入大小分配,每次运行时我会得到+-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();
    }
}
[TestMethod]
public void nearPerfectHashingForGuidestrings()
{
int y=100000;
int=0;
//字典列表=新字典(y,new GuidStringHashing());
字典列表=新字典(y);
对于(int x=0;x<5;x++)
{
可枚举的.Range(1,y).ToList().ForEach((h)=>
{
列表[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));
碰撞+=hashDuplicates.Count();
list.Clear();
}
Assert.AreEqual(0,冲突);
}
公共类GuidStringHashing:IEqualityComparer
{
公共布尔等于(字符串x、字符串y)
{
返回GetHashCode(x)==GetHashCode(y);
}
public int GetHashCode(字符串obj)
{
返回obj.GetHashCode();
}
}
您的测试失败

因为您的相等比较器错误地报告两个恰好具有相同哈希的不同GUID相等,所以您的字典从不首先存储冲突


由于的原因,根本不可能为超过232个项创建32位完美哈希。

这是不可能的。您需要为未知的密钥集创建完美哈希函数。您可以。您不能创建一个适用于所有密钥集的完美哈希函数


原因是“两个耶稣原则”,正如马克·克诺普勒(Mark Knopfler)所说:“两个人说他们是耶稣,其中一个肯定是错的。”(更广为人知的是“鸽子洞原则”)

你所说的完美散列码是什么意思

您的代码有些混乱,特别是因为您发布了一个测试方法未使用的类
GuidStringHashing

但您的代码表明,当您创建100000个GUI,将它们全部转换为字符串,然后获取字符串的哈希代码时,常常会出现并非所有哈希代码都是不同的情况。当有40多亿个整数可供选择,而您只生成100000个字符串时,这可能会令人惊讶

您将
GetHashCode()
用于常规字符串,但是您的字符串不是太常规,它们都类似于

"2315c2a7-7d29-42b1-9696-fe6a9dd72ffd"
因此,可能您的哈希代码不是最佳的。最好将字符串
h
解析回GUID,并使用该GUID的哈希代码,如
(新GUID(h))。GetHashCode()

然而,这仍然会与100000个guid发生冲突。我想你看到的只是一个例子

试试这个更简单的代码。这里我在guid上使用
GetHashCode()
,因此我们希望整数是非常随机的:

        var set = new HashSet<int>();
        for (int i = 1; true; ++i)
        {
            if (!set.Add(Guid.NewGuid().GetHashCode()))
                Console.WriteLine("Collision, i is: " + i);
        }
var set=newhashset();
for(int i=1;true;++i)
{
如果(!set.Add(Guid.NewGuid().GetHashCode()))
控制台.WriteLine(“碰撞,i为:+i”);
}

我们看到(通过多次运行上述代码)冲突几乎总是在计算100000个哈希代码之前发生。

这基本上是不可能的。32位中的每个128位GUID不能有唯一的哈希。@SLaks这是有意义的,但是如果我只指定100000个项并运行几百次测试,那么“基本上”它每次都可以通过?w我的意思是,使用传入的IEqualityComparer测试可以通过,现在每次使用字典中的defualt哈希函数都会失败,这更符合您的鸽子洞注释。由于int32哈希代码,我预计2147483647项之后至少会发生一次冲突,但根据测试结果,我只处理100000项在这个域空间上应该可以得到一个“接近”完美的哈希,当对字符串调用gethashcode比默认的字典hashingAlso要好得多时,我有点震惊,有趣的是:。根据接近末尾的表,对于32位哈希函数,哈希代码的数量需要有超过50%的几率为1碰撞仅为77000次。100000次可能会发生多次碰撞。Matthew Watson完全正确;您的预期与现实完全不符。我这里有一个32位哈希后发生多次碰撞的概率图:--正如您所见,仅10000次哈希时,一次碰撞的概率已经超过1%s、 上面的测试没有使用我的IEqualityComparer,它被注释掉了?你的评论是“当我通过IEqualityComparer时,只要调用字符串上的gethashcode,我就可以通过测试”这意味着您使用了错误的相等比较器,并且-因为它是错误的-得出了错误的结论。他的测试代码并不漂亮,但它确实确定了当您创建100000个GUI时,将它们转换为字符串,然后对字符串调用
.GetHashCode()
,然后在统计上会发生冲突。另外,由于“具有相同的哈希代码”是一个等价词