网上有很多解释KMP算法的文章,A_B_C_ABC(见附件)的 这篇很详细,反复看了好几遍,总算理解了个大概,但是总觉得没那么爽快。其实,一种算法各人有各人的理解方法,找到适合自己理解的才容易记住。下面是我对 这个算法的一些理解:
最普通的字符串匹配算法就不记了,简单贴一下代码
-
int strstr(char *sub, char* str){
-
int i=0;
-
char *p=str, *q=sub;
-
while(*(p+i)!='\0'&&*(q+i)!='\0'){
-
if(*(q+i)==*(p+i))
-
i++;
-
else{
-
p++;
-
i=0;
-
}
-
}
-
if(*(q+i)=='\0')
-
return p-str;
-
return -1;
-
}
当next(j)=k (k>=0)时,子串指针回溯到的位置,父串指针不变;
当next(j)=-1时,子串指针回溯到头,父串指针前进一步;
假设子串为P:"abacabab", 且我们将要求的是'b'的next值, e.g. next[7]
假设next[0~6]均为已知: next[0]=-1, next[1]=-1 , next[2]=0 , next[3]=-1 , next[4]=0 , next[5]=1 ,next[6]=2
- 若相等则 next[7] = next[6]+1
- 若不等, 我们进一步找更短的前半段与后半段相等的子串,因为aba和aba是一样的, 要找'abacaba' 中比'abc'短的这样的子串,相当于找'aba' 中的next[2]值是一样的.也就是next[next[6]]的值。然后再比较P[next[next[6]]+1]和P[7]是否等,若不等则继续 找更短的这样子串
在上的例子中 P[next[6]+1]=P[3]('c') ,与P[7]('b')不相等, 但是 P[next[next[6]]+1] = P[next[2]+1] = P[1]('b'), 与P[7]('b')相等
-
void calnext(char* P, int next[]){
-
next[0] = -1; //第一个元素的next总是-1, 因为根据(1) , 我们并找不到一个k比j=0小
-
for(int i=1; i<strlen(P); i++){
-
int k = next[i-1]; //因为采用递归的方法, 为了计算next[i], 先记录下next[i-1] 而且假设next[i-1]已知
-
while(P[k+1]!=P[i]&&k>=0){ // 递归
-
k = next[k];
-
}
-
if(P[k+1]==P[i]) //如果相等而结束, 则找到一对长度为k的前缀字串和后缀字串
-
next[i] = k+1; //增加了一个相同项
-
else
-
next[i] = -1; //其他情况
-
}
-
}
-
int find(char*T, char* pat){
-
int n = strlen(pat);
-
int *next = new int[n];
-
calnet(pat, next);
-
char *p=T, *q=pat;
-
int i=0;
-
while(*p!='\0'&&(*(q+i)!='\0')){
-
if(*p==*(q+i)){
-
p++;
-
i++;
-
}else{
-
if(i==0)
-
p++;
-
else
-
i = next[i-1]+1;
-
}
-
}
-
if(*(q+i)=='\0')
-
return p-T-n;
-
else
-
return -1;
-
}