KMP算法---处理字符串匹配

输入:字符串A,B

输出:B是否为A的子串

 

算法:

设A的长度为n,B的长度为m,即A=A[1…n],B=b[1…m]。

假设有两个索引:i,j,并且满足A[i-j+1…i]=B[1…j]相等,也就是说以i结尾的长度为j的A中子串匹配以j结尾的长度为j的B中子串。初始时i=j=0。现在要判断A[i+1]是否和B[j+1]是否相等,如果相等,则i和j都增加1,并且当j等于m时说明B是A的子串;如果不相等,则要重新规划j的值,变成j’,使得A[i-j'+1…i]=B[1…j'],那么怎么确定j’的值呢?要想满足A[i-j'+1…i]=B[1…j'],且已知条件A[i-j+1…i]=B[1…j],则要满足B[1…j']=B[j-j'+1…j]的最大j'值,这个值之和B字符串有关,所以可以进行预处理,对于每一个1=<j<=m,令j'=P[j]。

当P[j]确定时,A[i-P[j]+1…i]=B[1…P[j]],回到上一自然段的条件,继续推进即可。

当P[j]=0时怎么办,此时只有继续往后遍历i,知道找到A[i]=B[P[j]+1],继续推进。

举例:

现在有A=”abababaababacb”,B=“ababacb”

现在i=j=4,即A[1…4]=B[1…4],

i = 1  2  3  4  5  6  7  8  9  10  11  12  13  14

A= a  b  a  b  a  b  a  a  b   a     b    a     c    b

B= a  b  a  b  a  c   b

j = 1  2  3  4  5  6   7

现在判断A[5]和B[5],发现相等,i和j同时递增,此时A[1…5]=B[1…5]

i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14

A= a b a b a b a a b   a   b   a    c   b

B= a b a b a c b

j =1 2 3 4 5 6 7

现在i=j=5,判断A[6]和B[6],发现不等,我们查找P[5],发现是3,则新的匹配是A[3…5]=B[1…3]

i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14

A=a b a b a b a a b   a   b   a    c   b

B=      a b a b a c b

j=       1 2 3 4 5 6 7

现在i=5,j=3,判断A[6]和B[4],发现相等,i和j同时递增,此时A[3…6]=B[1…4]

i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14

A=a b a b a b a a b a b a c b

B=     a b a b a c b

j=      1 2 3 4 5 6 7

由于A[7]=B[5],继续推进得到上图,发现A[8]!=B[6],则要算出P[5],然后继续。。。


//初始化j为0
int j=0;
//i只会一直向前进
for(int i=1;i<=n;++i)
{
   //不能匹配的时候,去找P[j],直到能够匹配,或者直到j=0
   while(j>0 && B[j+1]!=A[i])
        j=P[j];
   //能够匹配,继续推进
   if(B[j+1==A[i]])
        ++j;
   //推进到B串的最后,输出
   if(j==m)
   {
       printf "substring at A's" i-m "position";
       //此处是为了继续推进查找,因为子串索引可能不止一处
       j=P[j];
   }
      
}

下面还剩一个问题,即P[j]怎么求。

P[1]=0;
j=0;
for(int i=2;i<=m;++i)
{
    while(j>0 && B[j+1]!=B[i])
	    j=P[j];
	if(B[j+1]==B[i])
	    j=j+1;
	P[i]=j;
}

 

参考自:http://www.matrix67.com/blog/archives/115

posted @ 2012-05-30 15:20  Cavia  阅读(362)  评论(0编辑  收藏  举报