Boyer-Moore 算法

2025年3月17日 | 阅读 3 分钟

Robert Boyer 和 J Strother Moore 于 1977 年提出。B-M 字符串搜索算法是一种特别有效的算法,自那时以来一直作为字符串搜索算法的标准基准。

B-M 算法采用“向后”方法:模式字符串 (P) 与文本字符串 (T) 的开头对齐,然后从右到左比较模式的字符,从最右边的字符开始。

如果比较的字符不在模式中,则通过分析此位置的任何其他方面都找不到匹配项,因此可以将模式完全更改为超出不匹配的字符。

为了确定可能的偏移量,B-M 算法同时使用两种预处理策略。每当发生不匹配时,该算法都会使用这两种方法计算一个变体,并选择更显着的偏移量,因此,如果对每种情况都使用最有效的策略。

这两个策略被称为 B-M 的启发式方法,因为它们用于减少搜索。它们是

  1. 坏字符启发式方法
  2. 好后缀启发式方法

1. 坏字符启发式方法

此启发式方法有两个含义

  • 假设文本中有一个字符根本没有出现在模式中。当在这种字符(称为坏字符)处发生不匹配时,整个模式可以更改,开始匹配这个“坏字符”旁边的子字符串。
  • 另一方面,可能模式中存在一个坏字符,在这种情况下,将模式的性质与文本中的坏字符对齐。

因此,在任何情况下,偏移量都可能大于 1。

示例 1:设文本 T = <nyoo nyoo>,模式 P = <noyo>

The Boyer-Moore Algorithm

示例 2:如果模式中不存在坏字符,则。

The Boyer-Moore Algorithm

坏字符启发式方法中的问题

在某些情况下,坏字符启发式方法会产生一些负偏移。

例如

The Boyer-Moore Algorithm

这意味着我们需要一些额外的信息来在遇到坏字符时产生偏移。此信息是模式中每个方面的最后一个位置,以及模式中使用的字符集(通常称为模式的字母表 ∑)。

COMPUTE-LAST-OCCURRENCE-FUNCTION (P, m, ∑ )
 1. for each character a ∈ ∑
 2. do λ [a] = 0
 3. for j ← 1 to m
 4. do λ [P [j]] ← j
 5. Return λ

2. 好后缀启发式方法

一个好后缀是一个成功匹配的后缀。在坏字符启发式方法中出现不匹配后,查看模式的一个子字符串是否与坏字符匹配,如果在其中有一个好后缀,那么我们有一个等于找到的后缀长度的向前跳跃。

示例

The Boyer-Moore Algorithm
COMPUTE-GOOD-SUFFIX-FUNCTION (P, m)
 1. Π ← COMPUTE-PREFIX-FUNCTION (P)
 2. P'← reverse (P)
 3. Π'← COMPUTE-PREFIX-FUNCTION (P')
 4. for j ← 0 to m
 5. do ɣ [j] ← m - Π [m]
 6. for l ← 1 to m
 7. do j ← m - Π' [L]
 8. If ɣ [j] > l - Π' [L]
 9. then ɣ [j] ← 1 - Π'[L]
 10. Return ɣ
 
BOYER-MOORE-MATCHER (T, P, ∑)
 1. n ←length [T]
 2. m ←length [P]
 3. λ← COMPUTE-LAST-OCCURRENCE-FUNCTION (P, m, ∑ )
 4. ɣ← COMPUTE-GOOD-SUFFIX-FUNCTION (P, m)
 5. s ←0
 6. While s ≤ n - m
 7. do j ← m
 8. While j > 0 and P [j] = T [s + j]
 9. do j ←j-1
 10. If j = 0
 11. then print "Pattern occurs at shift" s
 12. s ← s + ɣ[0]
 13. else s ← s + max (ɣ [j], j -  λ[T[s+j]])

字符串匹配算法的复杂度比较

算法预处理时间匹配时间
朴素O(O (n - m + 1)m)
Rabin-KarpO(m)(O (n - m + 1)m)
有限自动机O(m|∑|)O (n)
Knuth-Morris-PrattO(m)O (n)
Boyer-MooreO(|∑|)(O ((n - m + 1) + |∑|))
下一主题Kosaraju 算法