kmp算法是解决单模匹配问题的算法,难点在于求next[]数组
求next[]数组:对于模板串的所有前缀子串的最长公共前后缀的长度,就是next[]数组的值
eg:主串为cbbbaababac 子串为ababac
初始化next[0]=-1;
子串的最长公共前后缀长度
a -->0 next[1]=0
ab -->0 next[2]=0
aba -->1 next[3]=1
abab -->2 next[4]=2
ababa -->3 next[5]=3
next[]数组的作用是在当子串在和模板串失配的时候,next[]数组提供下一个字串的字母,和当前位置的模板串字母匹配
eg:模板串是cbbbaababac,子串是ababa
子串下标: 0 1 2 3 4
a b a b a
失配跳转位置next[]:-1 0 0 1 2
这里解释一下:当子串和模板串失配的时候,就根据next[]的值移动子串到相应位置去和模板串匹配。
这里模拟一下匹配过程,i表示模板串的当前匹配位置,j表示子串的当前匹配位置,初始i=0,j=0;模板串p[],子串s[]
a!=c ---> i++ i=1,j=0
a!=b ---> i++ i=2,j=0
a!=b ---> i++ i=3,j=0
a!=b ---> i++ i=4,j=0
a==a ---> i++,j++ i=5,j=1
b!=a ---> i保持不变,j=next[j],跳转 i=5,j=0
a==a ---> i++,j++ i=6,j=1
b==b ---> i++,j++ i=7,j=2
a==a ---> i++,j++ i=8,j=3
b==b ---> i++,j++ i=9,j=4
a==a ---> i++,j++ i=10,j=5
j>=strlen(s) 匹配结束 , 返回可以匹配的首地址 return j-i+1
#include<iostream>
#include<string.h>
using namespace std;
char p[100],s[100];
int next1[100];
void get_next(char *s,int *next1)
{
int m=strlen(s);//子串的长度
int j=0;//当前匹配的位置
int k=-1;//失配的时候要跳转的位置(也是最长公共前后缀的长度)
next1[0]=-1;
while(j<m)
{
if(k==-1||s[j]==s[k])
next1[++j]=++k;
else
k=next1[k];
}
}
int kmp(char *p,char *s)//p是模板串,s是子串
{
int i=0,j=0;
int n=strlen(p);
int m=strlen(s);
while(i<n&&j<m)
{
if(j==-1||p[i]==s[j])
{
i++;
j++;
}
else
j=next1[j];
}
if(j>=m)//s串比较完毕
return i-m+1;
else
return -1;
}
int main()
{
cin>>p>>s;
get_next(p,next1);
for(int i=0;s[i];i++)
cout<<"next["<<i<<"]="<<next1[i]<<endl;
cout<<"从第"<<kmp(p,s)<<"个字符开始匹配"<<endl;//返回的是开始匹配的第几个字符,不是位置
return 0;
}