KMP算法 next数组解析
本文很多词汇为 个人创造,如:最长匹配真前后缀、 次级最长匹配真前后缀 等。如有表述不清,请联系我。
接上篇:
next 数组 主要记录 子串 的 每一个前缀(按顺序)的 最长匹配真前后缀 的长度。
这里讲一下 求解原理。
数组从零开始,第一个数 “-1” ,代表不存在;(有的以 “0”,为起点代表空,这不矛盾,全加1 ,即为此格式)
此数组是一点点增长的,下一个数据依赖之前的数据。
举例子来描述原理:
步骤1:
当新的最后一个字母过来,和上一个字符串的 最长匹配真前后缀 的前缀后一位相同,则在数组对应位置,记录上的数是上一个 最长匹配真前后缀 长度 +1 ;即next数组前一个位置next[j] +1. (新出现一个数,最长匹配真前后缀 的长度 最多 +1 ,对吧。下面会用到)
步骤2 :
.如果新过来的字符和下一个位置不相符,如何处理?
新出现一个数,最长匹配真前后缀 的长度 最多 +1
那一定就是要把下面的串右移!!!即 最长匹配真前后缀 的长度 会减少!!
怎么移呢? 从头一个一个匹配? 可以,但并不优秀。
之前next数组中记录的数据,是不是可以用起来呢?
我们求的是匹配长度最大值,可以从可能的最大值依次往下验证,成立即为新的最大。
划重点啦!!! 可能的最大值 是什么呢?
就是从 次级最长匹配真前后缀 的下一位 匹配啊!!!
举个例子: 子串 S = "abcdabceabcdabc" ; 新字符 为 'd'; 示例如下:
'd' 和 'e' 失配后,存在可能性的就是 次级最长匹配真前后缀 且长度从大到小排列的,就是 图中的 S4 !
此时只需要把 : ‘d’ 和 次级最长匹配真前后缀 S4 后面的字符比较就可以了!
此处并不需要具体 字符串是什么,只需要知道位置即可,且next 数组存的就是这些!故此可以利用起来!
如果相同 执行步骤一,如果不相同执行步骤二。
解释:
次级最长匹配真前后缀 是 字符串S 的第二长的 匹配真前后缀 ,同时也是 最长匹配真前后缀 (S3)的 最长匹配真前后缀。
在此处,各位看官怎么理解都可以。不过似乎 理解为 ,最长匹配真前后缀 (S3)的 最长匹配真前后缀 (-->S4),方便一些。便于理解这个代码中的循环处理。
附上代码:
void cal_next(char *str, int *next, int len)
{
next[0] = -1;//next[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀
int k = -1;//k初始化为-1
for (int q = 1; q <= len-1; q++)
{
while (k > -1 && str[k + 1] != str[q])//如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。
{
k = next[k];//往前回溯 //取其次级最长匹配真前后缀 的长度
cout<< "k = " << k <<endl;
}
if (str[k + 1] == str[q])//如果相同,k++
{
k = k + 1;
}
next[q] = k;//这个是把算的k的值(就是相同的最大前缀和最大后缀长)赋给next[q]
cout<<next[q]<<endl;
}
}