C# 二维点结构的“GetHashCode()”算法(避免冲突)是什么
考虑以下代码:C# 二维点结构的“GetHashCode()”算法(避免冲突)是什么,c#,hashcode,point,C#,Hashcode,Point,考虑以下代码: struct Vec2 : IEquatable<Vec2> { double X,Y; public bool Equals(Vec2 other) { return X.Equals(other.X) && Y.Equals(other.Y); } public override bool Equals(object obj) { if (obj is Vec2)
struct Vec2 : IEquatable<Vec2>
{
double X,Y;
public bool Equals(Vec2 other)
{
return X.Equals(other.X) && Y.Equals(other.Y);
}
public override bool Equals(object obj)
{
if (obj is Vec2)
{
return Equals((Vec2)obj);
}
return false;
}
// this will return the same value when X, Y are swapped
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
}
这将破坏一本字典的收藏。因此,问题是如何为2、3甚至4个浮点值形成GetHashCode()
函数的属性,以使结果不对称且哈希不冲突
编辑1:
Point
实现不适当的x^y
解决方案,并PointF
包装ValueType.GetHashCode()
Rectangle
有一个非常特殊的((X^((Y>19)))^((宽度>6))^((高度>25))
哈希代码表达式,它的性能似乎与预期的一样
编辑2:
“St.Bug”有一个很好的实现,因为它不考虑每个比特同样重要的
public override unsafe int GetHashCode() //from System.Double
{
double num = this;
if (num == 0.0)
{
return 0;
}
long num2 = *((long*) &num);
return (((int) num2) ^ ((int) (num2 >> 32)));
}
Jon skeet对此进行了介绍: 另外,将
Equals(object)
实现更改为:
return Equals(obj as FVector2);
但是请注意,这可能会认为派生类型是相等的。如果您不想这样做,您必须将运行时类型other.GetType()
与typeof(FVector2)
进行比较(不要忘记空性检查)感谢您指出它是一个结构,LukH
Resharper具有很好的代码生成功能,可以生成相等代码和哈希代码,因此,如果您有Resharper,您可以让它完成它的工作哈希冲突不会对字典集合造成严重破坏。如果你运气不好得到它们,它们会降低效率,但是字典必须处理它们
如果可能的话,冲突应该很少发生,但这并不意味着实现是错误的。XOR通常是不好的,因为您已经给出了(高碰撞)的原因——ohadsc已经发布了我之前给出的一个示例,作为替代,这应该是好的
请注意,要实现无冲突的Vec2
,是不可能的-从GetHashCode
中只有232个可能的返回值,但有更多可能的X和Y值,即使在删除NaN和无限值之后
Eric Lippert有一个on
GetHashCode
,您可能会发现它很有用。如果哈希代码的大小小于结构的大小,那么冲突是不可避免的。坐标的合理界限是什么
除非它可以是所有可能的整数值,否则您可以简单地:
const SOME\u LARGE\u NUMBER=100000;
返回一些大的数字*x+y 哈希码方法适用于整数坐标,但不建议用于浮点值。使用浮点坐标,可以使用排序序列结构创建点集/点池 排序序列是一个叶版本的平衡二叉树
这里的关键点是点坐标 以最小化冲突为目标是可以的,但您的代码必须预料到它们;它们总是会发生冲突-
int
的可能值范围小于double
,与double
相比,它甚至更小。此外,您可能需要考虑一个更宽松的相等性比较——由于舍入,两个浮点值可能非常接近(任何人通过眼睛进行比较)会考虑相等,但仍然不完全相等。由于X^X-->0 all(C,C)与all(D,D)发生冲突,这是一个更大的冲突空间。所讨论类型的可能副本是一个结构,因此不能将Equals(object)
实现更改为使用as
。OP当前的Equals(object)
方法没有问题。这可能很有效,但如果您查看Double.GetHashCode()
的计算,您会注意到使用了更仔细的重要位,我也愿意这样做。感谢您的回复,因为我已经为许多结构实现了这个版本。很高兴能提供帮助!请注意,当字段是浮点数时,位不是稠密的,而是遵循特定的模式,为结构提供合理的数字。因此,如果异或运算避免了最高有效位的对称性,那么它就足够了。这有意义吗?@ja72:可能。这取决于真实世界的数据。如果它们实际上是整数,这仍然很糟糕,但与(X=1,Y=5)和(X=5,Y=1)的冲突是不可接受的。与(3.287e308,-7,.228e175)及其对称对的冲突更容易接受。如果您知道边界,这确实是最好的。您也可以使用int
s和int.MaxValue
和unchecked
clause来表示int
s。您可以显示一些代码来解释您提到的内容。我很难想象它。我知道浮点精度会使GetHashCode()
变得不确定,但我不明白你打算如何解决这个问题。忘记GetHashCode(),你不使用哈希。刚刚使用了一个带xy比较器的平衡二叉树。我经常需要实现IEquatable
,因此需要使用哈希来覆盖。你能展示一些代码让我们理解你在说什么吗?顺便说一句,你可以使用快照网格转换成整数,然后使用这些函数中的一个进行哈希运算而不产生冲突。以唯一和确定的方式将两个整数映射为一个整数。
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + X.GetHashCode();
hash = hash * 23 + Y.GetHashCode();
return hash;
}
}
return Equals(obj as FVector2);