近期在复习数据结构,看到串的时候看到这样一道题,求模式串strSub在主串strPrim中第一次出现的位置。第一种常规算法即BF算法,定义两个指针,一个i指向strPrim第一个字符,另一个j指向strSub第一个字符,两者相等,同时后移,两者不等,让j回到strSub第一个字符位置,i回到上次比较完成的下一个位置。另一种是KMP算法,使用一个next数组来完成匹配,本文的目的是通过BF算法与KMP算法比较来理解KMP算法。
// BF算法求模式串在主串中第一次出现的位置
int BF(const char* strPrim, const char* strSub)
{
int i = 0, j = 0;
while (strPrim[i] != '\0' && strSub[j] != '\0')
{
if (strPrim[i] == strSub[j])
{
++i; ++j;
}
else
{
i = i - j + 1;
j = 0;
}
}
if (strPrim[i] == '\0')
return -1;
if (strSub[j] == '\0')
return i - j;
return -1;
}
// KMP算法求模式串在主串中第一次出现的位置
void GetNext(const char* strSub, int *next)
{
//求模式串T的next函数修正值并存入数组next。
int i = 1;
next[0] = -1;
next[1] = 0;
int j = 0;
while (strSub[i] != '\0')
{
if (j == 0 || strSub[i] == strSub[j])
{
++i; ++j; next[i] = j;
}
else
{
j = next[j];
}
}
}
int KMP(const char* strPrim, const char* strSub)
{
if (!strPrim || !strSub || strSub[0] == '\0' || strPrim[0] == '\0')
return -1;
int i = 0, j = 0;
int next[26];
GetNext(strSub, next);
while (strPrim[i] != '\0' && strSub[j] != '\0')
{
if (strPrim[i] == strSub[j])
{
i++; j++;
}
else
{
j = next[j];
if (j == -1)
{
i++; j++;
}
}
}
if (strSub[j] == '\0')
{
return i - j;
}
else
return -1;
}
对比两段代码,我们发现:BF算法与KMP算法在比较的时候,
如果相等,两者都是让指针向后移动;
如果不相等,BF算法,i指向上一次遍历完的下一个位置,j指向初始位置。KMP算法,i不动,让j指向next数组中j下标的元素位置,也就是上次比较结束不等的位置。
基于这样的发现,我们可以看出,next数组是KMP算法的精髓,再通过比较KMP函数与GetNext函数,我们发现两者很相似,其实求next数组的过程也是使用了KMP算法。