KMP算法
KMP算法是D.E.Knuth与V.R.Pratt和J.H.Morris同时发现的,每一趟匹配过程中出现字符比较不等时候,不需要回溯i指针,而是利用已经得到的“部分匹配的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
我们先来看几个例子
第一个例子
主串S为:" ACABAABAABCACAABC"
子串T为:" ABAABCAC"
第一次比较:将子串T放在第一位与主串比较,发现子串第二位与主串第二位不等。第二次比较:将子串放T放在上一次不相等的位置,再次进行比较,发现子串第一位就与主串不相等。子串向后移动一位再次进行比较。第三次比较:这次是子串的第六位与主串第八位不相等,这时并没有把子串移置到不相等的位置上。仔细观察,如果子串移置主串第8位上
那么这时字符串匹配效果是失败的,字符串找不到与之相对应的主串字符,出现了漏查的情况。所以说子串第一个字符 回溯的位置另有蹊跷 。
匹配次数 | 子串起始位置 | 失败位置 |
---|---|---|
第一次 | 1 | 2 |
第二次 | 2 | 2 |
第三次 | 3 | 8 |
第四次 | 6 | - |
第二个例子
主串为:" ABCABDABCEABDBCBD"
子串为:" ABCEABBD"
匹配次数 | 子串起始位置 | 失败位置 |
---|---|---|
第一次 | 1 | 4 |
第二次 | 4 | 6 |
第三次 | 6 | 6 |
第四次 | 7 | 13 |
第五次 | 11 | 13 |
第六次 | 13 | 13 |
第O^O次 | … | … |
那么子串 回溯的位置另有蹊跷 ,究竟是什么呢。
这里另有蹊跷的意思是,子串需要观察自身结构,若自身有重复的结构,需要回溯到重复位置的后者不然会造成字符串匹配缺失的情况。这里科学家们引入了模式串next。
引入模式串next
模式串是对于子串而言,专门计算子串的前缀后缀重复字符个数
结合next[j]再来看例一
匹配次数 | 子串起始位置 | 子串失败位置 | 失败位置 | next[j] |
---|---|---|---|---|
第一次 | 1 | 2 | 2 | 1 |
第二次 | 2 | 1 | 2 | 0 |
第三次 | 3 | 6 | 8 | 3 |
第四次 | 6 | - | - | - |
现在是否发现了回溯位置与next[j]值的关系了呢?
next[j]代码实现
void get_next(SString T, int next[])
{
//求模式串T的next函数值并存入数组next。
int i = 1;
next[1] = 0;
int j = 0;
while (i < T.length)
{
if (j == 0 || T.ch[i] == T.ch[j])
{
++i; ++j;
next[i] = j;
}
else
j = next[j]