目录
1.关于KMP
KMP算法与BF算法的作用类似,都可以用来查找模式子串。但是对比于BF算法的蛮力破解,KMP算法用了一种巧妙的方式减少了回溯次数。
2.KMP算法的思路
这里我们用指针i表示指向文本串(父串)str,用指针j表示指向模式串(子串)sub。BF算法是当遇到str【i】!=sub【j】时,i回溯到匹配成功的下一个位置,j回溯到开头。
关于代码可以参考:用c语言实现BF算法_不会敲代码的运气选手^的博客-CSDN博客
KMP算法的神奇之处在于当遇到str【i】!=sub【j】时,i不用回溯,j回溯到一个特殊位置。特殊位置用一个next数组保存。
A.先看看如何手算next数组:
以下图为例:
B.计算机要如何计算next数组呢?
我们不妨先令i=2,k=0;
如果next[i-1]=k,那么next[i]=k+1;
如果next[i-1]!=k,那么k=next[k],对k进行回溯,令k=next[k]。
3.实现代码:
void getnext(char* sub,int lensub,int* next)
{
next[0] = -1;
next[1] = 0;
//从i==2开始处理
int i = 2; int k = 0;
while (i < lensub)
{
if (sub[i - 1] == sub[k]||k==-1)
{
next[i] = k + 1;
i++;
k++;
}
else
//找不到将k回溯重新判断
k=next[k];
}
}
int KMP(char* str, char* sub, int lenstr, int lensub,int pos)
{
//预处理特殊情况
assert(str&&sub);
if (pos < 0 || pos >= lenstr)
return -1;
if (lensub>lenstr)
return -1;
int i = pos; int j = 0;
//next数组是KMP算法的关键,next数组是用来存子串回溯位置的。
int* next = (int*)malloc(sizeof(int)*lensub);
getnext(sub, lensub,next);//处理next数组
//与bf算法类似
while (i < lenstr&&j < lensub )
{
if (str[i] == sub[j] || j == -1)//将j==-1单独处理防止数组越界
{
i++;
j++;
}
else
//回溯j
j = next[j];
}
if (j>=lensub)
return (i - j);//找到了,与bf算法结论一样。
return -1;
}