kmp算法是一个高效的匹配算法
对于数据量小的字符串
s
和p
,我们可以写暴力匹配去达到要求,但数据量很大的话,效率就会很低。这里我先讲一下暴力匹配的写法,因为高效的kmp算法和暴力匹配算法有很大关联
首先给一个字符串s[ ]
:"ababaaacd"
,再给一个匹配的字符串p[ ]
:"abaa"
如果我们想要写一个程序,让程序告诉我们s
串中是否含有p
串
思路很简单:
1:
ababaaacd
abaa
在p的最后一位不相同跳出即可
2:
ababaaacd
abaa
在p的第一位就不同,就没有匹配下去的必要了,直接跳出
3:
ababaaacd
abaa
匹配成功,结束即可
代码实现:
#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
void v_kmp(char*s,char*p)
{
int i=0,j=0,flag=0;
int slen=strlen(s);
int plen=strlen(p);
while(i<slen)
{
if(s[i]==p[j])
{
i++;
j++;
}
else
{
i=i-j+1;
j=0;
}
if(j==plen)
{
flag=1;
break;
}
}
if(flag)
{
printf("匹配成功\n");
}
else
{
printf("匹配失败\n");
}
}
int main()
{
char s[maxn],p[maxn];
memset(s,0,sizeof(s));
memset(p,0,sizeof(p));
cin>>s>>p;
v_kmp(s,p);
}
KMP算法之next[ ]的实现
kmp算法的高效在于next[ ]的应用,next[ ]求的是公共前后缀,公共前后缀的的作用是什么?这是我接下来要讲的
举个栗子:
s[ ]
: BBC ABCDAB ABCDABCDABDE
p[ ]
: ABCDABD
模拟一下匹配过程
BBC ABCDAB ABCDABCDABDE
ABCDABD
ABCDABD
ABCDABD
ABCDABD
省略了一步一步往前迁移的过程,当p[k]!=p[j]的时候,在前缀
k中找和p[j]相等的p[k]从而更新k值,当p[k]==p[j],前缀++
求next[ ]
的代码:
void getnext(char *p,int next[])
{
next[0]=0;//第一个数的公共前后缀肯定为0
int plen=strlen(p);
for(int i=1,k=0;i<plen;i++)
{
while(k>0&&p[i]!=p[k])//k代表前缀,i代表后缀
{
k=next[k-1];//在前缀里面找
}
if(p[i]==p[k])
{
k++;//有公共的前后缀k++
}
next[i]=k;//递归写法
}
}
KMP算法
写出next[]
后,暴力kmp
就可以为真正的kmp
,因为此时的kmp
并不依靠一个一个找的过程,当匹配到后面的时候直接根据next[]
进行跳越
kmp代码实现:
void kmp(char* s,char* p)
{
int slen=strlen(s);
int plen=strlen(p);
int Next[plen];
MakeNext(p,Next);
for(int i=0,j=0;i<slen;i++)
{
while(j>0&&s[i]!=p[j])
{
j=Next[j-1];//不相等的时候需要去找公共前后缀
}
if(s[i]==p[j])
j++;
if(j==plen)
{cout<<"匹配成功"<<endl;
return ;
}
}
cout<<"匹配失败"<<endl;
}