我正在寻找为一组二维点计算哈希码的最佳方法(这样我就可以在哈希表中存储多边形)。
有一些明显的方法可以做到这一点,例如连接字符串中的所有点坐标及其哈希码,但这会非常慢。
在速度/碰撞频谱的另一端,我还可以例如总结所有坐标,这将导致非常快的代码,但也会产生大量碰撞。
为一组点计算哈希码的最佳方法是什么??
如果坐标是整数(对比实际坐标),最佳解是不同的吗?
编辑:我正在使用.net,因此哈希码应该是32位长。
答案 0 :(得分:11)
这项工作没有最佳方式。这一切都取决于你能承受多大的哈希。你必须在速度和扩散之间进行传统。请记住,没有最佳解决方案(如果你不确切知道你要干什么)在某些情况下,xor可以很好。
以此代码为例
unsigned int JSHash(char* str, unsigned int len)
{
unsigned int hash = 1315423911;
unsigned int i = 0;
for(i = 0; i < len; str++, i++)
{
hash ^= ((hash << 5) + (*str) + (hash >> 2));
}
return hash;
}
/* End Of JS Hash Function */
你说聚合点在一起就是放慢速度。如果你修复上面的代码它不需要任何类型的agregation只是通过trought(没有多少不同的总和)如果你使用integeres和浮动你可能会修复轮班(&lt;&lt;&gt;&gt;是转换操作,一起工作就像按位旋转一样)以适合您的数据类型。
在这里检查其他哈希函数: http://www.partow.net/programming/hashfunctions/
答案 1 :(得分:1)
Optimal 取决于您对哈希计算的要求。
性能将以更多哈希冲突为代价。
你们两个都有困难吗?这将归结为数学分析,表明每个哈希冲突的百分比将在性能方面花费你多少。
答案 2 :(得分:1)
如果您的数据集中任何一个多边形可以有共同边但不重叠,那么您只需要在每个多边形中的三个点上进行散列以避免碰撞。
编辑:重新考虑这一点,想象可能与凹/凸边界的碰撞,你的多边形重叠也是如此。 - 叹息
唉:当凸面和凹面相遇时,它总会让我陷入困境。 :-P答案 3 :(得分:0)
答案 4 :(得分:0)
或者,您可以对各个点的哈希进行异或。
return p1.GetHashCode() ^ p2.GetHashCode()
根据价值观的不同而定。可能只是添加它们。
答案 5 :(得分:0)
如果您希望顺时针和逆时针定义的多边形相等,则必须创建规范化函数。从任意点开始以任何顺序给出多边形点的函数将以相等的顺序返回点。
我能想到的一种算法是找到所有可能的点序列中的最小值:
对于完全退化多边形,这是O(n ^ 2)最坏情况,但如果你的多边形没有重叠点,那么这是O(n),具有非常小的常数因子。
使用规范化顺序,您可以轻松地比较两个多边形的相等性,只需迭代地比较点的相等性。散列码计算也很简单,使用任何合理的鲁棒散列组合方法。例如:
int result = 0;
foreach (var point in this.points) {
result = (result * 31 + point.X.GetHashCode()) * 31 + point.Y.GetHashCode();
}
答案 6 :(得分:0)
对于非常快速(计算)具有顺时针/逆时针独立性的所需属性的哈希,您不希望依赖于找到明确定义的点的顺序。
这会将哈希组合操作限制为通勤的操作。因此,我们希望在组合操作期间保留与方向无关的任何和所有数据。
这是一个简单的解决方案:
假设一个组合函数int - &gt; int - &gt; int是关联的 以下任何一项都可以从:
开始public static int combine(int h, int x)
{
return h * 31 + x;
}
public static int combine(int h, int x)
{
return h ^ x;
}
然后我们可以执行以下操作:
public override int GetHashCode()
{
int x = 0;
int y = 0;
uint h = 0;
foreach (var point p in polgon)
{
x = combine(x, p.X);
y = combine(y, p.Y);
h++;
}
// simplified, unrolled Murmur2 hash for end stage
const uint m = 0x5bd1e995;
const int r = 24;
uint h = count;
uint k = ReinterpretInt32ToUInt32(x);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = ReinterpretInt32ToUInt32(y);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
// avalanche
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return ReinterpretUInt32ToInt32(h);
}
依靠这个来使上面的代码变得容易
public unsafe uint ReinterpretInt32ToUInt32(int i)
{
return *((uint*) (void*) &i);
}
public unsafe int ReinterpretUInt32ToInt32(uint u)
{
return *((int*) (void*) &u);
}
这在避免碰撞方面不是最好的哈希值,但计算速度非常快,您可能会发现它足以满足您的需求。