简单模式匹配算法
int index(Str str,Str substr)
{
int i=1,j=1,k=i;
while(i<=str.length && j<=substr.length)
{
if (str.ch[i]==substr.ch[j])
{
++i;
++j;
}
else
{
j=1;
i=++k;
}
}
if (j>substr.length)
return k;
else
return 0;
}
KMP算法
一般情况:每当发生不匹配时,找出模式串中的不匹配字符
,取其之前的子串
,将模式串后移,使F最先发生前部与后部相重合的位置,即为模式串应后移的目标位置。 事实上,在计算机中模式串是不会移动的,因此需要把模式串后移转化为 j 的变化,模式串后后移到某个位置可等效于 j 重新指向某个位置。易看出,j发生不匹配时,j 重新指向的位置恰好是F串中前后相重合子串的长度+1. 定义一个next[j]数组,其中 j 取1~m,m为模式串长度,表示模式串中第 j 个字符发生不匹配时,应从next[j]处的字符开始重新与主串比较。
特殊情况:
1)模式串中的第一个字符与主串 i 位置不匹配,应从(主串)下一个位置(i+1位置)和模串第一个字符继续比较。
2)当串F中不存在前后重合部分时(F与自身不能视为重合),则从主串中发生不匹配的字符与模式串第一个字符开始比较。
next[j]数组的手工求解方法
直接跳到
就是通常所说的简单模式匹配算法中 i 不需要回溯。i 不需要回溯意味着对于规模较大的外存中字符串的匹配操作可以分段进行,先读入内存一部分进行匹配,完成之后即可写会外存,确保在发生不匹配时不需要将之前写回外存的部分再次读入,减少了I/O操作,提高了效率。
next[j]的值已经求得,则next[j+1]的求值可分为两种情况分析
1)若
等于
,则next[j+1]=t+1,因为 t 当前为F最长相等前后缀长度
2)若
不等于
,只需将 t 值赋值为next[t],继续进行
与
的比较,若满足1)则求得next[j+1],不满足则重复 t 赋值为next[t],并比较
与
的过程。若在这个过程中 t 出现0的情况,则应将next[j+1]赋值为1.
/*求next数组的算法*/
void getnext(Str substr,int next[])
{
int i=1,j=0;
next[1]=0; //
while(i<substr.length)
{
if (j==0||substr.ch[i]==substr.ch[j])
{
++i;
++j;
next[i]=j;
}
else
j=next[j];
}
}
得到next数组之后,将简单模式匹配算法稍作修改就可以得到状态从
到
的改进算法
/*KMP算法*/
int KMP(Str str,Str substr,int next[])
{
int i=1,j=1;
while(i<=str.length && j<=substr.length)
{
if (str.ch[i]==substr.ch[j])
{
++i;
++j;
}
else
j=next[j];
}
if (j>substr.length)
return i-substr.length;
else
return 0;
}
KMP算法的改进
求nextval的一般步骤:
1)当 j 等于1 时,nextval[j]赋值为0,作为特殊标记。
2)当
不等于
时(k等于next[j]),nextval[j]赋值为k。
3)当
等于
时(k等于next[j]),nextval[j]赋值为nextval[k]。
/*求nextval数组的算法*/
void getnextval(Str substr,int nextval[])
{
int i=1,j=0;
nextval[1]=0; //
while(i<substr.length)
{
if (j==0||substr.ch[i]==substr.ch[j])
{
++i;
++j;
if (substr.ch[i]!=substr.ch[j])
nextval[i]=j;
else
nextval[i]=nextval[j]
}
else
j=nextval[j];
}
}