【发布时间】:2011-12-22 00:15:59
【问题描述】:
我在 .NET4 中使用短字符串时遇到哈希冲突问题。
编辑:我在 .NET 中使用内置字符串哈希函数.
我正在使用像这样存储转换方向的对象来实现缓存
public class MyClass
{
private string _from;
private string _to;
// More code here....
public MyClass(string from, string to)
{
this._from = from;
this._to = to;
}
public override int GetHashCode()
{
return string.Concat(this._from, this._to).GetHashCode();
}
public bool Equals(MyClass other)
{
return this.To == other.To && this.From == other.From;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
if (this.GetType() != obj.GetType()) return false;
return Equals(obj as MyClass);
}
}
这取决于方向,from 和 to 由“AAB”和“ABA”等短字符串表示。
我遇到了这些小字符串的稀疏哈希冲突,我尝试了一些简单的方法,比如添加盐(没有用)。
问题是我的太多像“AABABA”这样的小字符串与“ABAAAB”相反的哈希值冲突(请注意,这些不是真实的例子,我不知道 AAB 和ABA 实际上会导致冲突!)
我已经完成了像实现 MD5 一样的繁重任务(它有效,但速度要慢得多)
我也在这里执行了 Jon Skeet 的建议:
Should I use a concatenation of my string fields as a hash code?
这可行,但我不知道它对我的各种 3 个字符的字符串有多可靠。
如何改进和稳定小字符串的散列而不像 MD5 那样增加太多开销?
编辑:作为对发布的一些答案的回应...缓存是使用从MyClass 键入的并发字典实现的,如上所述。如果我将上面代码中的GetHashCode 替换为我发布的链接中的@JonSkeet 代码之类的简单代码:
int hash = 17;
hash = hash * 23 + this._from.GetHashCode();
hash = hash * 23 + this._to.GetHashCode();
return hash;
一切都按预期运行。 还值得注意的是,在这个特定的用例中,缓存不在多线程环境中使用,因此不存在竞争条件。
编辑:我还应该注意,这种不当行为取决于平台。它在我完全更新的 Win7x64 机器上按预期工作,但在未更新的 Win7x64 机器上运行不正常。我不知道缺少哪些更新的范围,但我知道它没有 Win7 SP1 ......所以我假设可能还有一个框架 SP 或更新它也丢失了。
编辑: 如前所述,我的问题不是由散列函数问题引起的。我有一个难以捉摸的竞争条件,这就是为什么它可以在某些计算机上工作但不能在其他计算机上工作的原因,也是为什么“较慢”的散列方法可以使事情正常工作的原因。我选择的答案对于理解为什么我的问题不是字典中的哈希冲突最有用。
【问题讨论】:
-
您遇到了与 3 个字符的字符串发生冲突?想发布其中的一些吗?我怀疑不是散列函数。
-
你能展示一下缓存是如何实现的吗?
-
在您展示的代码中,Equals 不是“public virtual bool Equals(object obj)”的覆盖...您在下面引用了哪些更新?
-
我对生成的 3 + 3 对进行了一些简单的测试。第一种情况(使用 Concat)的碰撞率为 1.7,第二种情况下的碰撞率为 4。正如预期的那样,第二个会产生更多的碰撞(但在这种情况下会更好,因为它不会创建新对象)。而且我看不出碰撞如何导致您的问题。在 Dictionary 中预期并正确处理碰撞。它更多的是关于 Equals,但它看起来不错。 MyClass 看起来不错。我会说这个问题在这个类之外的某个地方 - 如何使用字典,如何创建 MyClass 实例等等......
-
@Downvoter,需要解释一下吗?我可能在这里寻求解决方案的方向错误,但我肯定会努力解决这个问题......
标签: c# .net string hash collision