kmp算法是一种单模式匹配算法,一般来说就是可以在一个字符串中查找一个模式串,并返回模式串匹配的位置。而 kmp算法的核心是next数组,next数组利用回溯的思想,当字符不匹配时,回退到前面已经匹配成功的下一个位置。
最开始呢,我其实真的很不理解next数组,我只知道回退到最大前后缀的子串的长度,但是next数组和最大前后缀子串有个毛的关系啊,这完全不能理解啊,最大前缀,最大后缀,有什么联系吗?其实网上各种什么前缀后缀,目的只有一个,就是知道从模式串的首部第一个字符开始,最前面的k个字符和当前j字符之前的最后k个字符是一样的。这句话能够理解了,基本就不会被那些公式什么的搞得头大了,当然公式其实也很重要,是用逻辑来证明这些东西的,但是我看着那个公式的推导,真的头大。
先摆出求next数组的函数:
void next(const char * T,int next[])
{
int k = -1;
int j = 0;
next[0] = -1;
while(T[j]!='\0')
{
if (-1 == k || T[k] == T[j])
{
if (T[++k] == T[++j]) //当前位置的字符的下一个字符
{
next[j] = next[k]; //下一个字符的next值和前面的next[k]的下一个值相同,上面if中,j,k都前移了一位
}
else
{
next[j] = k;//下一位的字符不同,得到j下一个位的next值为k
}
}
else
k = next[k];
}
}
其是next数组的目的是要知道当模式串中有个字符和主串的某个字符不匹配时,我们应该将从模式串的什么位置再重新进行匹配。 在各种求next数组的函数中,k=next[k]这句是最不好理解的,这里其实是当模式串后面的字符没有与前缀字符相匹配时,需要回退到什么位置,因为T[k]!=T[j]时,说明,这里的j指向的字符和前缀中第k个字符不同,这时就要将k字符回退,这时回退的值就应该是k字符的next值,一直要回退到T[j]==T[j]直至起点,即重新和前缀字符相同的位置,这里其实就是跑着跑着和组织失联了,那我们就得回到最后一次和组织联系的地方在看看能不能和组织联系得上。