为什么GetHashCode方法需要在C#中进行移位
这个问题在这里已经有了答案:
我不能说他们为什么选择这个特定的哈希代码实现,但对于这个问题:
这里的ShiftAndWrap()
方法是一种算法的通用实现,用于将值左移N位,并将溢出包回到结尾。 所以在他们进行转换之前,他们首先得到最左边的N位,这样他们就可以将它们追加到最后。
因此,如果我们只使用8位值( byte
s)并将其称为value
=(二进制)11010010和positions
= 3,则调用ShiftAndWrap()
将看起来像这样:
value = 11010010
positions = 3
wrapped = value >> (8 - positions)
= 11010010 >> (8 - 3)
= 11010010 >> 5
= 00000110
result = value << positions | wrapped
= 11010010 << 3 | 00000110
= 10010000 | 00000110
= 10010110
我们可以看到,返回值10010110
是将11010010
移位三位并包围结果的结果。
至于他们为什么不使用x ^ y
,我怀疑这是因为这意味着Point(N, M)
将总是产生与Point(M, N)
相同的散列码。 通过对x
值进行移位,我们可以得到一个哈希码,它不仅考虑x
和y
值,还考虑它们的顺序,而x ^ y
会忽略它们的顺序。
在对包含相同类型子组件的数据结构进行散列处理时,散列函数对每个子组件进行不同处理是很常见的,因此它们的位置很重要。 例如,Java使用这个散列公式来表示字符串(这里^
表示一个指数,而不是XOR):
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
我们可以看到,每个字符乘以31的不同幂,所以stop
具有与pots
不同的散列码。
至于他们为什么选择2
作为转移职位的数量,可能是任意的,或者他们可能已经做了一些评估,看看可能产生最佳分配的转变程度。
HashCode
的要点是创建一个分布,以便数据结构可以将数据分配到特定的桶中。 它并不意味着平等。
如果您查看HashSet
的内部结构,您可以看到该类使用HashCode
标识正确的存储桶,然后使用Equals
方法确定相等性。
/// <summary>
/// Checks if this hashset contains the item
/// </summary>
/// <param name="item">item to check for containment</param>
/// <returns>true if item contained; false if not</returns>
public bool Contains(T item) {
if (m_buckets != null) {
int hashCode = InternalGetHashCode(item);
// see note at "HashSet" level describing why "- 1" appears in for loop
for (int i = m_buckets[hashCode % m_buckets.Length] - 1; i >= 0; i = m_slots[i].next) {
if (m_slots[i].hashCode == hashCode && m_comparer.Equals(m_slots[i].value, item)) {
return true;
}
}
}
// either m_buckets is null or wasn't found
return false;
}
所以碰撞很好,它只是在那里,所以确保一个相对平等的分布,以便更快地识别和检索。 这意味着,在你的情况下,这两个点将被放置在同一个桶中,但它们的Equals
方法将用于识别它们。