我正在尝试在Perl中实现Knuth Morris Pratt algorithm。以下是我的代码,我在Perl First Edition中提到了算法的Mastering Algorithms。当我运行代码时,它打印-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1作为结果。我哪里错了?
代码:
#!/usr/local/bin/perl
#text
my $seq = "babacbadbbac";
#pattern
my $motif = "acabad";
#pass the text and pattern to knuth_morris_pratt subroutine
my @res = knuth_morris_pratt($seq, $motif);
#print the result
print "The resulting array is:";
print "@res";
#computation of the prefix subroutine
sub knuth_morris_pratt_next
{
my($P) = @_; #pattern
use integer;
my ( $m, $i, $j ) = ( length $P, 0, -1 );
my @next;
for ($next[0] = -1; $i < $m; ) {
# Note that this while() is skipped during the first for() pass.
while ( $j > -1 && substr( $P, $i, 1 ) ne substr( $P, $j, 1 ) ) {
$j = $next[$j];
}
$i++;
$j++;
$next[$i] = substr( $P, $j, 1 ) eq substr( $P, $i, 1 ) ? $next[$j] : $j;
}
return ( $m, @next ); # Length of pattern and prefix function.
}
#matcher subroutine
sub knuth_morris_pratt
{
my ( $T, $P ) = @_; # Text and pattern.
use integer;
my ($m,@next) = knuth_morris_pratt_next( $P );
my ( $n, $i, $j ) = ( length($T), 0, 0 );
#my @next;
my @val;
my $k=0;
while ( $i < $n )
{
while ( $j > -1 && substr( $P, $j, 1 ) ne substr( $T, $i, 1 ) )
{
$j = $next[$j];
}
$i++;
$j++;
if($j>=$m)
{
$val[$k]= $i - $j; # Match.
}
else
{
$val[$k]=-1; # Mismatch.
}
$k++;
}
return @val;
}
答案 0 :(得分:1)
您对KMP算法的实现会返回一个数组,其中对于motif不匹配的seq的每个位置都为-1,以及匹配的位置匹配的索引。
例如,如果将主题更改为“acbad”,则数组也将包含3:
0 1 2 3 4 5 6 7 8 9 10 11 | index
"b a b a c b a d b b a c" | seq
"a c b a d" | motif
$> perl mq.pl "babacbadbbac" "acabad"
The resulting array is:
[-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1] [-1]
$> perl mq.pl "babacbadbbac" "acbad"
Match at index:3
The resulting array is:
[-1] [-1] [-1] [-1] [-1] [-1] [-1] [3] [-1] [-1] [-1] [-1]
$> perl mq.pl "babacbadbbac" "ac"
Match at index:3
Match at index:10
The resulting array is:
[-1] [-1] [-1] [-1] [3] [-1] [-1] [-1] [-1] [-1] [-1] [10]
修改后的代码
#!/usr/local/bin/perl
my($seq,$motif) = @ARGV;
die "seq and motif required..." unless $seq and $motif;
die "motif should be <= seq ..." unless length($motif) <= length($seq);
#pass the text and pattern to knuth_morris_pratt subroutine
my @res = knuth_morris_pratt($seq, $motif);
#print the result
print "The resulting array is:\n";
#print "@res";
print "[".join("] [",@res)."] \n";
#computation of the prefix subroutine
sub knuth_morris_pratt_next
{
my($P) = @_; #pattern
use integer;
my ( $m, $i, $j ) = ( length $P, 0, -1 );
my @next;
for ($next[0] = -1; $i < $m; ) {
# Note that this while() is skipped during the first for() pass.
while ( $j > -1 && substr( $P, $i, 1 ) ne substr( $P, $j, 1 ) ) {
$j = $next[$j];
}
$i++;
$j++;
$next[$i] = substr( $P, $j, 1 ) eq substr( $P, $i, 1 ) ? $next[$j] : $j;
}
return ( $m, @next ); # Length of pattern and prefix function.
}
#matcher subroutine
sub knuth_morris_pratt
{
my ( $T, $P ) = @_; # Text and pattern.
use integer;
my ($m,@next) = knuth_morris_pratt_next( $P );
my ( $n, $i, $j ) = ( length($T), 0, 0 );
#my @next;
my @val;
my $k=0;
while ( $i < $n )
{
while ( $j > -1 && substr( $P, $j, 1 ) ne substr( $T, $i, 1 ) )
{
$j = $next[$j];
}
$i++;
$j++;
if($j>=$m)
{
$val[$k]= $i - $j; # Match.
print "Match at index:".$val[$k]." \n";
}
else
{
$val[$k]=-1; # Mismatch.
}
$k++;
}
return @val;
}