最近学了一下KMP匹配算法,这个算法在字符串匹配中还是很有名的
一般的字符串匹配算法是这样的
1.比较目标串和待匹配的字符串,一个字符一个字符的比较,如果比较到待匹配串的末尾,则返回匹配成功的位置;
2.发现有不同的停止比较,将目标串向后移动一格,待匹配字符串重新回到起点,回到步骤1,继续匹配。
这个算法的优点是思路简单,有点像排序中的冒泡排序,选择排序的样子。缺点就是有大量的重复计算。
KMP匹配算法就是为了实现减少不必要的重复计算,这个思想在很多改良的算法中都是通用的。
例如 要寻找 pappappar 中pappar 出现的位置,按照上面的算法第一次匹配中一直匹配到pappar中的 ‘r’才发现匹配不成功,于是从待查串计数器移到‘a’ 的上面,目标串重新回到开始,继续匹配。这里重复匹配就出现了,可以看到在目标串 ‘r’ 前面有pa 是和自己前面是一样的,也就是说,下次匹配可以从第三位p和目标串中的第三个位置开始比较,如下图
这样就达到了待测串中遍历器不用回溯,目标串的遍历器也减少回溯的目的,实现如下
int * Cal(char * str,int length) //计算模式串
{
int* mod=new int[length];
mod[0]=mod[1]=0;
for(int i=2;i<length;i++)
if(str[i-1]==str[mod[i-1]])
mod[i]=mod[i-1]+1;
else if(str[i-1]==str[0])
mod[i]=1;
else
mod[i]=0;
for(int i=0;i<length;i++)
cout<<mod[i]<<" ";
cout<<endl;
return mod;
}
int KMP(char *target,char *source,int tlength,int slength)
{
int *mod=Cal(target,tlength);
int tar=0,sour=0;
if(target==NULL||source==NULL||tlength<0||slength<0)
{
cout<<"参数不合法"<<endl;
return -1;
}
while(sour<slength)
{
if(source[sour]==target[tar])
{
sour++;
tar++;
if(tar==tlength)
{
cout<<"位置"<<sour-tlength<<"检测到目标串"<<endl;
tar=0;
}
}
else if(mod[tar]==0) //如果该位置之前的串的后缀和其前缀不同
{
sour++;
tar=0;
}
else
tar=mod[tar]; //如果该位置之前的串的后缀和其前缀相同,利用该信息
}
cout<<"检测完毕"<<endl;
return 1;
}