Bootstrap

KMP算法和KMP算法的优化

1.KMP算法

KMP算法的匹配过程,可以分为两个个步骤:求next数组、根据next数组进行匹配。

现在给出一个主串T:abaabaabcabaabc,指向主串的指针 i;给出一个模式串S:abaabc,指向模式串的指针 j

步骤如下

1.1求next数组

next数组的第一项next[0] = -1(如果 j 以1为起始编号,那么next[0] = 0)。

j012345
模式串abaabc
next[j]-1

除next数组第一项外,next[j] = 第1个字符到第 个字符(不包括第 个字符)的前后缀最长匹配长度(当 j 的起始值为1时,next数组的值也要相应+1)。

前缀:除最后一个字符外,前任意个数的连续字符都是前缀。

后缀:除第一个字符外,后任意个数的连续字符都是后缀。

匹配:两个字符串相等,长度相等,每个对应的字符也相等,也就是strcmp(str1,str2)= 0。

对于模式串S:abaabc来说,它的所有前缀是:a、ab、aba、abaa、abaab;它的所有后缀是:c、bc、abc、aabc、baabc。

当 取1时,串为a:

        没有前缀和后缀,因此最长匹配长度为0,next[j] 取 0

当 取2时,串为ab:

        前缀取a,后缀取b,不匹配

        因此最长匹配长度为0,next[j] 取 0

当 取3时,串为aba:

        前缀取a,后缀取a,匹配,长度为1

        前缀取ab,后缀取ba,不匹配

        因此最长匹配长度为1,next[j] 取 1

当 取4时,串为abaa:

        前缀取a,后缀取a,匹配,长度为1

        前缀取ab,后缀取aa,不匹配

        前缀取aba,后缀取baa,不匹配

        因此最长匹配长度为1,next[j] 取 1

当 取5时,串为abaab:

        前缀取a,后缀取b,不匹配

        前缀取ab,后缀取ab,匹配,长度为2

        前缀取aba,后缀取aab,不匹配

        前缀取abaa,后缀取baab,不匹配

        因此最长匹配长度为2,next[j] 取 2

更新next数组

j012345
模式串abaabc
next[j]-100112

1.2进行匹配

(1)设定主串的指针 i 和模式串的指针 j 的起始值,这里为0。

(2)对 T[i] 和 S[j] 进行比较。

(3)如果匹配成功,如果 j 已经取得最大值,说明匹配成功;否则 i++,j++,回到(2)。

(4)如果匹配失败,如果 i 已经取得最大值,说明匹配失败;否则 j = next[j],i不变,回到(2)

2.KMP算法的优化

上面定义的next数组尚有缺陷,可以进一步优化。

假设主串T:aaabaaaab;模式串S:aaaab。

主串aaabaaaab

模式串

aaaab
j01234
next[j]-10123

当 j = 3 时,匹配失败,根据next数组的值,应该令 j 取 2,于是下一次的匹配是S[2] = a 和 T[3] = b进行匹配且失败;再下一次是S[1],然后是S[0]。可以看到S[0]、S[1]、S[2]、S[3]是相等的,当S[3]匹配失败时,跳转的S[2]、S[1]、S[0]一定会发生失败,这些匹配都是无意义的。

当next指向的字符和当前字符相等,那么下一次的匹配必定是失败的,可以直接跳过,所以应该直接跳转到next的next。于是可以根据next数组,更新出新的跳转数组,命名为nextval。

2.1求nextval数组

以第一节的主串T:abaabaabcabaabc 和模式串:abaabc 进行分析

nextval数组的第一项nextval[0] = -1(如果 j 以1为起始编号,那么nextval[0] = 0)。

j012345
模式串abaabc
next[j]-100112
nextval[j]-1

除nextval数组的第一项外,nextval[j] 的取值有两种情况:当S[j]和其对应的next位置的字符相等(即S[j] 和 S[next[j]]相等时),nextval[j]的值取相比较的字符对应的nextval(即nextval[j] 取 nextval[next[j]]);如果不相等,则直接取对应next数组的值

j 取 1 时

        S[1] = b,S[next[1]] = S[0] = a,不相等,所以nextval[1] = next[1] = 0。

j 取 2 时

        S[2] = a,S[next[2]] = S[0] = a,相等,所以nextval[2] = nextval[next[2]] = nextval[0] = -1。

j 取 3 时

        S[3] = b,S[next[3]] = S[1] = b,不相等,所以nextval[3] = next[3] = 1。

j 取 4 时

        S[4] = b,S[next[4]] = S[1] = b,相等,所以nextval[1] = nextval[next[4]] = next[1] = 0。

j 取 5 时

        S[5] = c,S[next[5]] = S[2] = a,不相等,所以nextval[5] = next[5] = 2。

更新nextval数组

j012345
模式串abaabc
next[j]-100112
nextval[j]-10-1102

2.2进行匹配

这里的匹配方法和1.2是相同的,无非是将其中的next数组,替换为nextval数组

;