本人的理解,供参考,如有错误请指出谢谢
设子串:ababafgda
getnext 函数的目的就是找出子串的子串的共同前后缀的长度
设变量
j = 0:
k = 1:表示循环进度,也表示当前在那个子串的子串
len = strlen(子串) = 9
while(k < len - 1)
匹配失败
k++ ,进入下一个子串,在 +1 之前 k 表示的是 ab 子串
j = 0,肯定要归零,要不然怎么找前缀
匹配成功
此时 k = 2,就表示aba子串,那么aba子串的公共最长前后缀就是 1,这个 1 只能从 j 变量获得,此时 j = 0,所以
next[k] = j+1
就是说 aba子串的公共最长前后缀就是 1
匹配结束进入下一个子串,所以 k++,所以不论成功与否 k 都是要+1的
那么 j 呢,也是要 +1 的
为什么?aba
要获得 aba 的前后缀需要比对 ab 中的a 和 ba 中的b 的匹配 和 ab中的b 和 ba 中的a 的匹配这里需要分两种情况
如果 ab 是匹配成功的,那么ba 就是 ab 各自下标的+1的偏移
如果不匹配就需要从头开始匹配
显然 ab 是不匹配的,所以就需要匹配 ab 的a 和ba 的 a,如果成功就说明 aba 的公共最长前后缀就是 1,不成功就是0咯例如:abab
aba 中 ab 的a 和ba 的 a 是匹配的(见上面),所以接下来就该匹配 两个b 了,这两个b 的下标就是aba 中两个a 的下标+1
之后重复下标+1和归零的操作即可
匹配成功
abab 的公共最长前后缀就是 aba 公共最长前后缀 +1有没有发现 aba 的公共最长前后缀是前缀也就是 j+1
aba 是 j 指向 a,值就是 0 ,所以需要 +1之后才能赋值给 next
但在 abab中 j 指向 aba 中的 b,值就是1,也需要 +1之后才能赋值给 next
所以可以先 +1 在赋值给next
匹配成功
ababa 的公共最长前后缀就是 abab 公共最长前后缀 +1
匹配失败
ababaf 的公共最长前后缀为 0
j 有需要归零
匹配失败
ababafg 的公共最长前后缀为 0
j 归零
匹配失败
ababafgd 的公共最长前后缀为 0
j 归零
匹配成功
ababafgda 的公共最长前后缀为 j+1=0
但是并不需要公共最长前后缀了,已经匹配结束了
公共最长前后缀 是为失败后下一次跳过公共的内容做准备的
前提是失败后
同理解释为什么要设
j = 0:
k = 1
一个字符的公共最长前后缀就是 1,但是一个字符失败后肯定只跳过一个字符呀,所以公共最长前后缀就无意义了
根据所讲内容应该能写出以下代码
j = 0
k = 1
// k 表示循环进度
while(k < len-1) {
// 这就是图中的两个字符的比对
if(str[j] == str[k]) {
++i;
// k 表示循环进度,也表示当前在那个子串的子串
next[k] = j;
}else{
j = 0 // j 归零
}
++j; // 无论如何都会 +1
}
但是这个并不好,不好体验在next数组的值
目前next 的值为
str: a b a b a f g d a
next: 0 0 1 2 3 0 0 0 0
设在 ababcd 中搜索 ababa
ababcd
ababa
ababcd
ababa
a 和 c 不匹配,所以要跳过什么?
跳过 ababa 的最长前后缀?看就能看出问题来,明显不是,而是跳过 ababa 中的 abab 的最长前后缀
那么如何获得 abab 的最长前后缀,是next[j-1]
设 j 是当前的位置
必须修改代码才能在使用的时候不用 -1
void mGetNext(char* str,int next[]) {
int i = 0;
int j = 1;
int len = strlen(str);
next[0] = -1;
next[1] = 0; // 因为 j+1
while(j < len-1) {
if(str[i] == str[j]) {
++i;
next[j+1] = i;
}else{
i = 0;
}
++j;
}
}
现在这代码和下面的代码是一样的效果
你应该看到过以下代码,
void GetNext(char* p,int next[])
{
int pLen = strlen(p);
next[0] = -1; // 利用 -1
int k = -1;
int j = 0;
while (j < pLen - 1)
{
//p[k]表示前缀,p[j]表示后缀
if (k == -1 || p[j] == p[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k];
}
}
}
该代码我是真的写不出来,
是我太菜了。?
关于 next[0] = -1 的想法,在我遇到的代码中充分利用了 -1 这个值(getnext和kmp函数都利用了)
由于本人太菜,不能写出那样的代码,所以还是将设为0吧
for(int i=0; i < rstr_len; ++i) {
if(sstr_index == sstr_len) {
// 找到了
sstr_index = 0;
}
if(rstr[i] == sstr[sstr_index]) {
++sstr_index;
}else {
// next 可能会返回 next[0] 的值,如果是-1那么就麻烦了,或者预防一下
// 但是,也可以将 next[0] 的值设为 0
sstr_index = next[sstr_index];
}
}
如有错误请指出?
markdown 用的好烂!!!