串的匹配算法:暴力匹配与KMP

一.暴力匹配算法

int Index(SString S, SString T){
int i=1,j=1;
while(i<=S.length&&j<=T.length){
if(S.ch[i]==T.ch[j]){
++i,++j;
}
}
else{
i=i-j+2;j=1;
}
}
if(j>T.length)
return i-T.length;
else return 0;
}

分别用计数指针i和j指示主串S和模式串T当中比较的字符位置。从主串S的第一个字符起,与模式T的第一个字符比较,若相等,则继续逐个比较后续字符,否则从主串的下一个字符开始,重新进行匹配,直到模式T中的每个字符依次和主串S中的一个连续的字符序列相等,则称匹配成功。

暴力匹配算法的最坏时间复杂度为O(mn),其中n和m分别为主串和模式串的长度。

二.KMP算法

在暴力匹配中,每次匹配失败将导致主串S比较字符位置的回溯,降低了效率的根源。

字符串的前缀和后缀

前缀:除最后一个字符外,字符串的所有头部子串。

后缀:除第一个字符外,字符串的所有尾部子串。

部分匹配值则为字符串的前后缀的最长相等前后缀长度。

可将部分匹配值写成数组形式,得到部分匹配值(PM)表。

当匹配失败时,移动位数=已匹配字符数-对应的部分匹配值。因为当匹配失败时,部分匹配值的部分无需再比较,用子串前缀后面的元素与主串匹配失败的元素比较即可。

已知:右移位数=已匹配的字符数-对应的部分匹配值,可写为:Move=(j-1)-PM[j-1]

将PM表右移一位,得到next数组。

 上式改写成Move=(j-1)-next[j],相当于将子串的比较指针j回退到j=j-Move=j-(j-1)+next[j]=next[j]+1。

求next值的程序:

void get_next(String T int next[]){
int i=1,j=0;
next[1]=0;
while(i<T.length){
if(j==0||T.ch[i]==T.ch[j]){
++i;++j;
next[i]=j;
}
else{
j=next[j];
}
}

设主串为s1s2....sn 匹配串为p1p2pm,假设此时应与模式中第k个字符继续比较,则模式中前k-1个字符的子串必须满足下列条件,且不可存在k'>k满足下列条件:p1p2...pk-1=pj-k+1pj-k+2...pj-1,若存在满足上述条件的子串,则发生失配时,仅需要将模式向右滑动至第k个字符。

KMP匹配算法

int Index_KMP(String S,String T,int next[]){
int i=1,j=1;
while(i<=S.length&&j<=T.length){
if(j==0||S.ch[i]==T.ch[j]){
++i;++j;
}
else{
j=next[j];
}
if(j>T.length)
return i-T.length;
else
return 0;
}

KMP算法的时间复杂度为O(m+n),其主要优点是不回溯。

 

posted @ 2021-03-13 22:55  第十八使徒  阅读(359)  评论(0)    收藏  举报