我一直在尝试了解 Boyer-Moore字符串搜索算法中的转换规则,但还没有理解它们。我在这里阅读wikipedia,但这太复杂了!
如果有人以简单的方式列出规则,那将会很有帮助。
答案 0 :(得分:16)
在Boyer-Moore算法中,您开始将模式字符与模式末尾的文本字符进行比较。如果发现不匹配,则配置类型为
....xyzabc.... <-text
....uabc <- pattern
^
mismatch
现在坏字符移位意味着移动模式,使不匹配的文本字符与模式的初始部分中该字符的最后一次出现对齐(模式减去最后一个模式字符),如果存在这样的事件,或者如果不匹配的字符没有出现在模式的初始部分中,则在模式之前的一个位置。
如果情况是
,那可能是左移 v
...xyzazc...
....uazc
..uazc
所以单凭这并不能保证进步。
另一个转移,良好的后缀转换,将文本的匹配部分m
与前面不同的模式中该字符序列的最右边出现对齐。字符(包括无,如果匹配的后缀也是模式的前缀),而不是模式的匹配后缀m
- 如果出现这种情况。
所以例如
v
....abcdabceabcfabc...
...xabcfabcfabc
...xabcfabcfabc
将导致四个位置的良好后缀移位,因为匹配的部分m = abcfabc
出现在其后缀出现的左侧四个位置的模式中,并且之前有一个不同的字符(x
而不是f
)比后缀位置。
如果模式中匹配部分没有完全出现,前缀为与后缀不同的字符,则良好的后缀移位将文本的匹配部分的后缀与模式的前缀对齐,选择最大重叠,例如
v
...robocab....
abacab
abacab
良好的后缀转换总是将模式向右移动,因此可以保证进度。
然后,在每次不匹配时,比较坏字符移位和良好后缀移位的进展,并选择越大。 Christian Charras和Thierry Lecroq here更详细地解释了这一点,以及许多其他字符串搜索算法。
对于您在评论中提到的示例,
SSIMPLE EXAMPLE
EXAMPLE
^
匹配的后缀为MPLE
,不匹配的文字字符为I
。因此,错误的字符移位会在模式的初始部分中查找I
的最后一次出现。没有,所以不良的角色转换会改变模式,以便在模式开始之前不匹配的I
是一个
SSIMPLE EXAMPLE
EXAMPLE
并且良好的后缀转换会查找模式中<{1}}最右边的MPLE
,而<{1}}前面的A
或MPLE
的最长后缀是模式的前缀。在后缀之前的模式中没有完全出现匹配的部分,因此匹配部分的最长后缀(也是模式的前缀)决定了良好的后缀移位。在这种情况下,作为模式前缀的匹配部分的两个后缀是单字符串E
和空字符串。最长的显然是非空字符串,因此良好的后缀移位将文本匹配部分中的单字符后缀E
与模式的单字符前缀对齐
SSIMPLE EXAMPLE
EXAMPLE
良好的后缀移动将模式向右移动,因此这是所选择的移位。
然后在最后一个模式位置立即出现不匹配,然后错误的字符移位将文本中的P
与模式中的P
对齐(并且良好的后缀移位不必是如果在最后一个模式字符处发生不匹配,则完全考虑,因为在这种情况下,它永远不会产生比不良字符移位更大的移位。)
然后我们完全匹配。
在具有模式TXAMPLE
的变体中,良好的后缀移位发现匹配部分的非空后缀不是模式的前缀(并且模式中没有出现完整的匹配部分) not 前面有A
),因此良好的后缀移位将文本匹配部分的空后缀(E
和空格之间的边界)与空对齐模式的前缀(T
之前的空字符串),导致
SSIMPLE EXAMPLE
TXAMPLE
(然后在下一步中,错误的字符移位会使两个L
对齐,此后步骤中的下一个不匹配发生在模式的初始T
处。
答案 1 :(得分:7)
有一个很好的可视化here.
(编辑:这两个例子以及如何实施预处理步骤here的例子也有很好的解释。)
一般规则:
我刚刚描述的是“坏人物”规则。 “良好后缀”规则提供了另一种转移选择;你应该采取的更远的转移。完全有可能在没有良好后缀规则的情况下实现算法,但是一旦构建了索引,效率就会降低。
良好后缀规则要求您还知道在何处查找模式的每个多字符子字符串。当您遇到不匹配(一如既往地从右到左检查)时,良好后缀移动将模式移动到已经已经匹配的字母将再次执行此操作的点。或者,如果匹配的部分在模式中是唯一的,您知道可以跳过它的所有方式,因为如果它与单独的事件对齐时不匹配,则在排列任何一个时都不可能匹配模式的其他部分。
例如,让我们考虑以下情况:
我有两个选择:
我应该拿任何一个让我转移得更远。
如果您仍然感到困惑,请尝试提出更具体的问题;当我们不知道你被困在哪里时,很难说清楚。
答案 2 :(得分:1)
有两种启发式方法:蝙蝠符号启发式和良好模式启发式。
首先,你知道,针头比较从它的结束开始。 因此,如果字符不匹配针移位,那么至少比较干草堆中的字符会匹配针。 E. g。针是“ABRACADABRA”,干草堆中的当前字符是“B”,它与最后的“A”不匹配,也与先前的“R”不匹配,所以一个一个是无意义的,没有匹配。但是“B”在针的最后一个字符中匹配2。所以我们至少要换针2个位置。如果haystack中的当前字符与针中的任何字符都不匹配,则必须将针移动到当前字符之外。换句话说,我们移动模式直到大海捞针中的当前角色与针中的角色匹配,或者整个针移动超出。
计算移位量并存储在数组中,因此对于“ABRACADABRA”,它将是:['R'] = 1,['B'] = 2,['D'] = 4等等。
haystack: XYABRACADABRA...
|
needle: ABRACADABRA
ABRACADABRA <-- pointless shift: R will not match B
ABRACADABRA
其次,如果在干草堆中发现至少匹配“ABRA”(但没有完全匹配),则可以移动针,以便下一个“ABRA”匹配。
匹配部分的移位量也是预先计算的:e。 G。 ['A'] = 3,['RA'] = 11,['BRA'] = 11,['ABRA'] = 7,['DABRA'] = 7 ......
haystack: XYZYXADABRACADABRA...
needle: ABRACADABRA (shift to ABRA from matched ADABRA)
~~~~ ~~~~
ABRACADABRA
这不是所有角落案例的完整解释,而是算法的主要思想。