串的模式匹配:KMP算法
o(m*n)的简易算法
int Index(string S, string T, int pos){
//返回子串T在主串S中第pos个字符之后的位置。若不存在,函数返回值为0
//其中T非空,1<<pos<<S.length()
int i=pos,j=0;//每一次字串都从头遍历
while(i<S.length() && j<T.length()){
if(S[i]==T[i]){//继续比较后面的指针
++i;
++j;
}
else{//否则从主串的下一个字符重新开始匹配
i=i-j+1;
j=0;
}
}
if(j=T.length())
return i-j.length()+1;//返回第一次匹配成功的首字符在主串中的位置
}
O(n+m)改进:KMP算法
O(m*n)的算法每次匹配失败后都要左移主串和字串的指针
而KMP只需要移动字串指针,主串指针不动
引入next[ ]与match[ ]数组
next[i]表示子字符串前i个元素中相同前缀与后缀的最长长度
match[i]表示next[i]条件下的最大前缀末尾在数组中的位置
显然match[j]=next[j]-1;
next[ ]从next[0]=0开始递推求解
match[ ]从match[0]=-1开始递推求解
因为match[j]=next[j]-1,所以可以直接对match[ ]数组进行求解
match[ ]数组代码实现:
void BuildMatch(char *pattern, int *match){
int i,j;
int m=strlen(pattern);
match[0]=-1;
for(j=1; j<m; ++j){
i=match[j-1];
//通过循环不断向前递推找到不仅有相同前缀后缀的情况,还要使pattern[i+1]=pattern[j]来更新match[j]的值
//没有找到则赋值-1
while((i>=0) && (pattern[i+1]!=pattern[j]))
i=match[i];
if(pattern[i+1]==pattern[j])
match[j]=i+1;
else
match[j]=-1;
}
}
KMP算法实现:
int KMP(char *string, char *pattern){//
int n=strlen(string);
int m=strlen(pattern);
int s, p, *match;
if(n<m)//考虑边界情况
return -1;
match=(int *)malloc(sizeof(int)*m);//为match数组开辟空间
BuildMatch(pattern, match);//构建match数组
s=p=0;//s为string的下标,p为pattern的下标
while(s<n && p<m){
if(string[s]==pattern[p]){//所指内容相同,两个指针全部右移
++s;
++p;
}
else if(p>0){//所指内容不同,s不动,p根据match数组进行移动
p=match[p-1]+1;
}
else//讨论pattern中只有一个元素的情况
++s;
}
return (p==m) ? (s-m) : -1;//返回s中匹配字串的起点位置
}