算法思想描述:
KMP算法是通过分析模式串,预先计算每个位置发生不匹配的时候,可以省去重新匹配的的字符个数。整理出来发到一个next数组, 然后进行比较,这样可以避免字串的回溯,模式串中部分结果还可以复用,减少了循环次数,提高匹配效率。通俗的说就是KMP算法主要利用模式串某些字符与模式串开头位置的字符一样避免这些位置的重复比较的。例如 主串: abcabcabcabed , 模式串:abcabed。当比较到模式串'e'字符时不同的时候完全没有必要从模式串开始位置开始比较直接从模式串的'c'字符开始比较就可以了。并且主串也不用回溯了。
分析模式串过程,假设模式串当前位置与主串位置不同,如何利用模式串中当前位置之前与模式串开始出相同的字符。不用从开始相互比较。
来一个例子:
模式串p_s:abaabc next[0-5] =0
单前位置 next 复用字符数(j) description
0 next[0]=0 0 前面没有任何字符
1 next[1]=0 0 当前字符前只有一个字符,无法服用的。
2 next[2]=0 0 p_s[1]!=p_s[j]('a' != 'b',j = 0) ;
3 next[3]=1 1 p_s[2]==p_s[j]('a' == 'a',j = 0);
4 next[4]=1 1 p_s[3]!=p_s[j]('a' != 'b',j = 1);然后清空可复用字节数j=0,
但是不可一将next[4]直接赋值位0,虽然当前位置与之前位复用序
列比较已经无法在满足服用序列了。但其有可能满足一个新的所以
再次p_s[3]!=p_s[j]('a' != 'a',j = 0);
5 next[5]=2 1 p_s[4]==p_s[j]('b' == 'b',j = 2);
代码如下:(本代码只经过本人的简单测试,可能存在问题。请相信自己的能力,敢于质疑。欢迎提供更好的、更快、更简洁的代码或者方法和指出错误。在ubuntu12.04使用gcc4.6.3版本编译,在vc中如出现错误,请谅解。)
void
kmp_next(char p[], int next[], int pn)
{
int i,j;
next[1] = 0;
next[0] = -1;
i = -1; j = 0;
while(j < pn){
if(i == -1 || p[i] == p[j]) {i++,j++; next[j] = i;}
else i = next[i];
}
}
int
kmp(char s[], char p[], int sn, int pn)
{
int next[MAX];
int j =0, i = 0;
if(sn > MAX) {
printf("s is to long\n");
return 0;
}
if(pn > sn) {
return -1;
}
kmp_next(p, next, pn);
while(i < sn) {
if(j == -1 || s[i] == p[j]) {i++, j++; if(j>=pn) return i -pn;}
else j = next[j];
}
return -1;
}
int
main(int argc, char *argv[])
{
char s[]="abababcabcabacababd";
char p[MAX] = "bcc";
int index, i;
int next[MAX];
while( scanf("%s", p) && strcmp(p, "#") != 0) {
index = kmp(s, p, strlen(s), strlen(p));
printf("%s\n", s);
i = 0;
while(i>=0 && i++ < index) printf(" ");
printf("%s |", p);
printf("%d\n", index);
}
}