KMP算法 的思想

代码:
<pre name="code" class="cpp">#include<iostream>
#include<string>
#include<vector>
using namespace std;


void getNext(const std::string& p, std::vector<int>& next)
{
    next.resize(p.size());
    next[0] = -1;


    int i = 0, j = -1;


    while (i != p.size() - 1)
    {
        if (j == -1 || p[i] == p[j])
        {
            ++i;
            ++j;
            next[i] = j;
        }
        else
        {
            j = next[j];
        }
    }


	for(i=0;i<p.size();i++)
		cout<<next[i]<<" ";
	cout<<endl;
}


int kmp(const std::string& s, const std::string& p, const int sIndex = 0)
{
    std::vector<int>next(p.size());
    getNext(p, next);//获取next数组,保存到vector中
	cout<<p<<endl;
    int i = sIndex, j = 0;
    while(i != s.length() && j != p.length())
    {
        if (j == -1 || s[i] == p[j])//j=-1 的时候,并不进行匹配。而是将j回置
        {
		//	cout<<i<<endl;
            ++i;
            ++j;
			cout<<i<<" "<<j<<"          OK"<<endl;
        }
        else
        {
			cout<<i<<" "<<j<<"          NO"<<endl;
            j = next[j];
        }
    }


    return j == p.length() ? i - j: -1;
}










int main()
{
	string s1="ababaaababa";
	string p1="bbabbababaaababa";
	cout<<p1<<endl;
	cout<<kmp(p1,s1);


}


 



j         0  1  2  3   4  5  6  7  8  9   10
P       a  b  a  b   a  a  a  b  a   b  a
next:-1  0  0  1   2  3  1  1  2   3  4
     
a  b  a  b   b  a  b  a  b   a  a  a  b  a  b   a











结果如下:
0 0          OK
1 1          OK
2 2          OK
3 3          OK
4 4          OK
4 4          NO
4 2          NO
4 0          NO
5 0          OK
6 1          OK
7 2          OK
8 3          OK
9 4          OK
10 5          OK
11 6          OK
12 7          OK
13 8          OK
14 9          OK
15 10          OK
16 11          OK
5Press any key to continue


我们假设模式串的每一个字符为P0P2P3P4……P10,同样,主串的每一个字符为S0S1S2……S16




从第0个开始一直到第3个,一直匹配到了。到了第4个,匹配不到。


注意,这时候,j=4,i=4.


此时, {P0 P1 P2 P3} == {S0 S1 S2 S3}       ……………………①
        P4 != S4


于是这时候,next数组就有作用了!




由于模式串的{ P0……P[ next[ j ] -1 ]} == { P[ j - next[ j ] ]……p[ j - 1 ] } 


于是,当j = 4的时候,next[j]=2
可以得到   { P0 P1 } == { P2 P3 }           ……………………②




由①得:{ P2 P3 } == { S2 S3 }             ……………………③


由②③得: { P0 P1 } == { S2 S3 }


又因为   P4 != S4
所以,我们只需 继续判断S4是否等于P2
      如果成立,也就是 S4 == P2,
      那就说明  { P0 P1 P2 } == { S2 S3 S4 }
那就不需要判断 S4是否等于P0了,这也就是KMP所谓的一次遍历滑到底,高效率的原因 就在这里


那么,以此类推,S的循环控制变量i就是只增不减了。


好吧,也许有点晕了...


我们 结合KMP思想 再回头看下例子:


j     0  1  2  3   4  5  6  7  8  9   10
P     a  b  a  b   a  a  a  b  a   b  a
next:-1  0  0  1   2  3  1  1  2   3  4
     
S     a  b  a  b   b  a  b  a  b   a  a  a  b  a  b   a






当在第j个匹配不成功时,可以说明三点:
    
     ①. Pj != Sj    (毋庸置疑,如果等于的话,那就匹配成功了)
     ②. { P0 P1 ……P[ j-1 ] } == { S0 S1……S[ j-1 ] }   (说明前面的从0到j-1匹配成功了)
     ③. { P[ j - next[ j ] ]……P[ j - 1 ] } == { S[ j - next[ j ] ]……S[ j - 1 ] }  (首先声明,next[j] < j,至于为什么,


请看next是如果赋值的)


因为 { P0……P[ next[ j ] -1 ]} == { P[ j - next[ j ] ]……p[ j - 1 ] }


所以  { P0……P[ next[ j ] -1 ]} == { S[ j - next[ j ] ]……S[ j - 1 ] }


这时候,就只需要判断 P[ next[ j ] ] 是否等于 Sj 了。


如果相等:就有 { P0……P[ next[ j ] ] } == { S[ j - next[ j ] ]……S[ j  ] }


如果不相等,就比较P[ next[ j ] ] 是否等于S[ i ]


以此类推!








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值