第一次写博客有点小激动,今天要讲一下KMP算法,这个查找算法比较难理解,我也是想了很久才想明白,我们在str2中的pos位置开始查找str1,当找到的时候返回str2中的下标,没有找到的时候返回-1;首先我们来参考一下我们最初写的查找字符串的函数,定义i=0为str2的下标,j=0为str1的下标,开始循环的时候,当遇到str2中的值,与str1中的值不同的时候,i变为最开始i前进的下一个下标,j的下标变为0,不断循环,知道i的值或者j的值大于他们的长度,然后再次判断,如果j的值大于str1的长度,则i-j的值,就是在str2中找到的str1的位置,在此函数中i需要不断地回退,因此时间复杂度比较大,在最大的时候会为O(n^2),因此我们用KMP算法的一个好处是i不需要回退,只需要把j回退到它该退的位置,j回退的位置,因此这样的时间复杂度较低,为O(m+n)首先我们需要在str1中查找两个相同的真子串,第一个真子串是str1的开头作为开头,第二个真子串是以刚刚匹配失败的前一个下标位置的作为结尾,每一次匹配失败的时候我们都需要去查找j该退回的位置,因此,定义一个数组来保存在每一个位置匹配失败的时候j应该回退的下标,下面的BF()是我们初次写的查找字符串的函数,Getnext()函数是我们获取一个next数组用来保存每一次j需要退回的位置,Getnextval()是根据得到的next再将j再次退到它直接应该回退的位置无论是利用Getnext()或者Getnextval()都能将j退回到该退的位置,然后从那个位置开始又与str2开始比较。
#include
#include
#include
#include
int BF(const char * str, const char *sub, int pos)
{
assert(str != NULL&&sub != NULL);
int lenA = strlen(str);
int lenB = strlen(sub);
if (pos<0 || pos>lenA)
{
return -1;
}
int i = pos;
int j = 0;
while (i < lenA&&j < lenB)
{
if (str[i] == sub[j])
{
i++;
j++;
}
else
{
i = i - j + 1;
j = 0;
}
}
if (j >= lenB)
{
return i - j;
}
else
{
return -1;
}
}
static void Getnext(char *next, const char *sub)
{
assert(next != NULL&&sub != NULL);
int len = strlen(sub);
if (len < 0)
{
return;
}
next[0] = -1;
next[1] = 0;
int j = 1;
int k = 0;
while (j < len-1)
{
if (k==-1||sub[j] == sub[k])
{
next[++j] =++k;
}
else
{
k = next[k];
}
}
}
static void Getnextval(char *next, const char *sub)
{
assert(next != NULL&&sub != NULL);
int len = strlen(sub);
if (len < 0)
{
return;
}
next[0] = -1;
next[1] = 0;
int j = 1; //sub的下标
int k = 0;
while (j < len - 1)
{
if (k==-1||sub[j] == sub[k])
{
++k;
++j;
if (sub[j] == sub[k])
{
next[j] = next[k];
}
else
{
next[j] = k;
}
}
else
{
k = next[k];
if (sub[k] == sub[j])
{
next[j] = next[k];
}
}
}
}
int KMP(const char *str, const char *sub, int pos)
{
assert(str != NULL&&sub != NULL);
int lenA = strlen(str);
int lenB = strlen(sub);
if (pos<0 || pos>lenA)
{
return -1;
}
int i = pos;
int j = 0;
char * next = (char *)malloc(lenB * sizeof(char));
Getnextval(next, sub);
while (i< lenA && j < lenB)
{
if (j==-1||str[i] == sub[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j >= lenB)
{
return i - j;
}
else
{
return -1;
}
free(next);
}