串的模式匹配算法
首先,关于串的模式匹配经典的算法:
即设两指针,分别指向主串和模式串,每次对以主串指针为首的元素进行匹配
(示例算法实现)
int index(SString S,SString T,int pos)
{//返回子串T在主串中第pos个字符之后的位置,元素T[0]与S[0]存放串长
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;
}
(若主串长n,模式串长m,则该算法时间复杂度为O(n*m))
上面便是关于模式串的经典算法,思路实现比较简单,但也是关于串匹配的主要思想,许多串的操作核心源于此。
然而,上面算法的主串指针经常需要回溯,效率较低,且难用于文件流扫描匹配。由此,我们希望不用回溯
主串指针的算法。由于在经典算法中,当主串指针需要回溯时,其前面的元素已经与模式串比较过,因此,我们
需要另一数组来告知我们当前元素位置前面匹配情况,以便我们在当前主串位置不匹配时不用回溯指针而得到重
新与之匹配的模式串中的元素位置.即所谓的KMP算法
算法示例:
int index_kmp(SString S,SString 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[];
接下来是关于如何求next[]数组的问题
这个问题也可以想象成主串和模式串是本身,指针前一部分是模式串,后一部分是主串,匹配有两种
情况即移动到下一元素和重新比较
算法示例:
void get_next(SString T,int next[])
{
i=1; next[1]=0; j=0;
whiel(i<T[0])
{
if(j==0||T[i]==T[j]){++i;++j;next[i]=j;}
else j=next[j];
}
}
由上可知,next[]数组的值由其前面的元素确定,但事实上,当按上面算法求的next的数组中,当串的
位置元素与其next数组位置元素一致时,比较变得无意义,因此对上面算法进行改进,加入当前元素的
影响
算法示例:
void get_nextval(SString T,int nextval[])
{
i=1;nextval[1]=0;j=0;
while(i<T[0])
{
if(j==0||T[i]==T[j])
{
++i;++j;
if(T[i]!=T[j])nextval[i]=j;//加入自身值的影响
else nextval[i]=nextval[j];
}
else j=nextval[j];
}
}
比较以上算法可以发现其大体原理一样,由于现实概率问题,经典算法在实际执行时时间类似于O(n+m),
因此仍有很高的效率。

浙公网安备 33010602011771号