【weekly-sharing】BM算法(Boyer-Moore算法)学习记录

BM算法

描述

BM算法即Boyer-Moore算法,是由Bob Boyer和J Strother Moore于1977年提出的,是一种非常高效的字符串搜索算法。

BM算法从模式串的尾部开始匹配,最坏情况下时间复杂度为O(n*m),n为文本串长度,m为模式串长度。

the Boyer-Moore-Galil和the Turbo-BM两个算法做了进一步优化,最坏情况下达到线性。

可参考论文:

《On improving the worst case running time of the Boyer-Moore string searching algorithm》

BM算法主要定义了两个规则:坏字符规则和好字符规则。

规则

对于每一次模式串的移动,执行以下规则:

  • 从模式串的最后一位字符与文本串相应位置字符开始比对;

  • 相等则获得一个好后缀,并再比对前一个字符;

  • 不相等则按坏字符规则获取模式串移动位数;

  • 存在好后缀时,执行好后缀规则,获取模式串的移动位数;

  • 比对通过坏字符规则和好后缀规则获得的关于模式串移动位数,取最大的值来移动。

坏字符(bad character)规则:

坏字符即文本串中不匹配的字符

模式串移动位数 = 此时坏字符在模式串中的位置 - 模式串中最近一个坏字符的位置(没有时记为-1)

如:文本串为“xxhel”,模式串为“hel”,(不考虑好后缀)

第一次比对如下:

xxxhel
hel

比对“x”和“l”,不相等,得到坏字符“x”。

此时坏字符在模式串中的位置为2,最近一个坏字符的位置为-1

移动位数 = 2 - (-1) = 3 结果如下:

xxxhel
   hel

还如:文本串为“xhel”,模式串为“hhl”,(不考虑好后缀)

第一次比对如下:

xxhel
hhl

比对“h”和“l”,不相等,得到坏字符“h”。

此时坏字符在模式串中的位置为2,最近一个坏字符的位置为1

移动位数 = 2 - 1 = 1 结果如下:

xxhel
 hhl
好后缀(good suffix)规则:

好后缀即文本串中和模式串匹配得后缀,好后缀的位置为其最后一个字符的位置。

好后缀规则的移动位数,需要考虑两种情况,在比对字符前的模式串中是否存在字符串与最长好后缀相匹配。

  • 存在
    • 移动位数 = 好后缀在模式串中的位置 - 模式串中最近一个最长好后缀的位置

如:文本串为“xxxxheahebhe”,模式串为“ahebhe”

第一次比对如下:

xxxxheahebhe
ahebhe

比对“e”和“e”,相同,比对字符往前移;

比对“h”和“h”,相同,比对字符往前移;

比对“x”和“b”,不相同。

得到好后缀有“he”,“e”,最大好后缀为“he”

此时好后缀在模式串中的位置为5,比对位置前的最近一个最长好后缀的位置为2

移动位数 = 5 - 2 = 3 结果如下:

xxxxheahebhe
   ahebhe
  • 不存在
    移动位数 = 好后缀在模式串中的位置 - 其他好后缀在模式串中对应前缀位置的最大值(都没有则取-1)

如:文本串为“xxxbhebhe”,模式串为“hebhe”

第一次比对如下:

xxbhebhe
hebhe

比对“e”和“e”,相同,比对字符往前移;

比对“h”和“h”,相同,比对字符往前移;

比对“b”和“b”,相同,比对字符往前移;

比对“x”和“e”,不相同。

得到好后缀有“bhe”,“he”,“e”,最大好后缀为“bhe”

此时好后缀在模式串中的位置位置为4。比对位置前的模式串中不存在最长好后缀,但是存在“he”前缀,位置为1

移动位数 = 4 - 1 = 3 结果如下:

xxbhebhe
   hebhe

例子

假设:

  • 要检索的文本串记为T,模式串记为P

  • 文本串T为 “hellooo fish fjfish hshfish”,文本串长度为26。

  • 模式串P为 “hshfish”,模式串的长度为7,下标从0开始,

  • 模式串P中未有的字符在P中的下标记为-1,如“hello”中“i”的下标为-1

查找过程如下:

hellooo fish fjfish hshfish
hshfish

为了方便观察,文本串和模式串写作如下,字符间以 “|”分隔:


0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26
h |e |l |l |o |o |o |  |f |i |s |h |  |f |j |f |i |s |h |  |h |s |h |f |i |s |h

h |s |h |f |i |s |h
0 |1 |2 |3 |4 |5 |6

第一次P的“h”和T的“o”不匹配,“o”为坏字符,在P中并为出现“o”,所以“o”在P中最近一次位置为-1,根据坏字符规则

P右移位数: 6 - (-1) = 7,6为“h”在P中的下标,-1为o在P中的下标

P在T中对应位置: 0 + 7 = 7, 0为P对应T的启示位置,对应字符为“ ”


0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26
h |e |l |l |o |o |o |  |f |i |s |h |  |f |j |f |i |s |h |  |h |s |h |f |i |s |h

                     h |s |h |f |i |s |h
                     0 |1 |2 |3 |4 |5 |6

“f”为坏字符,根据规则找到“f”在P中最近一次位置,为3,移动规则:

P右移位数: 6 - 3 = 3

P在T中对应位置: 7 + 3 = 10

0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26
h |e |l |l |o |o |o |  |f |i |s |h |  |f |j |f |i |s |h |  |h |s |h |f |i |s |h

                              h |s |h |f |i |s |h
                              0 |1 |2 |3 |4 |5 |6

“i”为坏字符,根据坏字符规则:

P右移位数: 6 - 4 = 2

P在T中对应位置: 10 + 2 = 12

0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26
h |e |l |l |o |o |o |  |f |i |s |h |  |f |j |f |i |s |h |  |h |s |h |f |i |s |h

                                    h |s |h |f |i |s |h
                                    0 |1 |2 |3 |4 |5 |6

得到坏字符“j”(T中14号下标),对应P中2号下标;得到好后缀“h”,“sh”,“ish”,“fish”,最长好后缀为“fish”

根据话字符规则:

P右移位数: 2 - (-1) = 3

P在T中对应位置: 12 + 3 = 15

好后缀位置为6,最长好后缀在P中最近位置为-1(P中无最近位置)。后缀“ish”和“sh”在P中位置为-1(P中不存在相应前缀),只有“h”在P中有相应前缀,位置为0

根据好后缀规则:

P右移位数: 6 - 0 = 6,

P在T中对应位置: 12 + 6 = 18

比较发现好后缀规则移动较大,选择好后缀规则移动

0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26
h |e |l |l |o |o |o |  |f |i |s |h |  |f |j |f |i |s |h |  |h |s |h |f |i |s |h

                                                      h |s |h |f |i |s |h
                                                      0 |1 |2 |3 |4 |5 |6

得到坏字符“i”(T中下标24,对应P中下标为6),在P中最近的“i”下标为4。

根据坏字符规则:

P右移位数: 6 - 4 = 2

P在T中对应位置: 18 + 2 = 20

0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26
h |e |l |l |o |o |o |  |f |i |s |h |  |f |j |f |i |s |h |  |h |s |h |f |i |s |h

                                                            h |s |h |f |i |s |h
                                                            0 |1 |2 |3 |4 |5 |6

匹配完成!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值