应用Rabin-Karp Hash进行大N.

时间:2014-03-02 22:16:13

标签: c# java algorithm hash

我指的是Rabin Karp Wikipedia article on Hash use.

在示例中,字符串"hi"使用素数101进行哈希处理。

hash("hi")= ASCII("h")*101^1+ASCII("i")*101^0 = 10609 

这种算法是否可以在Java或C#中实际使用,其中long的最大值为9,223,372,036,854,775,807?天真地,对我来说,似乎哈希值呈指数增长,并且具有足够大的N(字符串长度)将导致long类型的溢出。例如,假设我的字符串输入中有65个字符用于哈希?

这是正确的,还是有永远不需要溢出的实现方法(我可以想象一些懒惰的评估只能将ascii和单位存储在主要基础中)?

2 个答案:

答案 0 :(得分:1)

如果您的目标是一种仅包含“小”号的存储,则 但可以比较总和:

你可以简单地将其视为101号码系统,
像10 =十进制,16 =十六进制。等等。
IE浏览器。

a)你必须存储一组{ascii值,它是101-power}
(没有可能具有相同功率的多个条目)。

b)从字符串创建数据时,
值> 101必须传播(这是正确的词?)到下一个幂。

示例1:
“a”是97 * 101 ^ 0
(琐碎的)

例2:
“g”是1 * 101 ^ 1 + 2 * 101 ^ 0
因为g是103. 103> = 101即。 101 ^ 101只占103%101 (模数,除法的余数)
和(int)(103/101)为下一个权力。

(如果ascii numers可能更高或者素数低于101
(int)(103/101)也有可能超过主要数字 在这种情况下,它将继续填充^ 2,依此类推,直到值较小为止 比素数)

例3:
“ag”是98 * 101 ^ 1 + 2 * 101 ^ 0
与上述相比,由于a增加了97 * 101 ^ 1。 等等...

在不计算全额的情况下进行比较,
只需将每个电源的功率值相互比较即可 如果所有“功率值”相同则相等。

附注:请注意,^不是C#和Java等语言中的取幂。

答案 1 :(得分:1)

hash("hi")= ASCII("h")*101^1+ASCII("i")*101^0 = 10609

这只是事实的一半。实际上,如果你实际上计算了值s_0 * p^0 + s_1 * p^1 + ... + s_n * p^n,结果将是一个数字,其表示与字符串本身一样长,所以你没有获得任何东西。所以你实际做的是计算

(s_0 * p^0 + s_1 * p^1 + ... + s_n * p^n) mod M

其中M相当小。因此,您的哈希值将始终小于M

所以你在实践中做的是选择M = 2^64并利用无符号整数溢出在大多数编程语言中定义良好的事实。事实上,Java,C ++和C#中64位整数的乘法和加法相当于乘法和加法模2^64

使用2^64作为模数不一定是明智的选择。实际上,您可以轻松地构造一个包含大量碰撞的字符串,从而引发Rabin-Karp的最坏情况行为,Ω(n * m)匹配而不是O(n + m)

最好使用大质数作为模量并获得更好的抗碰撞性。通常没有这样做的原因是性能:我们需要明确地使用模块化缩减(添加% M)到每个加法和乘法。更糟糕的是,我们甚至不能再使用内置乘法,因为如果M > 2^32它可能会溢出。所以我们需要一个自定义MultiplyMod函数,它必然比机器级乘法慢很多。

  

这是正确的,还是有永远不需要溢出的实现方法(我可以想象一些懒惰的评估只能将ascii和单位存储在主要基础中)?

正如我已经提到的,如果你不减少使用模数,你的哈希值将增长到与字符串本身一样大,从而使得首先使用哈希函数变得无用。所以是的,使用受控溢出模2^64是正确的,如果我们不手动减少,甚至是必要的。

相关问题