令给定文本是一个长度为n的字符串S,模板是一个长度为m的字符串P,且m<=n。
- 假设现在文本串S匹配到i位置,模式串P匹配到j位置,
1:如果j=-1,或者当前字符匹配失败(即s[i]==p[j]),都令i++,j++,继续匹配下一个字符;
2:如果j!=-1,且当前字符匹配失败(即s[i]!=p[j]),则令i不变,j=next[j]。意思是失配时,模式串P相对于文本串S向右移动了j-next[j]位。
( 也就是在匹配失败时,模式穿向右移动的位数为:失配字符所在位置-失配字符所在位置的next值,即上文所述j-next[j]。)
- next数组表达的含义就是:当前字符之前的字符串中,有多大长度的相同前缀后缀。即next[j]=k,代表j之前的字符串中有最大长度为k的相同前缀后缀。也意味着在某个字符失配时,该字符对应的next 值会告诉你在下一步匹配中,模式串应该跳到哪个位置(跳到next [j] 的位置)。如果next [j] 等于0或-1,则跳到模式串的开头字符,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某个字符,而不是跳到开头,且具体跳过了k 个字符。
- 寻找最长相同前缀后缀:
模式串的各个子串 前缀 后缀 最大公共元素长度 A 空 空 0 AB A B 0 ABC A,AB C,BC 0 ABCD A,AB,ABC D,CD,BCD 0 ABCDA A,AB,ABC,ABCD A,DA,CDA,BCDA 1 ABCDAB A,AB,ABC,ABCD,ABCDA B,AB,DAB,CDAB,BCDAB 2 ABCDABD A,AB,ABC,ABCD,ABCDA,ABCDAB D,BD,ABD,DABD,CDABD,BCDABD 0
- 寻找最长相同前缀后缀:
接下来就是相关核心代码!!!
//递推得next数组
void GetNext(char* p,int next[])
{
int plen = strlen(p);
next[0] = -1;
int k = -1;
int j = 0;
while(j < plen - 1)
{
//p[k]表示前缀,p[j]表示后缀
if(k == -1||p[j] == p[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k];
}
}
}
!!!KMP标程
int KmpSearch(char* s,char* p)
{
int i = 0;
int j = 0;
int slen = strlen(s);
int plen = strlen(p);
while(i < slen && j < plen)
{
//如果j=-1,或者当前字符匹配成功(即s[i]==p[j]),都令i++,j++
if(j == -1 || s[i] == p[j])
{
i++;
j++;
}
else
{
//如果j!=-1,且当前字符匹配失败(即s[i]!=p[j],则令i不变,j=j[next]
//next[j]即为j所对应的next值
j = next[j];
}
}
if(j == plen)
return i - j;
else
return -1;
}
注: 我写的是缩减版
详情看 原作者:July 博客