数据结构(邓俊辉)学习笔记】串 14——BM_GS算法:构造gs表
以下,就来简要地介绍 gs 表的具体构造算法。算法为了便于理解其原理,这里将整个算法划分为若干的层次,并逐层递进、逐层细化。
我们首先需要引入 MS 子串与 ss 表的概念。实际上,相对于模式串中的任何一个字符 P[j] ,所谓的 MS[j] ,就是某个以 P[j] 为末字符的子串。而且这个子串也同样会出现于整个模式串的尾部。
当然,如果同时存在多个这样的候选,我们会在其中选择最长的那个。概括而言,所谓的 MS[j] 就是终止于 P[j] ,同时与全串的后缀实现最长匹配的子串。当然,这个子串也有可能是空。我们来看这样一个实例:
对于P[8],也就是字符 E 而言,它所对应的 MS 子串,自右向左由 E、C、I、R 这四个字符组成,因为这个子串与整个模式串的后缀实现了最长的匹配。
相应的,在 ss 表中,j 所对应的那一项,其实也就是 MS[j] 子串的长度。
在刚才这个例子中,8号字符 E 所对应的 ss 表项,也自然就应该是子串 RICE 的长度,4。
~
同理,对于字符 P[2] 而言,它所对应地MS 子串为ICE 。相应地ss表项,也就是这个串的长度,3。
实际上,在中转的这个 ss 表中,已经蕴含了我们最终要计算的 gs 表的所有信息。因此,快速构造 gs 表的问题,也就自然地转化为了如何快速地构造 ss 表。
那么,通过 ss 表,具体的如何构造出最终的 gs 表呢?无非两种情况:
- 首先, ss[j] 可能达到最大的极限,也就是 j +1。此时情况如这个图所示(上图中上面那个图),也就说 MS[j] 子串足够长,以至于它就是整个模式串的一个前缀。于是对于这个范围内的任何一个字符P[i], 一旦在扫描比对中发生失配,m-j-1 也必然是一个值得考虑的位移距离。
- 此外,都是一般的情况。也就是 MS[j] 子串的长度,充其量不过 j 。此时的情况可以由下面这幅图来示意。可以看到此时的 MS[j] 子串长度还没有达到极限。于是如果将来在扫描比对的过程中,在这个位置处(m - ss[j] - 1)发生首次适配,接下来一种值得考虑的位移距离自然也是 m-j-1。
通过以上的分析可以看到,构造 gs 表,关键就在于如何构造出 ss 表。当然,根据以上定义,即便采用蛮力策略也是可以构造出这个表的。
然而很遗憾,我们为此需要平方量级的时间。那么这个结果能否改进呢?当然是肯定的,采用新的算法,我们只需线性的时间就足以构造出 gs 表。