Java Boyer Moore

2025 年 5 月 12 日 | 阅读 9 分钟

Boyer-Moore 算法 是由 **Robert S. Boyer** 和 **J Strother Moore** 于 1977 年开发的字符串搜索或匹配算法。它是一种广泛使用且最高效的字符串匹配算法。它比暴力算法快得多。在本节中,我们将讨论 **Boyer-Moore 算法、特性** 及其 **在 Java 程序中的实现**。它的运行时间复杂度为 **O(nm+s)**。最坏情况是

T=ssssssss……………ssssssss

P=psssssssss

上述序列可能出现在图像和 DNA 序列中。

Boyer Moore 算法的特性

  • 它从右到左逐个字符进行比较;
  • 预处理阶段的时间和空间复杂度为 **O(m+)**。
  • 搜索阶段的复杂度为 **O(mn)**。
  • 在最坏情况下(搜索非周期性模式时),它会进行 3n 次文本字符比较。
  • 其最佳性能复杂度为 **O(n / m)**。

该算法基于以下两种启发式方法

  • 照后镜启发式
  • 字符跳跃启发式

让我们了解 Boyer-Moore 算法的工作原理。

Boyer-Moore 算法的工作原理

该算法从给定模式的最右边字符开始跟踪字符,然后向左移动。在发生任何不匹配和完全匹配模式的情况下,它使用两个预先计算的函数,分别向右和向左移动字符。这两个预先计算的移位函数称为**好后缀移位**(或**匹配移位**)和**坏字符移位**(或出现移位)。

注意:为了匹配模式,请按从左到右的顺序对齐字符,并按从右到左的顺序比较字符。

坏字符移位

发生不匹配时,跳过对齐,直到满足以下条件之一

  1. 不匹配变成匹配
  2. P 越过不匹配字符

例如,考虑下面给出的文本 (T) 和模式 (P)。

Boyer Moore Java

让我们开始匹配模式。

步骤 1:按从左到右的顺序对齐字符,并按从右到左的顺序比较字符。

我们看到 P 的最后三个字符与 T 中的字符匹配。第四个字符 (T) 不匹配。根据上面讨论的规则,跳过对齐,直到不匹配变成匹配。由于 P 中的第七个字符 (C) 与 T 中的 C 匹配。

Boyer Moore Java

步骤 2:向右跳过三个字符以匹配模式。

移动后,再次从右到左比较字符。第一个字符匹配。我们观察到字符 A 不出现在 P 的左侧。在这种情况下,P 移动到 T 中不匹配的字符 (A) 之后。

Boyer Moore Java

步骤 3:将 P 移过不匹配字符,我们得到

Boyer Moore Java

模式已匹配。

注意:坏字符移位可能为负值。由于 Boyer-Moore 算法在移位字符时会应用好后缀移位和坏字符移位之间的最大值(跳过的字符数)。

好后缀移位

设 t 是内循环匹配的子串,然后跳过字符直到

  1. P 和 t 之间没有不匹配。
  2. P 越过 t。

例如,考虑以下模式。

Boyer Moore Java

步骤 1:从右到左比较字符。我们看到 P 的最后三个字符与 T 中用 **t** 标记的字符匹配。

Boyer Moore Java

步骤 2:跳过字符,直到 P 和 t 之间没有匹配。我们观察到 P 的前四个字符(从左到右)(C T T A C)与 t 的最后五个字符匹配。

Boyer Moore Java

步骤 3:跳过三次对齐以获得匹配。因此,我们得到匹配。

Boyer Moore Java

上述两个移位函数可以定义如下

好后缀移位函数存储在一个名为 **bmGs** 的表中,大小为 **m+1**。表 **bmGs** 的计算使用一个名为 **suff** 的表,定义如下

坏字符移位函数存储在一个大小为 σ 的表 **bmBc** 中。对于 ∑ 中的 c

Boyer Moore 模式匹配示例

考虑以下模式。

Boyer Moore Java

让我们开始匹配。

步骤 1:从右到左比较字符。我们看到第一个字符不匹配,即 G 与 T 不匹配。

Boyer Moore Java

步骤 2:现在,跳过字符,直到找到匹配。六个字符后找到匹配。此处,好后缀移位规则不适用。

Boyer Moore Java

bc: 6, gs: 0

根据坏字符移位,P 越过不匹配字符(即 G)。

Boyer Moore Java

步骤 3:再次,从右到左比较字符。我们看到 P 的前三个字符(t)与 T 匹配,第四个不匹配。

Boyer Moore Java

在这里,我们可以应用两个函数,即坏字符后缀和好字符后缀。如果应用坏字符后缀,它只跳过一个字符。如果应用好字符后缀,它会跳过两次对齐。因此,我们将应用好字符后缀,因为算法规定,要跳过更多对齐。因此,我们跳过两次对齐。

Boyer Moore Java

bc: 0, gs: 2

通过三次对齐移位后,我们得到

Boyer Moore Java

bc: 2, gs: 7

在这里,我们观察到 C 不出现在 P 的左侧。因此,坏字符对齐跳过 **两次** 对齐,好字符对齐跳过 **七次** 对齐。

步骤 4:移位字符后,我们看到字符串已匹配。

Boyer Moore Java

在上述模式中,我们跳过了 15 次对齐,T 的 11 个字符被忽略了。

Boyer Moore 预处理阶段

模式 **T: A A T C A A T A G C** 和 **P: T C G C** 的预先计算的跳过可以定义如下。在上面的模式中,我们使用了坏字符移位函数。

Boyer Moore Java

上表定义了跳过的对齐(字符)数量。

Boyer Moore 算法伪代码

模式搜索 Java 程序

让我们看看模式搜索 Java 程序。在下面的程序中,我们实现了暴力字符串搜索算法。

PatternSearchingExample.java

输出

Brute force looking for abddef in abcfefabddef
	Found match in the given text at index 6
Boyer-Moore looking for abddef in abcfefabddef
	Found match in the given text at index 6

让我们用 Java 程序实现该算法。

Boyer Moore Java 程序

让我们实现 Boyer-Moore 算法并通过 Java 程序搜索模式。

BoyerMooreImplementation.java

输出

Patterns occur at character = 0
Patterns occur at character = 5
Patterns occur at character = 10

让我们看另一个 Java 程序,在该程序中我们实现了不同的模式搜索逻辑。下面的程序检查是否在文本中找到了指定的模式。

BoyerMooreExample.java

输出

Pattern Not Matched
	text: aabbccdef
	word: cde
	exp: 0, res: 5
Pattern Not Matched
	text: zzzzaaapppxyzabc
	word: pqrs
	exp: 1, res: -1
Pattern Matched
Pattern Matched
Pattern Matched
Pattern Not Matched
	text: pqrsabcdxyzamnop
	word: cdxyza
	exp: 1, res: 6
Pattern Matched
Pattern Matched