我想知道是否有人可以分享Rabin-Karp算法的来源?
由于
答案 0 :(得分:1)
http://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm
http://www.eecs.harvard.edu/~ellard/Q-97/HTML/root/node43.html
以下是几个消息来源。
答案 1 :(得分:1)
这是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;
}
答案 2 :(得分:0)
试一试。在将标点符号发送到$needle
之前,您必须从$haystack
和match_rabinKarp()
中删除标点符号,但这基本上遵循维基百科页面上给出的算法。
// 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;
}
答案 3 :(得分:0)
这里是Gumbo上面回答的略有改动的版本,为了说明的目的,更简单的散列和更清晰的变量命名。
在下面的说明性散列中,我只是将每个字符的ord()值添加到一个数字(表示散列),然后减去该值/在推进搜索时添加下一个char的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;
}