设:m是模式串pattern的长度,n是主串长度
传统的字符串匹配(暴力法)的时间复杂度是O(n*m)。
而KMP串匹配算法可以将时间复杂度降为O(n+m),这需要一个额外的预处理O(m)。
KMP优化的地方在于:当出现字符失配的情况时,无需回溯i指针,而是利用已经匹配的部分,将模式串尽可能向右滑动一部分。
实际上:KMP的预处理本身就是一个模式串pattern“自我匹配”的过程。因此,预处理和kmp算法主体非常神似。
预处理过程:
int get_next(char* p, int* next)
{
int len = strlen(p);
int i = 0, k = -1;
next[0] = -1;
while(i<len)
{
if(k==-1 || p[i]==p[k])
{
i++;
k++;
next[i] = k;
}else
{
k = next[k];
}
}
}
KMP匹配算法,这里我们和书上的做了一点改进,加入了一个start,即可以支持在主串中查找多次模式串。代码如下:
int kmp_index(char* s, char* p, int* next, int start)
{
int i=start,j=0;
int slen = strlen(s);
int plen = strlen(p);
while(i<slen && j<plen)
{
if(j==-1 || s[i]==p[j])
{
i++;
j++;
}else
{
j = next[j];
}
}
if(j>=plen)
{
return i-plen;
}else
{
return -1;
}
}
测试驱动如下:
int main()
{
char* str = "xxabaabcacxxabaabcacdabaabcac99";
char* pattern = "abaabcac";
int next[MAX];
int plen = strlen(pattern);
int i;
// Get next value
get_next(pattern, next);
for(i=0;i<plen;i++)
{
printf("%d ", next[i]);
}
printf("\n");
// KMP Index
i=0;
while(i!=-1)
{
i = kmp_index(str, pattern, next, i);
if(i!=-1)
{
printf("'%s' @ %dth of '%s'\n", pattern, i, str);
i++;
}
}
return 0;
}