KMP模式匹配:
时间复杂度O(n+m)
意义:已匹配的指针i不用回退了
概念解释
主串标记i,模式串标记j
前缀:除最后一个字符外,字符串的所有头部子串;
后缀:除最后一个字符外,字符串的所有尾部子串;
部分匹配值:字符串前缀和后缀最长相等前后缀长度。
下次移动位数:已匹配部分数据段长度-部分匹配值
先统计已匹配i个模式串字符时,该i个模式串字符的部分匹配值next[j]
下次移动位数=(j-1)-next[j-1]
移到j发现不匹配了,所以已匹配长度=j-1,若用原始算法,i应退回(i-j+1)+1的位置
部分匹配数组定义
匹配到第j个不相同时,下次开始匹配模式串的位置
void GetNext(char c[], int *next){
int i=1, j=0, n; //j:模式串中头尾相匹配的个数
next[0]=0;
n = strlen(c);
while(i < n){
if( j==0 && c[i]!=c[j] ) { //匹配到第二个元素不一样,下次从next[0]开始
next[i]=0; ++i;
}
else if( c[i]==c[j] ){ //头尾相匹配,++j,next[i]=j,++i
j++; next[i]=j; i++;
}
else{ //从非第一个位置开始,若不匹配从next[j-1]个重新匹配
j=next[j-1];
}
}
}
KMP匹配过程
int KMPmatch(char original[],char module[]){
int orlen,molen,i=0,j=0;
int next[100]; //匹配到第j个不一样,下次从第next[j]的位置匹配,模式串最长100
GetNext(module,next); //为模式串各个匹配长度的部分匹配长度赋值
orlen = strlen(original); molen = strlen(module);
while(i<orlen && j<molen){
if(j==0 && original[i]!=module[j]){ //第一个数字就不一样
++i;
}
else if( original[i]==module[j] ){ //匹配相等
++i; ++j;
}
else{ //j!=0且匹配不相等,j后退部分匹配个数
j=next[j];
}
}
if(j==molen) return i-j+1; //匹配成功,返回变量所在位置
else if(i==orlen) return NOTHAVE;
else return -9999;
}
文件初始定义
#include <stdio.h>
#include <stdlib.h>
#define NOTHAVE 0
int strlen(char *c){
int i=0;
while(c[i] != '\0'){ //字符串以'\0'结尾
i++;
}
return i;
}
main函数测试
int main(){
char origin[50],modu[10]; int next[50]; int i,n;
scanf("%s",origin);
scanf(" %s",modu);
GetNext(modu, next);
n = strlen(modu);
// for (i=0; i<n; i++){
// printf("%d,",next[i]);
// }
int num = 0;
num = KMPmatch(origin, modu);
printf("\n%d",num); //输出匹配到的位置
return 0;
}