简单地说,我有很多(x,y)形式的点。
我想把这些点放入一个哈希表中,点是键。
我应该如何实现类hashCode()
的{{1}}方法?以Java为语言
Point
答案 0 :(得分:2)
数字往往聚集在大多数坐标平面上;因为,我们倾向于使用舒适范围内的数字。出于这个原因,不可取的是微不足道的xor组合,因为x == y
将碰撞的所有数字,以及x + 1 == y
等所有数字都会发生冲突。
为避免这种情况,我建议您在使用x坐标进行x坐标之前反转y坐标的字节。这将组合一个输入的大多数可变性(低位字节)的区域与另一个输入的最小可变性区域(高位字节)。在考虑数字簇时(例如x的值在1和1000之间),这样的算法将给出更均匀的分布。
由于哈希算法在散列产生数字字段而没有大量聚类时效果最好,因此这种解决方案实际上会使哈希相关的数据结构更快,因为哈希冲突的频率较低。
以下是当然没有优化的,你可以根据自己的需要修改它,但这是基本的想法:
public int hashCode() {
long bits = Double.doubleToLongBits(y);
byte[] ybits = new byte[] {
(byte)((y >> 56) & 0xff),
(byte)((y >> 48) & 0xff),
(byte)((y >> 40) & 0xff),
(byte)((y >> 32) & 0xff),
(byte)((y >> 24) & 0xff),
(byte)((y >> 16) & 0xff),
(byte)((y >> 8) & 0xff),
(byte)((y >> 0) & 0xff),
};
byte[] xbits = new byte[] {
(byte)((x >> 56) & 0xff),
(byte)((x >> 48) & 0xff),
(byte)((x >> 40) & 0xff),
(byte)((x >> 32) & 0xff),
(byte)((x >> 24) & 0xff),
(byte)((x >> 16) & 0xff),
(byte)((x >> 8) & 0xff),
(byte)((x >> 0) & 0xff),
};
// this combines the bytes of X with the reversed order
// bytes of Y, and then packs both of those into 4 bytes
// because we need to return an int (4 bytes).
byte[] xorbits = new byte[] {
(xbits[0]^ybits[7])^(xbits[4]^ybits[3]),
(xbits[1]^ybits[6])^(xbits[5]^ybits[2]),
(xbits[2]^ybits[5])^(xbits[6]^ybits[1]),
(xbits[3]^ybits[4])^(xbits[7]^ybits[0]),
};
int value = 0;
for (int i = 0; i < 3; i++) {
value = (value << 8) + (by[i] & 0xff);
}
return value;
}
我建议的初始优化是将哈希码缓存在对象中以供后续查找,如果分析表明它是一个问题,也许更有效地管理创建/销毁的数组。
答案 1 :(得分:0)
我不确定双人的哈希有多好,但你应该能够做到:
public int hashCode() {
return x.hashCode() ^ y.hashCode();
}
如果这在测试中产生了太多的冲突(你这样做了吗?),你可以通过位移,幻数等来改变它。所有类型的按位运算,确实。
这是Java吗?我的答案基于我对C#的经验。
答案 2 :(得分:0)
您可以使用您想要的任何功能。这一切都取决于您的坐标是什么样的典型值,以及您希望哈希函数有多好。
如果是你所有的点都在1到1百万的范围内,那么你可以使用这样的东西(这是C ++代码,不知道你使用的是哪种语言)。
size_t hashCode = (size_t)x * (size_t)y;
或者您可以添加值,或乘以值,或做任何您想做的事。
size_t hashCode = (size_t)(x+y);
或
size_t hashCode = (size_t)(x*y);
甚至
size_t hashCode = (size_t)(x*y) + (size_t)(x+y);