在了解如何手算next数组后,我们接下来用代码来解析next数组的求解过程:
首先给出代码:
void get_next(SString T, int* next)
{
int i = 1;
int j = 0;
next[1] = 0;
while (i < T[0])//T[0]里保存的是子串长度
{
if (j == 0 || T[i] == T[j])
{
++i; ++j;
next[i] = j;
}
else
{
j = next[j];
}
}
}
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
T | a | b | a | a | b | c | a | c |
next | 0 |
当i=1时进入循环,满足j=0, i=2,j=1,next[2]=1
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
T | a | b | a | a | b | c | a | c |
next | 0 | 1 |
接着循环,此时不满足if条件语句,则进入else,j=next[1]=0,继续循环,满足j=0,
i=3,j=1,next[3]=1
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
T | a | b | a | a | b | c | a | c |
next | 0 | 1 | 1 |
进入循环,此时满足if条件,T[1]==T[3]='a',i=2,j=4,next[4]=2
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
T | a | b | a | a | b | c | a | c |
next | 0 | 1 | 1 | 2 |
进入循环,不满足if,则j=next[j]=next[4]=2,再次进入循环,不满足if,j=next[j]=next[2]=1,在此进入循环,T[4]==T[1]='a',i=5,j=2,next[5]=2.
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
T | a | b | a | a | b | c | a | c |
next | 0 | 1 | 1 | 2 | 2 |
后续方法都与上相同,读者可以自己判断,最终的结果:
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
T | a | b | a | a | b | c | a | c |
next | 0 | 1 | 1 | 2 | 2 | 3 | 1 | 2 |
在了解普通next数组求解后,接下来给出改进后的next_val代码:
void get_next(SString T, int* next)
{
int i = 1;
int j = 0;
next[1] = 0;
while (i < T[0])//T[0]里保存的是子串长度
{
if (j == 0 || T[i] == T[j])
{
++i; ++j;
if (T[i] != T[j])
next[i] = j;
else
next[i] = next[j];
}
else
j = next[j];
}
}
相比之下,两个代码并没有多大区别,仅仅多了一个判断和赋值,
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
T | a | b | a | a | b | c | a | c |
next | 0 | 1 | 1 | 2 | 2 | 3 | 1 | 2 |
next_val | 0 | 1 | 0 | 2 | 1 | 3 | 0 | 2 |
根据代码,写出next_val,求解nextval数组是基于next数组的,模式串每一个字符和next数组值给出的下标的对应位置的数作比较,相等就取对应的next数组值作为当前位置字符的next-val值,不等就直接取当前位置字符的next数组的值作为next-val的值。
next-val数组第一个数直接为0,求解第二个b的next_val数组,看他的next为1,则把1作为下标,T[1]为‘a'!='b',则b的next-val值就直接取当前位置字符的next数组的值作为next-val的值,为1.
求解第三个a的next_val数组,看他的next为1,则把1作为下标,T[1]为‘a'='a',则相等就取对应的next数组值作为当前位置字符的next-val值,及第一个的next值为0.
后续求解都与上面方法相同,读者可以自己根据情况理解。