/*********************************/
* KMP算法
* 预处理时间:O(m), 运行时间O(n)
* 改进了状态机算法的预处理时间
* 依旧利用后缀最前前缀原理
* 理解有限自动机后理解此算法
/*********************************/
const int MAXN=10000;
char T[MAXN],P[MAXN];
int next[MAXN];
int m,n;
void computePrefixFunction()
{
m=strlen(P)-1;
next[1]=0;
int k=0; // k比q延迟了2个身位
int q;
for(q=2;q<=m;++q)
{
while(k>0&&P[k+1]!=P[q])
{
k=next[k];
}
if(P[k+1]==P[q])
{
k=k+1;
}
next[q]=k;
}
}
void kmpMatcher()
{
n=strlen(T)-1;
m=strlen(P)-1;
computePrefixFunction();
int q=0; //q比i延迟了一个身位
int i;
for(i=1;i<=n;++i)
{
while(q>0&&P[q+1]!=T[i])
{
q=next[q];
}
if(P[q+1]==T[i]) //同时解决了q=0或者P[q+1]==T[i]两个问题
{
q=q+1;
}
if(q==m)
{
printf("匹配成功,位置:%d/n",i-m+1);
q=next[q];
}
}
}
int main()
{
T[0]=P[0]='z';
scanf("%s%s",T+1,P+1);
kmpMatcher();
return 0;
}
算法的思想是这样的, 如果当前已经匹配了一段, 结果匹配下一个字符的时候失败了, 那么应该将模式串向右移动多少来继续匹配呢?
next数组就是这个作用,什么作用呢?
假设文本串T与模式串P。
P[1...k]与T[]的某一段匹配了, 结果P[k+1]与T[]的下一个字符不相等.
这时候,怎么办? 可以在P[]里找一个P[1...k]的最长前缀,而且这个前缀是P[1...k]的一个后缀, 那么这个后缀一定也与T[]的后半段匹配, 假设这个后缀是P[1...s], 那么现在可以继续判断P[s+1]与T[]下一个字符是否相等, 重复这个过程 .如果相等, 那么i++, s++.
就是这么一回事, 基础一定是有限自动机.