您的位置:首页 > 其它

【模式匹配】KMP算法的简明理解

2014-04-08 09:55 169 查看
KMP算法是模式匹配算法的一种改进算法。这种算法是D.EKunth与V.P.Pratt和J.H.Morris同时发现的,因此称为克鲁特——莫里斯——普拉特操作,简称为KMP算法。
假设给定子串P,待查找的字符串T.
这个算法是目的是在子串中找出待查找的的字符串,要求从子串P中超出所有与字符串T相同的子串,这称为模式匹配。(返回结果可以是子串在P中的位置)
首先给出一个例子:

P:
p0
p1
p2
p3
p4
p5
……
pm-1
……
pn
T:
t0
t1
t2
t3
t4
t5
……
tm-1
从t0开始,使得P的连续m个字符和T相同。
一、解决模式匹配的方案:
1、 普通的模式匹配算法:将T中的字符串和P一一比较,如果遇到不相同的字符,则将T右移一位将继续上面的操作,直到匹配成功或者匹配到最后一位为止。
举例:
P:
a
a
a
a
a
a
a
a
a
b
T:
a
a
a
b
从上面的例子可以看出在最坏的情况下每次都要比较m次,比较的趟数为n+1-m趟,所以总的比较次数为m*(n-1+m)。

2、 KMP算法:从上面普通匹配算法来看,其实有很多比较是可以避免的,因为上面的过程出现的回溯。那么KMP将会尽量避免回溯产生的冗余比较。
KMP算法主要是要确认以下问题:
A、字符串不等时,T向右移动多少个位置;
B、移动后从T的第几个字符开始和P中的那个字符比较;
KMP的关键是借助了一个和T字符串长度相等的数组next,这组数组只与T自身有关(与P无关)。现在给出next的定义:每个T的字符对应一个next直接给出一个相关的式子。
① 字符串不等时,T向右移动i-next[i] (注意i可以取到0)个位置;
② 移动后从T的第next[i] (当为-1时,取值为0)个字符开始和P中的那个字符比较;

以下是计算next的方法(i是从0开始的)

-1(i=0)
next[i]={ Max{k|0<k<j-1,”t0…t(k-1)”=”t(i-k)…t(i-1)”}
0(其他情况)

上述情况二中其实是计算第i个字符比较不同时,从T的i-1序号向前推进能和t0开始的最多k个字符相等,取值那个最大的k即可。
例如下面的例子:
P:
a
c
a
b
a
a
b
a
……
T:
a
b
a
a
b
c
i

0
1
2
3
4
5
T:
a
b
a
a
b
c
next[i]
-1
0
0
1
1
2
#include<stdlib.h>
#include<iostream>
using namespace std;

void getnext(char* t,int next[]){
int i=-1,j=0,n=strlen(t);
next[0]=-1;
while(j<n-1)
{
if(i==-1||t[i]==t[j]){
i++;  j++;
next[j]=i;
}
else i=next[i];
}
}

int KMP(char* s,char* t,int next[],int pos)
{
int i=pos,j=0,len1=strlen(s),len2=strlen(t);
while((i<len1)&&(j<len2))
{
if(j==-1||s[i]==t[j]) {j++;i++;}
else j=next[j];
}
if(j==len2) return i-len2;
else return -1;
}

int index_KMP(char* s,char* t,int next[],int pos)
{
int i=0,j=0,len1=strlen(s),len2=strlen(t),re=0;
while(i<len1&&j<len2)
{
if((j==-1)||(s[i]==t[j])) {i++;j++;
}
else j=next[j];
re=max(re,j);
}
return re;
}

int main()
{
char ax[]="abaabcacacabaabaabcacaabc";
char ah[]="abaabcac";
int next[8]={0};
int pos=0,startpos=0,endpos;

while(pos!=-1){
getnext(ah,next);
pos=KMP(ax,ah,next,startpos);
endpos=index_KMP(ax,ah,next,startpos);
cout<<"pos="<<pos<<",endpos="<<endpos<<endl;
startpos=pos+endpos;
}
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: