Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 应用Rabin-Karp散列法求大N_C#_Java_Algorithm_Hash - Fatal编程技术网

C# 应用Rabin-Karp散列法求大N

C# 应用Rabin-Karp散列法求大N,c#,java,algorithm,hash,C#,Java,Algorithm,Hash,我指的是 在本例中,使用素数101作为基数对字符串“hi”进行散列 hash("hi")= ASCII("h")*101^1+ASCII("i")*101^0 = 10609 在Java或C语言中,long的最大值为9223372036854775807,这样的算法可以实际使用吗?天真地说,在我看来,散列值似乎呈指数增长,如果N足够大(即字符串长度),将导致long类型溢出。例如,假设我的哈希字符串输入中有65个字符 这是正确的,还是有一些实现方法永远不需要溢出(我可以想象一些懒惰的计算,它

我指的是

在本例中,使用素数
101
作为基数对字符串
“hi”
进行散列

hash("hi")= ASCII("h")*101^1+ASCII("i")*101^0 = 10609 
在Java或C语言中,long的最大值为
9223372036854775807
,这样的算法可以实际使用吗?天真地说,在我看来,散列值似乎呈指数增长,如果N足够大(即字符串长度),将导致
long
类型溢出。例如,假设我的哈希字符串输入中有65个字符


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

如果您的目标是一种只包含“小”数字的存储类型,
但是,如果可以比较总额:

您可以简单地将其视为101数字系统,
比如10=十进制,16=十六进制。等等。

a) 您必须存储一组{ascii值,它是101幂}
(不可能有多个具有相同功率的条目)

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

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

例2:
“g”是1*101^1+2*101^0
因为g是103。103>=101即101^0仅取103%101 (模,除法余数)
和(int)(103/101)用于下一个电源

(如果ascii数字可能高于或素数低于101
(int)(103/101)也可能超过素数。
在这种情况下,它将继续素数^2,依此类推,直到值变小
(大于质数)

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

要进行比较而不计算全部总和,
只需将每种功率的一种功率值相互比较即可。
如果所有“功率值”相同,则为相等

旁注:请注意^在C#和Java等语言中不是指数运算

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
,并利用无符号整数溢出在大多数编程语言中定义良好这一事实。事实上,爪哇、C++和C 64位整数的乘法和加法相当于乘法和加法模<代码> 2 ^ 64 < /代码> .< 使用
2^64
作为模数并不一定是明智的选择。事实上,你可以很容易地构造一个包含大量碰撞的字符串,从而引发拉宾·卡普的最坏情况行为,即
Ω(n*m)
匹配,而不是
O(n+m)

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

这是正确的,还是有一些实现方法永远不需要溢出(我可以想象可能是一些懒惰的计算,它只将ascii和单位位置存储在素数基中)


正如我已经提到的,如果不使用模来减少,那么散列值将与字符串本身一样大,因此首先使用散列函数是无用的。因此,是的,使用受控溢出模
2^64
是正确的,如果我们不手动减少,甚至是必要的。

谢谢,这更有意义。你看过维基百科的文章了吗?我错过了还是他们完全忽略了使用模的步骤?@stevebot:我也差点错过了,但它就在那里,在关于散列函数的部分:“理论上,还有其他算法可以提供方便的重新计算,例如,将所有字符的ASCII值相乘,这样子字符串的移位只需要除以第一个字符并乘以最后一个字符。但是,限制是整数数据类型的大小有限,并且需要使用模块化算法来缩小散列结果(请参阅散列函数文章)