Boyer-Moore算法
Boyer-Moore算法是由德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授与1977年发明的。 算法的主要思想包括以下两点:
坏字符规则 bad character
好后缀规则 good suffix
下面采用一个例子进行解释:
- 1
1
2"字符串" HERE IS A SIMPLE EXAMPLE
"模式串" EXAMPLE 2
可以发现头部对齐时, 从尾部开始比较,发现尾部的字符不匹配,那么只要比较一次,就知道字符串的前七个字符不是我们要找的。1
2HERE I`S` A SIMPLE EXAMPLE
EXAMPL`E`S
和E
不匹配,此时,S
就被成为坏字符(bad character)。同时我们发现,S
不在模式串EXAMPLE
中,因此可以直接将模式串移动到S
的后一位。 只需比较一次就可以跳7个字符,也是该算法加速的原因之一。- 3 依然从尾部开始比较,发现
1
2"字符串" HERE IS A SIM`P`LE EXAMPLE
"模式串" EXAMPL`E`P
与E
不匹配,所以P
是坏字符。但是,P
包含在搜索词EXAMPLE
之中。所以,将搜索词后移两位,两个P
对齐。 4
因此,我们可以总结出坏字符规则1
2HERE IS A SIM`P`LE EXAMPLE
EXAM`P`LE如果坏字符在模式串中不出现,则上一次的位置为1
后移动的位数 = 坏字符在模式串中的位置 - 模式串中的坏字符上一次出现的位置
-1
, 取值-1
是因为字符串索引是0-based
。
以3
中的匹配为例,P是坏字符,出现在模式串的第6位(0-based), 由于模式串中存在该坏字符,且出现的位置为4, 所以,后移动的位数为6-4 = 2位
。
再以2
中出现的S为例,该坏字符出现的位置是6
位置,但是在模式串中上一次没有出现,因此,上一次出现的位置为-1
, 则整个模式串后移的位数6 - (-1) = 7位
。
- 5
1 | HERE IS A SIMPL`E` EXAMPLE |
依然从尾部开始比较,E
与E
匹配
- 6
1 | HERE IS A SIMP`L`E EXAMPLE |
LE
与LE
匹配
7
1
2
3HERE IS A SIM`PLE` EXAMPLE
EXAM`PLE`PLE
与PLE
匹配8
1
2
3HERE IS A SI`MPLE` EXAMPLE
EXA`MPLE`MPLE
与MPLE
匹配. 我们把E
,LE
,PLE
,MPLE
中出现的字符称为好后缀(good suffix)。9
比较前一位,发现1
2
3HERE IS A S`I`MPLE EXAMPLE
EX`A`MPLEI
和A
不匹配,所以I
是坏字符。10
根据坏字符规则,后移的位数1
2
3HERE IS A SI`M`PLE EXAMPLE
`E`XAMPLE2-(-1) = 3位
i,M
与E
对齐,但是此时,会有一个疑问,有没有更好的移法呢?比3
更多呢?11
1 | HERE IS A SI`MPLE` EXAMPLE |
此时,存在好后缀MPLE
,采用好后缀规则。
1 | 后移的位数 = 好后缀的位置 - 模式串中好后缀上一次出现的位置 |
好后缀规则的注意点:
12
此时的好后缀有1
2HERE IS A SIMPLE EXAMPLE
EXAMPLEE
,LE
,PLE
,MPLE
,在四个中间只有E
出现,在模式串EXAMPLE
中,且出现在头部, 所以后移的位数6 - 0 = 6位
, 可以看到使用好后缀规则移动的更多,比坏字符多出3位。因此Boyer-Moore算法的 思想就是每次后移选取两个规则中移动位数最多的。由于,两个规则只和模式串有关,与原字符串无关,因此可以预先制定 坏字符规则表和好后缀规则表,使用时,查表即可。13
继续从尾部比较,1
2HERE IS A SIMPLE EXAM`P`LE
EXAMPL`E`P
与E
不匹配,因此P
是坏字符,根据坏字符规则,后移的位数6 - 4 = 2位
, 此时没有好后缀。14
继续从尾部开始比较,发现完全匹配上了,搜索结束。若还要继续匹配,则使用好后缀规则,使用的是好后缀1
2
3HERE IS A SIMPLE EXAMPLE
EXAMPLEE
, 后移6 - 0 = 6位
,继续匹配。
Python 实现
1 | def bad_character(): |