- 简单的模式匹配算法
a. 基本思想:从主串S指定的字符开始和模式串T的第一个字符比较,若相等,则继续逐个比较后续字符串,直到T中的每个字符依次和S中的一个连续的字符序列相等,则匹配成功。若比较途中某对字符不想等,则从主串S的下一个字符开始比较。如果S串比较完,仍没匹配成功,则称匹配不成功。
b. 代码
int Index(SString S, SString T)
{
int i=1,j=1;
while(i<=S[0]&&j<=T[0])
{
if(S[i]==T[j])
{++i;++j;} //比较下一字符
else {i=i-j+2;j=1;} //指针后退重新开始匹配。
}
}
c. 该方法容易,不用过多说明最坏时间复杂度O(n*m)
2. KMP算法(改进的模式匹配算法)
a. (这个是比较重要的字符串匹配模式) 基本思想:上面朴素匹配方法典型有很大的问题,在一次比较不成功后,直接回溯i指针。KMP算法的改进方式就是比较字符串不匹配时,无需回溯i指针,利用已得到的“部分匹配”的结果将模式向右”滑动“尽可能远的一段距离后,继续进行比较。怎样尽可能滑的远,这就值得讨论了。
b. 解决方法
KMP算法的每趟比较让子串向后滑动一个合适的位置(next数组求解),让这个位置上的字符和主串中的那个字符比较,这个合适的位置与子串本身结构有关。
c. 子串T的next[]数组求解. ( 很尴尬,本想搜执行图贴上来,还是手写一下图形了 )
next数组:
(1)next[1]=0.next[2]=1. (next[0]不使用)
(2)后面求解每一位的next[j]值时,根据j的前一位进行比较,令k=next[j-1];
(3)将T[j-1]与T[k]进行比较:
a.如果相等,则该next[j] = k+1;
b.如果不等,令k=next[k],若k不等于0,跳至(3)。若k等于0,next[j]=1.
代码:
void get_next(char T[],int next[]){
i=1;
next[1]=0;
j=0;
while(i<=T[0]){ //T[0]保存字符串长度
if(j==0||T[i]==T[j]){
++i;++j;next[i]=j;}
else j=next[j];
}//while
}
手写例子如下
d. KMP匹配算法
形式上与简单的模式匹配算法很相似,不同之出就是匹配失败时,指针i不变,指针j退回next[j]的位置上,再重新进行比较。并且当指针j为0时,指针i和j同时加1(即主串第i个位置和模式串的第一个字符不等时,应从主串的第i+1个位置开始匹配)。
代码:
int KMP(char S[],char T[],int next[],int pos){
//利用模式串T的next数组,求T在主串S中第pos个字符之后的位置的KMP算法
//其中,T非空,1<= pos <=strlen(S)
i = pos;
j = 1;
while(i<=S[0]&&j<=T[0]){
if(j==0||S[i]==T[j]){
++i;++j;
}
else j=next[j];
}//while
if(j > T[0])
return i-T[0];
else
return 0;
}
时间复杂度O(n+m)