【问题标题】:Rabin-Karp Algorithm in PHPPHP 中的 Rabin-Karp 算法
【发布时间】:2009-09-07 21:25:39
【问题描述】:

我想知道是否有人可以分享 Rabin-Karp 算法的源代码?

谢谢

【问题讨论】:

    标签: php string algorithm rabin-karp


    【解决方案1】:

    【讨论】:

    • @Gabe:是的,维基百科已经有一个伪代码源。如果你想按照你的标签建议使用 php,它足够强大,可以逐行翻译该算法。
    【解决方案2】:

    这是this C implementation of the Karp-Rabin algorithm的端口:

    function KR($haystack, $needle) {
        $n = strlen($haystack);
        $m = strlen($needle);
        if ($m > $n) {
            return -1;
        }
        /* Preprocessing */
        $d = 1 << ($m - 1);
        for ($hh = $hn = $i = 0; $i < $m; ++$i) {
            $hh = (($hh<<1) + ord($haystack[$i]));
            $hn = (($hn<<1) + ord($needle[$i]));
        }
        /* Searching */
        $j = 0;
        while ($j <= $n-$m) {
            if ($hh == $hn && substr($haystack, $j, $m) === $needle) {
                return $j;
            }
            if ($j === $n-$m) {
                return false;
            }
            /* Rehashing */
            $hh = (($hh - ord($haystack[$j]) * $d) << 1) + ord($haystack[$j + $m]);
            ++$j;
        }
        return false;
    }
    

    【讨论】:

    • 这是最优雅和可读的解决方案。我在下面添加了一个修改后的版本,并进行了更多说明。
    • 超级解决方案,但我不太明白的一件事是 $d 的目的是什么?
    【解决方案3】:

    为了便于说明,这里是 Gumbo 上面的答案稍有改动的版本,具有更简单的散列和更清晰的变量命名。

    在下面的说明性哈希中,我只是将每个字符的 ord() 值添加到表示哈希的数字中,然后在推进搜索时减去该值/添加下一个字符的 ord()。 这很容易发生冲突(因此不适合生产),但如果您只是从概念上学习 Rabin-Karp,则更容易理解。

    function rk ($needle, $haystack)
    {
        $nlen = strlen($needle);
        $hlen = strlen($haystack);
        $nhash = 0;
        $hhash = 0;
    
        // Special cases that don't require the rk algo:
        // if needle is longer than haystack, no possible match
        if ($nlen > $hlen) {
            return false;
        }
        // If they're the same size, they must just match
        if ($nlen == $hlen) {
            return ($needle === $haystack);
        }
    
        // Compute hash of $needle and $haystack[0..needle.length]
        // This is a very primitive hashing method for illustrative purposes
        // only. You'll want to modify each value based on its position in
        // the string as per Gumbo's example above (left shifting)
        for ($i = 0; $i < $nlen; ++$i) {
            $nhash += ord($needle[$i]);
            $hhash += ord($haystack[$i]);
        }
    
        // Go through each position of needle and see if
        // the hashes match, then do a comparison at that point
        for ($i = 0, $c = $hlen - $nlen; $i <= $c; ++$i) {
            // If the hashes match, there's a good chance the next $nlen characters of $haystack matches $needle
            if ($nhash == $hhash && $needle === substr($haystack, $i, $nlen)) {
                return $i;
            }
            // If we've reached the end, don't try to update the hash with
            // the code following this if()
            if ($i == $c) {
                return false;
            }
    
            // Update hhash to the next position by subtracting the
            // letter we're removing and adding the letter we're adding
            $hhash = ($hhash - ord($haystack[$i])) + ord($haystack[$i + $nlen]);
        }
    
        return false;
    }
    

    【讨论】:

      【解决方案4】:

      试试这个。在发送到match_rabinKarp() 之前,您必须从$needle 和$haystack 中删除标点符号,但这基本上遵循维基百科页面上给出的算法。

      // this hash function is friendly, according to the wikipedia page
      function hash($string) {
       $base = ord('a');
       if (strlen($string) == 1) {
        return ord($string);
       } else {
        $result = 0;
        // sum each of the character*(base^i)
        for ($i=strlen($string)-1; $i>=0; $i++) {
         $result += $string[$i]*pow($base,$i);
        }
        return $result;
       }
      }
      // perform the actual match
      function match_rabinKarp($needle, $haystack) {
       $needle = substr($needle);      // remove capitals
       $haystack = substr($haystack);  // remove capitals
       $m = strlen($needle);           // length of $needle
       $n = strlen($haystack);         // length of $haystack
       $h_haystack = hash($haystack);  // hash of $haystack
       $h_needle = hash($needle);      // hash of $needle
       // whittle away at the $haystack until we find a match
       for ($i=0;$i<$n-$m+1;$i++) {
        if ($h_needle == $h_haystack) {
         if (substr($haystack,$i,$i+$m-1) == $needle) {
          return $i;
         }
        }
       }
       return false;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-04-09
        • 2022-01-10
        • 2018-04-09
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-19
        相关资源
        最近更新 更多