Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/316.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字符串搜索算法中使用的滚动哈希函数是否有任何有效的实现?_C#_Java_Algorithm_Hash_Rabin Karp - Fatal编程技术网

C# Rabin-Karp字符串搜索算法中使用的滚动哈希函数是否有任何有效的实现?

C# Rabin-Karp字符串搜索算法中使用的滚动哈希函数是否有任何有效的实现?,c#,java,algorithm,hash,rabin-karp,C#,Java,Algorithm,Hash,Rabin Karp,我希望使用一个滚动散列函数,这样我就可以对一个非常大的字符串的n-gram进行散列 例如: “stackoverflow”,分为5克: “stack”、“tacko”、“ackov”、“ckove”, “kover”、“overf”、“verfl”、“erflo”、“rflow” 这对于滚动散列函数非常理想,因为在我计算第一个n-gram散列之后,下面的计算相对便宜,因为我只需删除第一个散列的第一个字母,然后添加第二个散列的新的最后一个字母 我知道,一般情况下,此哈希函数的生成方式如下: H=c

我希望使用一个滚动散列函数,这样我就可以对一个非常大的字符串的n-gram进行散列

例如:

“stackoverflow”,分为5克:

“stack”、“tacko”、“ackov”、“ckove”, “kover”、“overf”、“verfl”、“erflo”、“rflow”

这对于滚动散列函数非常理想,因为在我计算第一个n-gram散列之后,下面的计算相对便宜,因为我只需删除第一个散列的第一个字母,然后添加第二个散列的新的最后一个字母

我知道,一般情况下,此哈希函数的生成方式如下:

H=c1ak− 1+c2ak− 2+c3ak− 3 + ... + cka0,其中a为常数,c1,…,ck为输入字符

如果您在上遵循此链接,它说明“a”通常是某个大素数

我希望我的散列存储在32位整数中,那么素数“a”应该有多大,这样我就不会溢出整数

是否存在我可以使用的哈希函数的现有实现


以下是我创建的一个实现:

public class hash2
{

    public int prime = 101;

    public int hash(String text)
    {
        int hash = 0;

        for(int i = 0; i < text.length(); i++)
        {
            char c = text.charAt(i);
            hash += c * (int) (Math.pow(prime, text.length() - 1 - i));
        }

        return hash;
    }

    public int rollHash(int previousHash, String previousText, String currentText)
    {

        char firstChar = previousText.charAt(0);
        char lastChar = currentText.charAt(currentText.length() - 1);

        int firstCharHash = firstChar * (int) (Math.pow(prime, previousText.length() - 1));
        int hash = (previousHash - firstCharHash) * prime + lastChar;

        return hash;
    }

    public static void main(String[] args)
    {
        hash2 hashify = new hash2();

        int firstHash = hashify.hash("mydog");
        System.out.println(firstHash);
        System.out.println(hashify.hash("ydogr"));
        System.out.println(hashify.rollHash(firstHash, "mydog", "ydogr"));
    }

}
公共类hash2
{
公共整数素数=101;
公共整数散列(字符串文本)
{
int hash=0;
对于(int i=0;i
我用101作为我的主要目标。我的哈希值是否会溢出有关系吗?我认为这是可取的,但我不确定


这似乎是正确的方法吗?

据我所知,这是一种功能最小化:

2^31 - sum (maxchar) * A^kx

其中
maxchar=62
(对于
A-Za-z0-9
)。我刚刚用Excel(OO Calc,准确地说):)计算了它,它找到的最大值a是质数的
76
,或
73

我记得一个稍微不同的实现,它似乎来自sedgewick的一本算法书(它还包含示例代码-尝试查找)。下面是调整为32位整数的摘要:

您可以使用模运算来防止每次运算后整数溢出

初始设置:

  • c=文本(“堆栈溢出”)
  • M=n克的长度
  • d=字母表的大小(256)
  • q=一个大素数,这样(d+1)*q不会溢出(8355967可能是一个不错的选择)
  • dM=dM-1模q
首先计算第一个n-gram的哈希值:

h = 0
for i from 1 to M:
  h = (h*d + c[i]) mod q
对于以下每n克:

for i from 1 to lenght(c)-M:
  // first subtract the oldest character
  h = (h + d*q - c[i]*dM) mod q

  // then add the next character
  h = (h*d + c[i+M]) mod q
在减去最早的字符之前必须添加d*q的原因是,由于前面的模运算导致的值较小,因此可能会遇到负值


错误也包括在内,但我认为你应该明白这一点。试着找一本sedgewick的算法书,以获得详细信息、更少的错误和更好的描述。:)

不确定您的目标是什么,但如果您试图提高性能,那么使用math.pow将比计算滚动哈希值节省更多的成本


我建议您从保持简单高效开始,您很可能会发现它足够快。

为什么此应用程序的素数与“正常”字符串哈希代码生成有任何不同?该算法非常简单,很容易从伪代码实现。你试过自己编码吗?你所说的包含错误是什么意思?如果我这样做,我会遇到“负值”吗?如何防止它?@Myth17:我的意思是你应该谨慎使用我的(伪)代码,因为它可能包含错误/i没有对它进行广泛测试。Rabin-Karp字符串serach算法中使用的滚动哈希应该允许计算下一个哈希值:s[i+1..i+m]=s[i..i+m-1]-s[i]+s[i+m]。您提供的算法不能用于此目的。计算功率的最快方法?这取决于具体情况。简单乘法通常更快。