关于KMP及其扩展的讲解有很多,可以自己百度下。
此文为个人的源码及整理的注释。
本人第一次写博文的菜鸟,将就着看吧。。。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
char S[100],T[100];//S->母串,T->子串
int perfix[100],n=0,m=0,next[100],extend[100];
//perfix[i]->T[1...perfix[i]-1]==T[i-perfix[i]+1...i-1]:T[1...perfix[i]]是 T[i-perfix[i]+1...i-1]的前缀,且perfix最大
//next[i]->T[1...next[i]]=T[i...m]:使T[1...next]==T[i...i+next-1]的最大next
//extend[i]->T[1...extend[i]]=S[i...i+extend[i]-1]:使T[1...extend]==S[i...i+extend-1]的最大extend
void _orgin()//base
{
int k=0;//T中当前位置的指针
perfix[1]=0;//对于首次出现的字符,perfix为0
for(int i=2;i<=m;i++)
{
while(k>0 && T[k+1]!=T[i])k=perfix[k]; //若失配,则将指针调至perfix进行匹配
if(T[k+1]==T[i])k++;//若匹配成功,指针后移
perfix[i]=k;//若匹配失败,则k必定为0
}
}
void _KMP()//base
{
int k=0;//同上
for(int i=1;i<=n;i++)
{
while(k>0 && T[k+1]!=S[i])k=perfix[k];//同上
if(T[k+1]==S[i])k++;//同上
if(k==m)printf("%d\n",i-m+1);//若k==m,即找到了T在S中的位置
}
}
void KMP_extend()//extend
{
next[1]=m;
next[2]=m-1;
for(int i=1;i<=m;i++)//预处理出next[2]的值
{
if(T[i+1]!=T[i])
{
next[2]=i-1;
break;
}
}
int p,k=2,j,L;//p->当前最远匹配 ,使匹配最远的k
for(int i=3;i<=m;i++)//此为T与自己的extend_kmp
{
p=k+next[k]-1;L=next[i-k+1];
//由next定义(见变量申明下方的注释)->T[k...p]==T[1...p-k+1] ->T[i...p]==T[i-k+1...p-k+1]
if(i+L<=p)//讨论i+L与p的关系
{
next[i]=L;
}
else
{
j=p-i+1;//已知的长度
j=max(j,0);
while(i+j<=m && T[i+j]==T[j+1])j++;//未知串检测匹配
next[i]=j;k=i;
}
}
k=1;
extend[1]=m;
for(int i=1;i<=m;i++)//此为S与T的extend_kmp
{
if(S[i]!=T[i])
{
extend[1]=i-1;
break;
}
}
for(int i=2;i<=n;i++)
{
p=k+extend[k]-1;L=next[i-k+1];
if(i+L<=p)
{
extend[i]=L;
}
else
{
j=p-i+1;
j=max(j,0);
while(i+j<=n && j<=m && S[i+j]==T[j+1])j++;
extend[i]=j;k=i;
}
}
for(int i=1;i<=m;i++)printf("next[%d]:%d\n",i,next[i]);
for(int i=1;i<=n;i++)printf("extend[%d]:%d\n",i,extend[i]);
}
int main()
{
freopen("Kmp.in","r",stdin);
freopen("Kmp.out","w",stdout);
char a=getchar();
while(a!='\n')
{
S[++n]=a;
a=getchar();
}
a=getchar();
while(a!='\n')
{
T[++m]=a;
a=getchar();
}
_orgin();
_KMP();
KMP_extend();
return 0;
}