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; }