首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rabin-Karp算法的PHP实现

Rabin-Karp算法的PHP实现
EN

Stack Overflow用户
提问于 2012-03-26 20:10:58
回答 1查看 1.6K关注 0票数 2

嗨,我正在写一个PHP类来实现Rabin-Karp算法。我有关于重新散列部分的问题。此代码不包括匹配字符的一部分。我不得不停下来,因为它从来没有匹配散列代码,因为与重新散列的问题。有没有人能帮我解决这个问题。

代码语言:javascript
复制
<?php
 class RabinKarp
 {
    /** 
    * @var String
    */ 
    private $pattern ;
    private $patternHash ;
    private $text ;
    private $previousHash ;

    /** 
    * @var Integer
    */ 
    private $radix ;
    private $prime ;
    private $position ;

    /** 
    * Constructor 
    *
    * @param String $pattern - The pattern
    *
    */ 
    public function __construct($pattern) 
    {
        $this->pattern = $pattern;
        $this->radix = 256;
        $this->prime = 100007;
        $this->previousHash = "";
        $this->position = 0;
        $this->patternHash = $this->generateHash($pattern);
    }

    private function generateHash($key)
    {
        $charArray = str_split($key);
        $hash = 0;
        foreach($charArray as $char)
        {
             $hash = ($this->radix * $hash + ord($char)) % $this->prime;
        }

        return $hash;
    }

    public function search($character)
    {
        $this->text .= $character;
        if(strlen($this->text) < strlen($this->pattern))
        {
            return false;
        }
        else
        {
            $txtHash = 0;
            echo $this->previousHash . "<br/>";
            if(empty($this->previousHash))
            {
                $txtHash = $this->generateHash($this->text);
                $this->previousHash = $txtHash;
                $this->position = 0;
            }
            else
            {
                // The issue is here 
                $charArray = str_split($this->text);
                $txtHash = (($txtHash  + $this->prime) - $this->radix * strlen($this->pattern) * ord($charArray[$this->position]) % $this->prime) % $this->prime;
                $txtHash = ($txtHash * $this->radix + ord($character)) % $this->prime; 

                $this->previousHash = $txtHash;
            }

            if($txtHash == $this->patternHash)
            {
                echo "Hash Match found";
            }
        }

    }

 }

$x = new RabinKarp("ABC");
$x->search("Z");
$x->search("A");
$x->search("B");
$x->search("C");
?>

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-26 22:54:22

您要删除的字符(c表示缩写)对散列的贡献值为

代码语言:javascript
复制
ord(c) * radix^(length(pattern)-1)

因为字符在第一次进入匹配窗口时贡献了ord(c),对于进入匹配窗口的每个length(pattern)-1字符,散列-因此也包括其贡献-与radix相乘,直到c最终离开它。

但是你在减去ord(c) * radix * length(pattern)

代码语言:javascript
复制
$charArray = str_split($this->text);
$txtHash = (($txtHash  + $this->prime)
             - $this->radix * strlen($this->pattern)
             * ord($charArray[$this->position]) % $this->prime)
           % $this->prime;
$txtHash = ($txtHash * $this->radix + ord($character)) % $this->prime;

此外,在计算中,您使用了变量$txtHash,该变量设置为0,应该是$this->previousHash,并且必须递增文本位置。

原则上,

代码语言:javascript
复制
$charArray = str_split($this->text);
$txtHash = (($this->previousHash  + $this->prime)
             - pow($this->radix, strlen($this->pattern)-1)
             * ord($charArray[$this->position]) % $this->prime)
           % $this->prime;
$txtHash = ($txtHash * $this->radix + ord($character)) % $this->prime;

$this->previousHash = $txtHash;
$this->position += 1;

是你必须要做的。

但是,除非模式非常短,否则pow($this->radix,strlen($this->pattern)-1)将溢出,因此您必须用模幂函数替换pow($this-radix, strlen($this->pattern)-1)

代码语言:javascript
复制
function mod_pow($base,$exponent,$modulus)
{
    $aux = 1;
    while($exponent > 0) {
        if ($exponent % 2 == 1) {
            $aux = ($aux * $base) % $modulus;
        }
        $base = ($base * $base) % $modulus;
        $exponent = $exponent/2;
    }
    return $aux;
}

(如果$modulus,也就是这里的$this->prime太大,这仍然会溢出)。相关的代码行将变为

代码语言:javascript
复制
$txtHash = (($this->previousHash  + $this->prime)
             - mod_pow($this->radix, strlen($this->pattern)-1, $this->prime)
             * ord($charArray[$this->position]) % $this->prime)
           % $this->prime;

那么你就会有一个潜在的巨大的低效

代码语言:javascript
复制
$this->text .= $character;
...
    $charArray = str_split($this->text);

如果字符串变得很长,连接和拆分可能需要很长时间(不确定PHP如何实现字符串和字符串操作,但它们可能不是恒定的时间)。您可能应该只保留字符串的相关部分,即在重新计算散列后删除第一个字符。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9871850

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档