参考了博客园博主:sofu6 的博文:KMP算法详解-彻底清楚了(转载+部分原创)
KMP算法用于快速比较在主串中模式串(p)是否匹配的问题,又可理解为类似搜索引擎中的关键字匹配。
相比传统的BF算法,优点在于提升了比对效率,主要体现在:不必像BF算法一样一个字符一个字符的比对,遇到坏字符就将p移到开始位置0,再一个个比对,而是移动到一个合适的位置,以此来减少无效的比对次数
该算法的重点在于弄懂其中用于存放: 比对过程中,模式串遇到不匹配的字符(这里叫做坏字符)时,模式串如何在主串中移动到合适的位置,开始下一次的匹配的 模式串指针返回位置。因为比对中会存在多次遇到坏字符甚至p根本就不匹配主串的情况,所以用一个数组next[](该算法的关键就在该数组的求解过程)来存放这多次遇到坏字符的返回位置。
求解next[]数组算法如下:
void GetNext(int next[], char *t){
int i = 0;
int j = -1;
int tlen = strlen(t);
next[0] = -1;
while(i < t-1){
if(j == -1 || t[j] == t[i]){
i++;
j++;
next[i] = j;
}else{
j = next[j];
}
}
}
理解分解:
1、j = -1 这里初始化为-1,是因为考虑到若连续遇到坏字符的返回需要
2、next[0] = -1 这里的初始化为-1,同上(1)原因一样,另外是若在刚开始比对时,第一个(位置为0时)遇见的就是坏字符,此时的模式串没有可返回的位置,再结合接下来比对中若遇到匹配的要进行j++,则表示存在有遇到坏字符后可以返回的位置了,位置当然不能是-1,至少要是0开始。
3、最为关键的:j = next[j] 先理清一下如下定义:
首先next数组存放的时,遇到坏字符时,模式串中下一个要比对的字符就要返回的位置,也就是坏字符前面已匹配的串中最大可重复前缀串的长度
个人理解是:每当遇到坏字符,我们就要回头查看主串中这个坏字符前的后缀串与模式串该坏字符前的前缀穿的最大可重复串,这个串的长度假设为j,即前面已经存在的next[i] = j,然后将模式串的下一个要匹配的字符位置移动到这个长度j所处的位置,即j=next[j],然后继续开始比对,若匹配,则向++操作,否则重复前面的回退过程,直到j=-1,然后主串要比对的字符下移一个位置i++,此时i++后的前面的串中不存在最大可重复的串,也即最大可重复串的长度为0,因为此时的j=-1也就是j++后为0,也就是模式串移动到j位置,也即开始第一个字符(0位置)再开始同主串i++后的字符比对,此时也就完成了模式串的移动。