我必须处理数字序列,其中序列具有以下属性:
给定一个序列,我想知道这个序列是否已经发生,那就是我想要哈希序列。例如,
[2, 3, 6, 2, 13]
和
[6, 3, 2, 13, 2]
应具有相同的哈希值。
使用的编程语言是C.
我知道我可以先对序列进行排序,然后将它们存储在trie中,这绝对是一种选择。然而,为此目的,什么是适当的哈希函数?
答案 0 :(得分:3)
要求
- 元素的顺序无关紧要
让我立刻想到Zobrist hashing之类的东西。也就是说,你有一个函数f
将整数映射到随机位串,你的散列就是与序列中数字对应的位串的XOR。
当然,上面描述的基本Zobrist哈希不能满足你的其他要求
- 允许多次出现元素
因为XOR运算是它自己的反转(即任何a XOR a = 0
的{{1}})。但是,简单地用一些其他ring操作替换XOR而没有这个属性(在正常的Zobrist散列中,实际上被认为是可取的),例如 n -bit的加法,应该产生类似的散列你想要的:
a
(关于这个函数的一个小细节是,如果你想截断它的输出,使用高位而不是低位稍微好一点。这是因为,如果 k 最低序列unsigned int hash_multiset (int *seq, int n) {
unsigned int h = 0;
while (n--) h += f( *seq++ );
return h;
}
和[a]
的哈希比特会发生冲突, k [b]
,[a, a]
,{{1}的最低位也会发生冲突对于 k 最高位,这不是真的,因为较低的位可以转移到较高的位,产生更多的“随机”输出。)
有多种方法可以实现函数[b, b]
。对于有限范围的输入整数,您可以简单地使用随机位串的固定查找表。或者,如果您事先不知道输入的范围,则可以使用另一个(普通)哈希表将整数映射到随机位串,然后“动态”构建它。
最后,也可以在没有查找表的情况下实现[a, b]
,只需使用“看起来足够随机”的固定函数即可。这种功能的一个好选择是使用简单快速的block cipher,例如TEA或(在具有硬件支持的系统上)AES,输出被截断为你的首选哈希长度。
答案 1 :(得分:1)
如何将序列的所有数字和长度相乘,以一些相当大的数量为模?这是一些显示计算的Scala代码:
val l = List(6, 3, 2, 13, 2)
(l.reduce(_ * _) * l.length) % 10000
结果为:4680。
显然,这并不能保证如果哈希匹配,则序列是唯一的。 (它甚至可能不是一个非常好的近似值!)但是,如果哈希不匹配,则保证序列不相同。