“KMP算法”,又称看毛片算法(我瞎说的),这个算法的引入极大地优化了字符串匹配的匹配的效率。是一个十分著名的算法。
它的原理就是通过给要匹配的字符串加一个next数组,以这个数组来作为它的回溯指导,减去不必要的回溯。那么首先来看一下next数组的规则是什么,我简单概括一下,就是判断当前位置的后缀有无前缀匹配,如果有,假设后缀字符串长度为n,为多少就在当前位置填n+1;
举个简单的例子,字符串T和它的next数组;
T a b a a b a a b
next 0 1 1 2 2 3 4 2
首先要明确前缀必须从第一位开始它是固定的,不能从第二位开始。
我们分析第一个,next[1]始终是0,这个不解释,然后从第二位开始肯定也是1这是固定的,
然后我们从3位看起,这时候,前缀的值为a,后缀是b,不匹配填1,
第4位,前缀依旧是a,后缀变成a,有匹配值长度1,填1+1;
第5位,后缀虽然有aa,但是没有前缀匹配,故只能是后缀a和a匹配,填2;
第6位,前缀可以ab了,后缀也是ab,匹配,长度2,填2+1;
第7位,后缀aba可以找到匹配的前缀值,长度为3,填3+1;
这就是比较简单的理解,如果你是应付考试,做题看到这里就可以结束了,下面要说的是真正的难以理解的地方。我们来看一段代码,可以跟着代码单步调试理解,
void get_next(String T, int *next)
{
int i = 1;
int j = 0;
next[1] = 0;
while (i < T[0])
{
if (0==j || T[i] == T[j])//匹配失败就回溯,成功给next[]赋值;
{
i++;
j++;
if (T[i] != T[j])
{ next[i] = j; }//把数组位置给next[i];
else
next[i] = next[j];
}
else {
j = next[j];//回溯位,
}
}
}
int KMP(String S,String T)
{
int i = 1;
int j = 1;
int next[255];
get_next(T, next);
while (i <= S[0] && j <= T[0])
{
if (0 == j || S[i] == T[j])
{
i++;
j++;
}
else
{
j = next[j];//从回溯位置开始继续匹配
}
}
if (j > T[0])
{
return i - T[0];
}
else
{
printf("查找失败");
return 0;
}
}
void main()
{
char S[255] = " ababaaaba";
S[0] = 9;
char T[255]=" abc";
T[0] = 3;
printf("%d", KMP(S, T));
}