昨天有点小插曲,我们今天继续前天的字符串匹配模式算法,上次的朴素的匹配模式算法的效率非常低,于是我们想办法对它改进,前辈们就发现呀,如果要匹配的字符串前几位和后几位中某几位相同,前几位匹配失败的话,就可以直接跳过后几位的匹配过程,这样一来,效率就提高了,下面我们直接介绍前辈的kmp算法。我们设置一个数组next记住匹配字符串各个位置的j值。
next[j]=0,j=1;Max{k|1<k<j,且p1…pk-1=pj-k+1…pj-1}当此集合不为空时;1 其他情况。
例1:
j:123456
模式串T:abcdex
next[j]:011111
例2:
j:123456
模式串:ascasx
next[j]:01123
至于他怎么推导出来的,请看公式。
下面上代码:
//KMP模式匹配算法
void get_next(string T,int *next)//初始化子串next数组
{
int i,j;
i=1;
j=0;
next[1]=0;
while(i<T[0])
{
if(j==0||T[i]==T[j])
{
i++;
j++;
next[i]=j;
}
else
j=next[j];
}
}
int Index_KMP(string S,string T,int pos)
{
int i=pos;
int j=1;
int next[255];
get_next(T,next);
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;
}
只有匹配串有重复kmp的又是才体现出来,后来有人发现kmp还有缺陷,还可以改进,例如匹配串的前部分和后部分的距离不变,当前半部分匹配成功后面出现匹配失败时,匹配字符串往下移动,其实一直到出现错误的部分就不用看了,不会匹配成功的,于是大佬又引入了nextval数组,用来记住next数组相等的部分去取代字符后续数组的值。不明白是吧,看个例子:
j:123456789
模式串:ababaaaba
next[j]:011234223
nextval[j]:010104210
明白了nextval就可以上代码啦:
//KMP算法再改进
void get_nextval(string T,int *nextval)
{
int i,j;
j=0;
nextval[1]=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];
}
}