串的模式识别是指在主串中找到模式串的过程。
例如从主串abcdef寻找模式串ef,并返回模式串首字母在主串中的位置。
以ababcabc为主串abc为模式串为例。
ababcabc
abc (此时i=1,j=1回溯到i-j+2的位置)
基本算法如下:(接上篇文章中的String定义)
int Index(String S,String T,int pos) //当两个字符相等时,将下标各往后增加1,如果不相等时,将j置1再次指向T的首字符,i进行回溯,用i减去当前j-1所指的长度再加上1代表
{ //当前向后一个的位置,即i-j+2.
i=pos;
j=1;
while(i<S[0]&&j<T[0])
{
if(S[i]==T[j])
{
i++;j++;
}
else
{
i=i-j+2;j=1;
}
}
if(j>T[0]) return i-T[0];
else return 0;
}
}
改进型KMP算法:
在上述的算法中有许多不需要进行的比较,例如:ababcabcabcababcaba为主串,ababcaba为模式串当比较至ababcabc不等于ababcaba时,若i指针进行回溯,则需比较babcabca是否等于ababcaba。由于我们已知在主串的c字符之前,二者是相等的。而模式串本身中由于babcabc并不等于ababcab(这个信息获取不涉及主串),所以模式串也不可能等于主串的下一个元素开始的串,即babca...因此我们在求解时不采用i指针回溯的方式,而是改变j指针的值。具体将j改为多少,请看下面的具体分析:
因此上述方案的实现如下:
int Insert(String S,String T,int pos)
{
i=pos;j=1;
while(i<S[0]&&j<T[0])
{
if(j==0 || S[i]==T[j])
{
i++;j++;
}
else
j=next[j];
}
if (j>T[0])
return i-T[0];
else return 0;
}
因此此时涉及到next[j]如何获取,这是一个递归的过程,假设next[j]=k,说明在j之前有k-1个元素是有相同串的,即:p1...pk-1=pj-k+1...pj-1,则此时next[j+1]=?
分为以下两种情况:
pj=pk,这种情况说明p1...pk=pj-k+1...pj,此时相同字符串的长度增加了1,有next[j+1]=next[j]+1。
pj<>pk,这种情况是一种模式匹配问题,此时模式串和主串相同,就是比较在这不同的串之前有没有最大长度的首尾相同串,例如例中,若模式abaabcac,若已知第6个字符c的next[6]=3,而p6<>p3,因此将此模式串向右滑动,p6<>p1,则next[7]=1.
这个的实现方法如下:
void next(String T,int next[])
{
i=1;next[1]=0;j=0;
while(i<T[0])
{
if(j==0 || T[i]==T[j] )
{ i++;j++;next[i]=j;}
else j=next[j];
}
}
在下一篇中介绍关于next的修正算法,针对一些特殊的案例。