字符串中的快速模式匹配1
1、非正式推演:
如果我们想象着以某种方法把模式从文本的左边滑动至文本的最右面,那么本文讲的模式匹配方法可能就会很容易掌握了。举个例子,在文本babcbabcabcaabcabcabcacabc中搜索模式abcabcacab;刚开始,我们把模式放在输入文本的最左边并且准备扫描最左边的字符:
这里的箭头指向当前文本字符;因为它指向b,与模式中的a不匹配,我们将模式右移一位并将指针移向下一个输入字符:
现在,我们匹配成功了一个了,于是模式保持位置不动,继续读进接下来的文本字符,然后我们就找到了一个不匹配的:
这里我们匹配成功了模式的前三个字符,但是第四个匹配失败了,所以我们就知道了输入文本中的连续四个字符格式为abcx(x!=a),我们就不需要记住之前浏览过的字符,因为模式中的位置可以有足够的信息来重建他们。在这个例子中,无论x是什么只要它不是a那么我们就可以推断模式可以立即右移四位;一位、两位、三位都不会产生匹配的。
很快我们就找到了另一个部分匹配,这次是在模式的第8个字符匹配失败:
那么我们就知道了接下来的八个字符为abcabcax(x!=c)。这个模式应该右移三位:
我们本想找一个新的匹配字符,但是又失败了,因此我们需要再将模式右移四位。这就会产生一个匹配,继续扫描直至出现另一个与模式的第八个字符不匹配:
再一次将模式右移三位,这一次一个模式的完整匹配找到了:
通过这个例子的一步步演示表明模式匹配算法会很高效只要我们有一个记录当匹配不成功的时候需要滑动模式多远的辅助表,表pattern[j]用来记录模式中的字符,表next[j]用来记录一次不匹配之后应该检查的下一个字符位置,这样我们就可以将模式滑动j-next[j]个位置。下面一个表是列举了对应的数值:
(其中next[j]=0表示我们将把模式移过当前位置)稍后我们会讨论如何提前计算这个辅助表;幸运的是这个表的计算方法非常简单,而且它只需要O(m)步。
在扫描过程中的每一步中,我们要么移动文本指针要么移动模式,而且它们都最多可以移动n次;所以在next表被设置后最多只需要执行2n步。当然,模式本身不会真正移动,我们通过简单的保存指针变量j来实现这个必要的操作。