1.串匹配的朴素方式;
已知两个串,源 abcde 模式串 de ;
用3个指针, 开头匹配,然后分别 增加,直到全匹配为止;否则 移动 de。代码如下:
int brutal_force(char *s,char*t){
int slen= strlen(s);
int tlen= strlen(t);
int i = 0;
while(i<slen-tlen){
int p=i;
int q=0;
while(q<tlen&&s[p++]==t[q++]);
if(q==tlen)
return i;
else
i++;
}
}
设slen 为n, tlen为m 复杂度 O(m*n)
2.KMP的方式
思想就是发生不匹配的时候,模式串尽量多移动
例如 ababd 匹配
abababdc 的时候 到最后一位 模式串的第五位 不匹配
应该直接移动 两位,而且开头的部分不用再比较,仍然从源串的第五位和next[5]继续比较
ababd
abababdc
这个移动的位置,存储 在next [m]的数组中,这个值只与 模式串的固有属性有关。
这里就不细细讨论原理, 这个值就是 : T[0],T[1]...T[m-1]的前缀和后缀的最长匹配长度。
这个next数组的求解代码十分巧妙简短,可以用循环不变式验证。
代码如下:
void index(char *t){
int len = strlen(t);
int j = -1;
int i = 0;
next[i]=j;
while(i<len-1){
if(j==-1 || t[i]==t[j]){
i++;
j++;
next[i]=j;
}else{
j=next[j];
}
}
}
int kmp(char *s ,char *t){
int slen = strlen(s);
int tlen = strlen(t);
int i =0, j =0;
while(i<slen && j<tlen){
if(j==-1||s[i]==t[j]){
i++;j++;
}else{
j=next[j];
}
}
if(j==tlen)
return i-j;
else
return -1;
}
index部分还可以优化一下,即 如果 S[I]!=T[j] 时 就会更新 j=next[j] 但是要避免 T[j]==T[next[j]]的情况。 所以给next 数组加这条约束 例如aaaaaaab 求next的时候就会做很多无用功 ,退化成朴素的方式了。
修改了某4行 :
int next_val[5];
void get_next_val(char *t){
int len = strlen(t);
int j =-1;
int i = 0;
next_val[i]=j;
while(i<len-1){
if(j==-1||t[i]==t[j]){
i++;
j++;
if(t[i]==t[j])
next_val[i]=next_val[j];
else
next_val[i]=j;
}else{
j=next_val[j];
}
}
}