突破该死的无回溯模式匹配算法
关键字:无回溯模式匹配
本文是我研究张乃孝的《算法与数据结构-C语言描述(第二版)》中第三章“字符串”的无回溯模式匹配算法(P77)时的一些心得。这个算法只有简单的几行,却让我看了差不多两个晚上才看懂。为了让后来人不至于跟我一样花同样或甚至更多的时间在理解它上面(当然肯定还有不少比我厉害的牛人,你们就不用看了^_^)。特写下此心得。请在阅读以前,先让自己的心静下来,先要看懂算法的思想,不要拘泥于细节,然后根据思想并结合例子彻底搞懂。张乃孝先生本章的“小结”最后一段中说:“认真理解无回溯的模式匹配算法需要费一定的时间。不过一旦真正弄懂了这个算法,将会极大地增强你的学习兴趣。”所以请千万不要急功近利。当然,也可以根据你的实际情况,跳过有关段落。我尽量用最浅显易懂地方式为大家解说(大家会发现大部分内容来自书上,但经过我的精心整理^_^),大家可以结合书本来看,也可以完全抛开书本来看。
一、对朴素模式匹配的简单回顾
为了说明思想,只考虑极为简单的一般情况:
假设主串为:t=t(1) t(2) … t(m-1) … t(n-1),模式为:p=p(0) p(1) … p(m-1),这里的x(i)表示下标为i的字符(后同)。第一次匹配(图1):
j=m-1
t(0) t(1) … t(m-1) … t(n-1)
| | |
p(0) p(1) … p(m-1)
i=m-1
图1
这里的“|”表示比较上下对应的字符,j、i分别为控制变量即指向当前比较的字符(后同)。假设匹配失败,则j回到1,i回到0,开始下一次匹配(图2):
j=m
t(0) t(1) t(2) … t(m-1) t(m) … t(n-1)
| | | |
p(0) p(1) … p(m-2) p(m-1)
i=m-1
图2
如果仍然匹配失败,则继续下去,直到匹配成功或找不到这样的子串为止。可以看出,朴素模式匹配过程当中,如果匹配不成功需要进行下一次匹配,则必须回溯控制变量。
二、无回溯模式匹配
(一)、next数组的意义
搞懂next数组的意义是至关重要的第一点,这里我只解释next数组的意义,其他的请你先放一边,“分治法”不是我们常用的分析方法吗:)
在p与任意的t匹配时,若发现p(i)!=t(j),则意味着p(0),p(1),…,p(i-1)已与t中对应的字符进行过比较,而且是相等的,如图3所示:
j
t(0) … t(j-i+1) t(j-i) … t(j-1) t(j) … t(n-1)
= = !=
p(0) … p(i-1) p(i)