模式匹配算法BF和KMP
2016-11-24 20:17
204 查看
BF(Brute-Force)算法
步骤:
1:利用计数指针i和j指示主串S和模式T中当前正在比较的字符的位置,i的初始值pos可为任意小于主串S长度的值,j初值为1;2:若两串均未比较到串尾
a:若S[i]=T[j],则i和j分别指示串中的下一个位置,继续比较后面的字符;
b:若S[i]不等于T[j],则指针后退重新比对,从主串的下一个字符(i=i-j+2)起重新开始和模式T的第一个字符比较
3:若j>T.length,说明匹配成功,返回和模式T中第一个匹配相等的字符在主串S中的序号(i-T.length);否则,返回0
注意:数组下标从1开始计数,所以i=i-j+2;
算法描述(c++):
int BF(string S,string T,int pos){
int i,j;
i=pos;j=1;
while(i<=S.length&&j<=T.length){
if(S[i]==T[j]){
i++;
j++;
}
else{
j=1;
i=i-j+2;
}
}
if(T.length<j)
return i-T.length;
return 0;
}
匹配过程:
S:aaaaabaT:aab i=pos=1,j=1 i=2;j=1 i=3,j=1;
第一次匹配:a a a a a b a 第二次匹配:a a a a a b a 第三次匹配:a a a a a b a
a a b a a b a a b
i=3,j=3; i=4,j=3 i=5,j=3;
i=4,j=1
第四次匹配: a a a a a b a
a a b
i=7,j=4
返回i-T.length=7-3=4
KMP算法(改进的BF算法)
例1:S:abcdefab
T:abcdex
第一次匹配:a b c d e f a b 第二次匹配:a b c d e f a b 第三次匹配:a b c d e f a b
a b c d e x a a
i=6,j=6
i=2,j=1; i=3,j=1;
第四次匹配:a b c d e f a b 第五次匹配:a b c d e f a b 第六次匹配:a b c d e f a b
a a a
i=4,j=1 i=5,j=1; i=6,j=1
通过观察我们可以看出,对于匹配的子串T来说,“abcdex”首字母‘a’与后面的串“bcdex”中任意一个字符都不相等,对于第一步而言,前五位字符分别相等,这就意味着T的首字符不可能与S串中的第二位到第五位的字符相等,所以第二步到第五步都是多余的。
例2:
S:abcababca...
T:abcabx
第一次匹配:a b c a b a b c a... 第二次匹配:a b c a b a b c a... 第三次匹配:a b c a b a b c a...
a b c a b x a a
i=6,j=6 i=2,j=1 i=3,j=1
第四次匹配:a b c a b a b c a... 第五次匹配:a b c a b a b c a... 第六次匹配:a
b c a b a b c a ...
a a b a b c
4000
i=4,j=1 i=5,j=2 i=6,j=3
通过观察我们可以发现,第二步和第三步是多余的。
T的首位‘a’和T的第四位‘a’相等,第二位‘b’和第五位‘b’相等,而在第一步,第四位的‘a’和第五位的‘b’已和主串S中的相应位置比较过,是相等的,因此可以判断,T的第一位和第二位的字符与S的第四位和第五位也不用比较了,所以第四次和第五次也是多余的。
在BP算法中,主串的i值需要不断地回溯,而通过上面的例子可以看出i回溯可以不需要,KMP算法就是避免不必要的回溯发生。
既然i值不能回溯,那就考虑j值得变化,通过观察可以发现例1中T=“abcdex”,当中没有任何重复的字符,所以j由6变成1,而例2中T=“abcabx”,前缀的“ab”与最后“x”之前串的后缀“ab”相等,所以j由6变成3,因此我们可以得出规律,j值取决于当前字符之间的串的前后缀的相似度。
把T串中各个位置的j值得变化定义为一个数组next,next的长度就是T的长度,next[1]=0
next数组的推导
T="abcdex"j:1 2 3 4 5 6
T: a b c d e x
next[j]: 0 1 1 1 1 1
1)当j=1时,next[1]=0;
2)当j=2时,j由1到j-1就只有字符‘a’,next[2]=1;
3)当j=3时,j由1到j-1的字符串“ab”,显然“a”不等于“b”,next[3]=1;
4)同理,所以T串的next[j为011111
T=“abcabx”
j:1 2 3 4 5 6
T:a b c d e x
next[j]: 0 1 1 1 2 3
1)当j=1时,next[1]=0;
2)当j=2时,j由1到j-1就只有字符‘a’,next[2]=1;
3)当j=3时,j由1到j-1的字符串“ab”,显然“a”不等于“b”,next[3]=1;
4)当j=4时,j由1到j-1的字符串“abc”,显然不相等,next[4]=1;
5)当j=5时,j由1到j-1的字符串“abca”,前缀字符a与后缀字符“a”相等,因此可推算出next[5]=2;
6)当j=6时,j由1到j-1的字符串“abcab”,前缀“ab”与后缀“ab”相等,next[6]=3;
算法实现
void get_next(string T,int *next){
int i,j;
i=0;
j=1;
next[1]=0;
while(j<T.length())
{
if(i==0||T[j]==T[i])
{
++i;
++j;
next[j]=i;
}
else
i=next[i];
}
}
int KMP(string S,string T,int pos)
{
int i=pos;
int j=1;
int next[255];
get_next(T,next);
while(i<=S.length()&&j<=T.length())
{
if(j==0||S[i]==T[i])
{
++i;
++j;
}
else
j=next[j];
}
if(j>T.length())
return i-T.length();
return 0;
}
KMP算法改进
例:S=“aaaabcd”
T=“aaaaax”
1:a a a a b c d
2: a a a a b c d 3:a a a a b c d 4:a a a a b c d 5:a a a a b c d 6:a a a a b c d
| | | | | |
a a a a a x a a a a a x
a a a a a x a a a a a x a a a a a x a
i=5,j=5 i=5,j=4 i=5,j=3 i=5,j=2 i=5,j=1 i=6,j=1
如上面的例子,next数组值是012345,通过观察发现,2345步骤是多余的,由于第二,三,四,五位置的字符斗鱼首位‘a相等,可以用首位的next【1】的值去取代后续的next【j】的值,因此增加一个取代的数组nextval
nextval数组推导
T=“ababaaaba”j:1 2 3 4 5 6 7 8 9
T:a b a b a a a b a
next[j]:0 1 1 2 3 4 2 2 3
nextval[j]:0 1 0 1 0 4 2 1 0
1)当j=1时,nextval[1]=0;
2)当j=2时,第二个字符‘b’的next值是1,第一位是‘a’,不相等,所以nextval[2]=next[2]=1,维持原值
3)当j=3时,第三个字符‘a’的next值是1,第一位是‘a’,相等,所以nextval[3]=nextval[1]=0;
以此类推
算法实现
void get_nextval(string T,int *next){
int i,j;
i=0;
j=1;
nextval[1]=0;
while(j<T.length())
{
if(i==0||T[j]==T[i])
{
++i;
++j;
if(T[i]!=T[j])
nextval[j]=i;
else
nextval[j]=nextval[i];
}
else
i=nextval[i];
}
}
相关文章推荐
- 串的模式匹配算法之KMP与BF
- 数据结构编程笔记十一:第四章 串 定长顺序串以及模式匹配算法(BF和KMP)的实现
- 串的模式匹配算法(BF、KMP)
- 串的模式匹配算法 穷举与KMP
- KMP模式匹配算法分析与实现
- [zz]三种模式匹配算法(KMP,MonteCarlo,LasVegas)的比较与分析
- poj 3461 KMP模式匹配算法
- 模式匹配算法kmp
- 字符串的模式匹配算法 KMP
- 字符串模式匹配(所谓的kmp)算法
- 【原创】朴素的模式匹配和改进的模式匹配(KMP)算法说明(草稿)
- KMP模式匹配算法以及普通模式匹配算法
- 串的模式匹配算法(非kmp)
- 模式匹配 -- KMP 算法原理与实现
- 字符串模式匹配之一-------BF & KMP
- KMP模式匹配算法
- KMP字符串模式匹配算法最详解
- KMP字符串模式匹配算法
- 一种比KMP更优的字符串模式匹配算法
- KMP模式匹配算法的一些理解