代码:
<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);
}
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 ]
以此类推!