普通的匹配算法在最坏的情况下的效率很低,如:‘00001’,主串:‘00000000000000001’,则时间复杂度为O(n*m ).
kmp算法不需要回溯指针,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。
简单来说,模式串中的某个字符匹配失败了,返回下一个要查找的字符,看个例子:模式串:‘abcabd’,主串:‘cabcabcabd’,第一次匹配模式串的第一个与主串的第一个不匹配,则指针向后移动一位,模式串的第一个与主串的第二个匹配成功,依次向后匹配,当模式串的最后一个字符‘d’与主串的第5个字符‘c’匹配失败这时不需要指针回溯,观察主串与模式串发现将模式串的第三歌字符与刚刚主串中匹配失败的字符匹配,这便是kmp算法的核心思想。
还可以多举几个例子,便可以发现:
移动位数 = 已匹配的字符数 - 对应的部分匹配值
那我们只需要将模式串中的各个字符匹配失败是移动的位数求出,用一个数组存放,取名next。
typedef char String[MAX + 1];//0位贮存串的长度
定义了一个串的类型。下面是的得到next数组的函数
void getNext(int *next,String str)
{
int i = 0,j = 0;
int length = str[0];
next[0] = 0;
while(i < length)
{
if(!j || (str[i] == str[j]))
{
j++;
i++;
next[i] = j;
}
else
j = next[j];
}
}
求得了next数组就可以进行匹配算法
int match(String str1,String str2)
{
int next[str1[0] + 1],i = 0,j = 0;
getNext(next,str1);
while((i <= str1[0]) && (j <= str2[0]))
{
if(!i || (str1[i] == str2[j]))
{
i++;
j++;
}
else
i = next[i];
}
if(i == str1[0] + 1)
return j - str1[0];//匹配成功,返回的一个字符的位置
return 0;
}
当使用kmp算法时时间复杂度为O(m + n)
当然还可以对next数组进行优化,这里不详细写了。