匹配过程中,若相同,主串和模式串指针各增加1
若产生失配,则主串指针不变,模式串指针退回到next位置继续匹配,若模式串指针退回到0匹配失配,则主串指针加1,,模式串指针仍为索引为0的字符重新开始匹配
计算模式串的next数组值
next数组值表示:主串中第i个字符与模式串中第j个字符失配时,主串中第i个字符应该与模式串中哪个字符再进行比较,只和模式串有关,和主串无关
/*
StrLocation 0 1 2 3 4 5 6 7
Str a b a a b c a c
BackIndex -1 0 0 1 1 2 0 2
kmp算法中当主串第j个字符与模式串索引i个字符(索引从0开始)匹配失效时,模式串退回到 Next[i]继续匹配
*/
void GetNext(std::string Str, int Next[])
{
int StrLocation = 1;
int BackIndex = 0;
Next[0] = -1;//作为首字符判断位,如果Next[0] = 0,if条件if (BackIndex == 0 || Str[BackIndex] == Str[StrLocation])判断失效
Next[1] = 0;
while (StrLocation < Str.size())
{
if (BackIndex == -1 || Str[BackIndex] == Str[StrLocation])
{
Next[StrLocation + 1] = BackIndex + 1;
StrLocation++;
BackIndex++;
}
else
{
BackIndex = Next[BackIndex];
}
}
}
//Next[0]作为当最长公共前后缀子串只有第一个字符时,即 BackIndex == 0 且 Str[1] != Str[StrLocation] 时的标志,
//Next[0]可以是任何其他非索引范围的整数,但是设为-1的好处是可以合并判断同时加1,
//而不必分开判断将模式串索引位置0
void kmp(const std::string MainStr, const std::string MinorStr)
{
const int n = MinorStr.size();
int Next[100];
GetNext(MinorStr, Next);
int MainIndex = 0, MinorIndex = 0;
while (MainIndex < MainStr.size() && MinorIndex < MinorStr.size())
{
if (MinorIndex == -1 || MainStr[MainIndex] == MinorStr[MinorIndex])
{
MainIndex++;
MinorIndex++;
}
else
{
MinorIndex = Next[MinorIndex];
}
}
}
在想为什么Next[0] = -1; 如果 Next[0] = 0;只能知道回退到了模式串首字符,但是无法根据 Next[0]的值确定模式串首字符是否匹配,且可能陷入死循环
对比下面的代码
void kmp(const std::string MainStr, const std::string MinorStr)
{
const int n = MinorStr.size();
int Next[100];
GetNext(MinorStr, Next);
int MainIndex = 0, MinorIndex = 0;
while (MainIndex < MainStr.size() && MinorIndex < MinorStr.size())
{
if (MinorIndex == Next[0] && MainStr[MainIndex] != MinorStr[MinorIndex]) //when Next[0] = 0
{
MainIndex++;
MinorIndex = 0;
}
else if (MainStr[MainIndex] == MinorStr[MinorIndex])
{
MainIndex++;
MinorIndex++;
}
else
{
MinorIndex = Next[MinorIndex];
}
}
}
void GetNext(std::string Str, int Next[])
{
int StrLocation = 1;
int BackIndex = 0;
Next[0] = 0;
Next[1] = 0;
while (StrLocation < Str.size())
{
if (BackIndex == 0 && Str[BackIndex] != Str[StrLocation]) //when Next[0] = 0
{
Next[StrLocation + 1] = BackIndex;
StrLocation++;
}
else if(Str[BackIndex] == Str[StrLocation])
{
Next[StrLocation + 1] = BackIndex + 1;
StrLocation++;
BackIndex++;
}
else
{
BackIndex = Next[BackIndex];
}
}
}