【发布时间】:2011-03-08 17:29:15
【问题描述】:
我需要在 GetHashCode 中为 BitArray 生成一个快速哈希码。我有一个字典,其中的键是 BitArrays,并且所有 BitArrays 的长度都相同。
有没有人知道一种从可变位数生成良好哈希的快速方法,就像在这种情况下一样?
更新:
我最初采用的方法是直接通过反射访问内部整数数组(在这种情况下,速度比封装更重要),然后对这些值进行异或。 XOR 方法似乎运作良好,即在 Dictionary 中搜索时不会过度调用我的“Equals”方法:
public int GetHashCode(BitArray array)
{
int hash = 0;
foreach (int value in array.GetInternalValues())
{
hash ^= value;
}
return hash;
}
但是,Mark Byers 建议并在 StackOverflow 其他地方看到的方法稍微好一些(我的测试数据的 XOR 调用为 16570 Equals 和 16608)。请注意,这种方法修复了前一种方法中的一个错误,即位数组末尾之外的位可能会影响哈希值。如果位数组的长度减少,就会发生这种情况。
public int GetHashCode(BitArray array)
{
UInt32 hash = 17;
int bitsRemaining = array.Length;
foreach (int value in array.GetInternalValues())
{
UInt32 cleanValue = (UInt32)value;
if (bitsRemaining < 32)
{
//clear any bits that are beyond the end of the array
int bitsToWipe = 32 - bitsRemaining;
cleanValue <<= bitsToWipe;
cleanValue >>= bitsToWipe;
}
hash = hash * 23 + cleanValue;
bitsRemaining -= 32;
}
return (int)hash;
}
GetInternalValues 扩展方法是这样实现的:
public static class BitArrayExtensions
{
static FieldInfo _internalArrayGetter = GetInternalArrayGetter();
static FieldInfo GetInternalArrayGetter()
{
return typeof(BitArray).GetField("m_array", BindingFlags.NonPublic | BindingFlags.Instance);
}
static int[] GetInternalArray(BitArray array)
{
return (int[])_internalArrayGetter.GetValue(array);
}
public static IEnumerable<int> GetInternalValues(this BitArray array)
{
return GetInternalArray(array);
}
... more extension methods
}
欢迎提出任何改进建议!
【问题讨论】:
-
您最大的问题是 GetHashCode 返回一个 int32。这仅允许大约 40 亿个不同的值。因此,对于最大大小为 32 位的位数组,您的 HashCode 只能是无冲突/唯一的。如果你想用你的 BitArrays 做大,我建议你去一个自定义的字典实现,它支持一个自定义的 GetHashCode,它支持 long 作为结果类型,甚至可能是一个 bool 数组
标签: c# .net dictionary gethashcode bitarray