不要试图在一个已经被广泛报道的主题上写一篇新文章,请参阅
wikipedia关于哈希函数的文章。特别是第一张图片清楚地显示了如何将多个输入散列到相同的值。基本上,您的三元组将被散列到范围为[0,2 ^ 64-1](允许重复)的某些哈希值中。然后通过方程式hash = hash%n将该范围缩小到略大于您的输入值的数量(例如n = 5)。对于输入值[(1,1,1),(1,2,3),(2321,322,232),(3,3,3)],得到的关系将看起来像这样:
(1,1,1) -> 2
(1,2,3) -> 0
(2321, 322, 232) -> 0
(3,3,3) -> 3
正如您所看到的,没有任何输入值与1或4相关联(即哈希),而有两个输入值哈希为0。
通过注意到从哈希表中检索输入值(例如(1,1,1))需要执行以下步骤,可以清楚地看出哈希的强大之处(以及平均情况为O(1)的原因)。
- 计算输入值的哈希并应用
hash = hash%n
,因此(1,1,1)-> 2。
- 执行直接的O(1)查找,即
hash_function [2] =(1,1,1)+存储在此特定输入值中的其他数据
。
- 完成!
在多个输入值映射到相同的哈希值(在我们的示例中为0)的情况下,内部算法需要对这些输入值进行搜索,通常使用红黑树进行搜索(最坏情况为
O(log n)
)。任何查找的最坏情况也是
O(log n)
。
完美的哈希发生在关系变成一对一到函数(双射)时。这会提供最佳性能,但很少见。正如我之前所说,幸运的是,几乎完美的哈希很容易产生,其中重复很少。实质上,使您的哈希函数尽可能随机。
我在评论中给出的示例可能足够(也是错误的方法:),但更标准的计算方式是:hash = ((((prime1 + value1) * prime2) + value2) * prime3) + value3) * prime4
这也回答了问题。请注意,素数可以是任何素数,但通常使用31、37等较小的值。
在实践中,测试可用于检查性能,但通常不必要。
无论如何,重新阅读您的问题,我想知道为什么您不放弃整个哈希思想,而只是将点存储在简单的数组中?
hash = (x * 31) + (y * 37) + (z * 41)
就足够了。 - Florishash = (x * 18397) + (y * 20483) + (z * 29303)
,假设您的哈希值可以高达2^48。 - Florishash = x * 16777216 + y * 4096 + z
也可以避免碰撞,仅使用36位(每个坐标为12位)。它可以使用位移来实现。但是,如果将其缩小为某个较小的二次幂,则性能会非常差,这在实际哈希映射中可能发生。 - MvG