四个无符号整数的散列函数(C ++)

时间:2009-11-30 06:23:18

标签: c++ hash integer

我正在编写一个程序,它产生四个无符号32位整数作为某个函数的输出。我想要散列这四个整数,所以我可以将这个函数的输出与未来的输出进行比较。

我在写一个像样的散列函数时遇到了麻烦。当我最初编写这段代码时,我简单地添加了四个整数中的每一个,我知道这是不够的。我尝试了其他几种技术,例如转移和添加,但无济于事。我得到一个哈希值,但它的质量很差,而且这个函数产生了大量的碰撞。

哈希输出可以是32位或64位整数。有问题的函数产生了数十亿个哈希值,因此冲突在这里是一个真正的问题,我愿意使用更大的变量来确保尽可能少的冲突。

任何人都可以帮我弄清楚如何编写高质量的散列函数吗?

7 个答案:

答案 0 :(得分:8)

为什么不将四个整数存储在合适的数据结构中并进行比较?除非存储是个问题,否则在这种情况下对它们进行散列的好处对我来说是不确定的。

如果存储是个问题,您可以使用其中一个分析的散列函数here

答案 1 :(得分:4)

这是一个相当合理的散列函数,从4个整数到1个整数:

unsigned int hash = in[0];
hash *= 37;
hash += in[1];
hash *= 37;
hash += in[2];
hash *= 37;
hash += in[3];

通过均匀分布的输入,它可以提供均匀分布的输出。输入的所有位都参与输出,每个输入值(尽管不是每个输入位)都会影响每个输出位。有可能它比产生输出的函数更快,在这种情况下没有性能问题。

还有其他具有其他特征的哈希值,但是除非另有证明,否则累积乘以素数是一个良好的开端。如果您愿意,可以尝试使用xor而不是添加来累积。无论哪种方式,都很容易产生碰撞(例如{1,0,a,b}与{0,37,a,b}碰撞所有a,b),所以你可能想要选择一个你认为具有的素数与您的函数中任何合理的实现错误无关。因此,如果你的函数中有很多模数运算,那么可以改用1000003。

答案 2 :(得分:3)

因为散列会产生冲突,所以无论如何都必须将密钥保存在内存中才能发现这些冲突。哈希映射和其他标准数据结构在内部簿记中执行此操作。

由于密钥太小,只需直接使用密钥而不是散列。这样会更快,并且不会发生碰撞。

答案 3 :(得分:1)

我完全同意Vinko - 只是将它们全部比较。如果您仍然需要良好的散列函数,则需要分析4个非整数整数的分布。然后你必须以某种方式制作散列函数,结果将在32位散列值的整个范围内均匀分布。

一个简单的例子 - 让我们假设大多数时候,每个函数的结果都在0到255之间。然后你可以轻松地将每个函数的低8位混合到你的哈希中。大多数情况下,你直接得到结果,有时(当一个函数返回一个更大的结果时)你就会发生碰撞。

总结一下 - 如果没有关于4个函数的结果如何分布的信息,我们无法帮助您获得良好的散列函数。

答案 4 :(得分:0)

为什么要哈希?看起来像std :: set或std :: multi集合更适合存储这种输出。您需要做的就是将四个整数包装在一个结构中并编写一个简单的比较函数。

答案 5 :(得分:0)

尝试使用CRCFNV。 FNV很好,因为它很快并且有一个定义的折叠位方法来获得“较小”的哈希值(即12位/ 24位/等)。

从128位(4 X 32位)数字生成64位哈希的好处有点值得怀疑,因为正如其他人所建议的那样,您可以将原始值用作集合中的键。您确实希望散列中的位数表示您最初拥有的值的数量。例如,如果数据集具有100,000个4X32位值,则可能需要17位或18位散列值,而不是64位散列值。

答案 6 :(得分:0)

可能有点矫枉过正,但请考虑Boost.Hash。生成非常简单的代码和良好的价值。