7

我正在研究一个哈希冲突会成为问题的系统。本质上,有一个系统引用哈希表+树结构中的项目。然而,所讨论的系统首先将包含结构中路径的文本文件编译成包含散列值的二进制文件。这样做是出于性能原因。然而,由于这种冲突非常糟糕,因为该结构不能存储具有相同哈希值的 2 个项目;要求物品的部分没有足够的信息来知道它需要哪一个。

我最初的想法是,使用 2 种不同算法或两次使用相同算法的 2 次哈希使用 2 种盐会更耐碰撞。对于不同的散列算法,两个项目具有相同的散列是不太可能的。

出于空间原因,我希望将哈希值保持为 32 位,所以我想我可以切换到使用两种 16 位算法而不是一种 32 位算法。但这不会增加可能的哈希值的范围......

我知道切换到两个 32 位哈希会更耐冲突,但我想知道切换到 2 个 16 位哈希是否至少比单个 32 位哈希有一些收益?我不是最喜欢数学的人,所以我什至不知道如何开始检查答案,除了强加它......

系统的一些背景:

项目由人类命名,它们不是随机字符串,通常由单词、字母和数字组成,没有空格。它是一个嵌套的哈希结构,所以如果你有类似 { a => { b => { c => 'blah' }}} 的东西,你会通过获取 a/b/c 的值来获得值 'blah',编译后的请求将是立即序列中的 3 个哈希值,a、b 和 c 的哈希值。

只有在给定级别发生碰撞时才会出现问题。顶层项目和较低层项目之间的冲突是正常的。你可以有 { a => {a => {...}}},几乎可以保证不同级别的碰撞(不是问题)。

实际上,任何给定级别的哈希值都可能少于 100 个,并且在同一级别上没有一个是重复的。

为了测试我采用的散列算法(忘记是哪个,但我没有发明它)我下载了整个 CPAN Perl 模块列表,将所有命名空间/模块拆分为唯一的单词,最后对每一个进行散列搜索以查找冲突,我遇到了 0碰撞。这意味着该算法对于 CPAN 命名空间列表中的每个唯一单词都有不同的哈希值(或者我做错了)。这对我来说似乎已经足够好了,但它仍然在我的脑海中挥之不去。

4

1 回答 1

9

如果您有 2 个 16 位散列,它们产生不相关的值,那么您刚刚编写了一个 32 位散列算法。这不会比任何其他 32 位哈希算法更好或更差。

如果您担心冲突,请确保您使用的哈希算法可以很好地对您的数据进行哈希处理(有些只是为了计算速度快,这不是您想要的),并增加您的哈希直到你舒服为止。

这就提出了碰撞概率的问题。事实证明,如果你n的收藏中有东西,就会有n * (n-1) / 2成对的东西可能发生碰撞。如果您使用的是k位散列,则单对碰撞的几率为. 如果你有很多东西,那么不同对碰撞的几率几乎是不相关的。这正是泊松分布所描述的情况。2-k

因此,您将看到的碰撞次数应大致遵循泊松分布,其中. 由此看来,没有哈希冲突的概率约为. 使用 32 位和 100 个项目,在一个级别中发生碰撞的几率约为百万分之 1.1525。如果你这样做的次数足够多,并且有足够多的不同数据集,最终百万分之一的机会就会加起来。λ = n * (n-1) * 2-k-1e

但请注意,您有许多正常大小的关卡和一些较大的关卡,较大的关卡会对您的碰撞风险产生不成比例的影响。那是因为你添加到集合中的每一个东西都可能与前面的任何东西发生碰撞——更多的东西等于更高的碰撞风险。因此,例如,具有 1000 个数据项的单个级别大约有 10,000 个失败的机会 - 这与具有 100 个数据项的 100 个级别的风险大致相同。

如果散列算法不能正常工作,你的碰撞风险会迅速上升。多快在很大程度上取决于故障的性质。

使用这些事实和您对应用程序使用情况的预测,您应该能够决定您是否对 32 位哈希的风险感到满意,或者您是否应该升级到更大的东西。

于 2011-04-06T05:01:40.123 回答