数据结构(邓俊辉)学习笔记】串 10——BM_BC算法:坏字符

news/2025/3/31 11:00:40/

文章目录

  • 1.坏字符
  • 2. 特殊情况

1.坏字符

在这里插入图片描述

实际上,刚才的实例中我们所展示的那样一个计算过程,就是所谓 BM 算法所采用的策略之一,而这一策略,将我们刚才所说的教训称作坏字符。

在这里,不妨改为基于蛮力算法的第二个版本来进行改造。也就是说模式算中当前参与比对的如果是字符 P[j],那么文本串中对应的就是 T[i + j], 这幅图画出的就是这样一个一般性的场景。

请注意,当前这趟扫描如果的确已经抵达 P[j] 或 T[i + j],则说明在这对字符的右侧,有一段足够长的匹配部分。而相对于模式串而言,这个匹配部分是一个后缀。既然这两个字符失配,不妨就分别将它们记作 X 和 Y。

延续我们在刚才的分析中所采用的逻辑,如果我们将这次失配当做一次教训,那么其原因就可以解释为:在 Y 这个位置,我本来期望是一个 X,然而这个字符Y的出现,却使得我们在此局部获得一次完整匹配的希望成了泡影,因此 BM 算法也将这个字符 Y 称作坏字符。

正是因为这个坏字符的出现,当前这个对齐位置,也就自然地可以被排除掉了。那么,更重要的是,这次教训能够为我们带来什么启示呢?具体的能为我们后续的比对提供什么有益的借鉴呢?

将刚才我们所举的实例推越广之,如果我们还希望能够在这个字符 X 附近,实现一次完整的匹配,那么作为一项必要条件,与这个字符 X 对准的也应该至少是一个 X。是的,由刚才所举的实例推而广之,我们也同样可以得出此时的处置方法。

具体来说,就是试图从模式上中去找出这样的一个字符 X,并且通过相应的移动,使得这个 X 能与文本串中的那个 X 彼此对齐。而一旦完成了这样的对齐,我们又可以继而从最右端开始,启动下一轮的扫描比对。

那么对应于每一个这样的场景,相应的位移量又应该是多少呢?

稍加观察我们不难发现,这个位移量仅取决于刚才失配的位置 j 以及对应的字符 X 在模式传中的位置。而与文本串以及当前的对齐位置没有任何关系。这就意味着我们可以与 KMP 算法一样通过预处理事先计算出每种情况下对应的位移量。

也就是说,我们可以将每一个这样的字符所对应的位移量制成一个表,也就是所谓的 bc 表。通过再进一步观察,我们不能发现,这个表只需记录每一个字符 X 在模式串中所对应的秩,在图中也就对应于这段距离(bc[‘X’])。

我们知道,这段前缀的长度恰好就应该是 j,而对应的位移量也自然就应该是这两段前缀的长度之差。

2. 特殊情况

当然,实际情况要更为复杂一些。不妨来看看还有哪些特殊情况需要考虑并且处置。

在这里插入图片描述

  1. 首先需要考虑的一种情况就是,在模式串中有可能同时存在多个 X,那在这种情况下,我们究竟应该用哪个 X 来替换哪个坏字符 Y 呢?与 KMP 算法一样,当同时存在多个候选时,我们并不倾向于向数学上那样,逐一地去尝试它们,而应该在安全的前提下,选择其一,从而使得我们不必回溯。

也就是说,如果有多个候选,那么我们倾向于选择其中对应的位移量尽可能小的那个。按照刚才的分析,任何一个字符所对应的位移量都与这个字符在模式串中的秩呈反比。因此,为了使得位移量尽可能的小,所对应字符的秩就应该尽可能地大。换而言之,当有多个候选时,我们应该首先选用其中的最靠后者,或者等价的,在相对于这个字符 X 的那个后缀中,必须不包含任何 X。

在这里插入图片描述

  1. 那么与此相反的另一种极端情况就是,在模式串中,可能没有任何这样的 X 可供选择。

    回忆一下,在我们此前所举的那个实例中,的确就有这种情况。比如其中文本串中的那个"道"字,在模式串中根本就没有出现过。你应该还记得我们当时的处置方法,没错,我们只需将模式串完整的移过这个对齐的位置。那么在相应的算法描述以及代码实现的过程中,我们又应该如何统一地来处置这种情况呢?没错,哨兵。

    与 KMP 算法一样,我们可以为每一个模式串在最左侧增设一个假想的通配哨兵。于是所谓的将整个模式串移过这个位置,也就等效于用这个通配的哨兵与刚才失配的字符对齐。既然是通配字符,那么此前适配的这个字符在此后就可以被忽略掉。

实际上,除了以上所介绍的两种,还有一种更为特殊的情况需要处理,你能看出来吗?是的,在这种情况下,模式串中的确至少存在一个候选的字符 X。然而,其中最靠右的那个,位置又过于靠右。也就说,它所对应的那个 bc 表项,或者说他的秩太大了,高过了 j,以至于通过二者之差所计算出来的位移量,既然是一个负数。显然,这样的回溯是没有道理的,也是不必要的。

因为作为这个算法的一条不变性,相对于任何时候的当前对齐位置,此前的所有对齐位置,都已经被淘汰掉了,因此根本没有必要再回过头去重新考虑。既然以前的所有对齐位置都已被淘汰掉,而当前的这个对齐位置也刚刚被否定掉了。所以再直接而简洁不过的处置方法就是,将整个模式串向后移动一个字符,并进而考察下一个对齐位置。

在这里插入图片描述

至此,我们已经兼顾到了可能发生的所有情况,包括特殊情况。我知道 KMP 算法的整个策略,完全是融入并体现于其中的 next 表。而这里的 BM 算法也类似,其策略也将最终融入并体现于 bc 表,以及稍后要介绍的 gs 表。

那么首先一个问题就是 bc 表又当如何构造出来呢?相应的我们又需要花费多长时间呢?


http://www.ppmy.cn/news/1520843.html

相关文章

C++系列-STL容器的应用举例

STL容器的应用举例 [TOC](STL容器的应用举例) 临安春雨初霁》 陆游 世味年来薄似纱,谁令骑马客京华。 小楼一夜听春雨,深巷明朝卖杏花。 矮纸斜行闲作草,晴窗细乳戏分茶。 素衣莫起风尘叹,犹及清明可到家 code: /* 报道的有10个同…

【JUnit单元测试框架】

单元测试的概念 单元测试,顾名思义,是针对软件中的最小可测试部分(通常是类或方法)进行的测试。它的目的是确保这些最小单元按照预期工作,从而帮助开发者快速定位和解决问题。单元测试通常遵循“隔离”原则&#xff0…

C++基础知识之顺序结构

顺序结构 --> 小数学问题 1.数据类型: short 短整形 2字节 65335 int 整型 4字节 2147483647 10位 long long 长整型 8字节 .... 19位 float 单精度浮点数 4字节 .... …

如何在知行之桥上通过业务单号查找原始报文?

在知行之桥中接收或发送的数据通常是EDI原始报文,知行之桥会对EDI原始报文进行格式转换,以方便用户后端系统的处理。因此,一般情况下,用户看到的都是转换后的数据结构,例如Json、XML或Excel等,无需直接查看…

Elasticsearch倒排索引

什么是倒排索引 倒排索引(Inverted Index)是一种将文档中的每个单词映射到包含该单词的文档列表上的数据结构 倒排索引的构建过程 文档1: “我爱吃苹果” 文档2: “我爱吃香蕉” 文档3: “我喜欢苹果和香蕉” 文档分词:将文档中的文本内容…

jpg转gif,四款图片转化软件盘点!

在这个视觉为王的时代,一张静态的图片往往难以满足我们追求生动与趣味的心。想象一下,将平淡无奇的JPG图片转化为生动有趣的GIF动图,瞬间就能吸引无数眼球!今天,就让我们一起探索四款超实用的JPG转GIF图片转化软件&…

too many blocks in cooperative launch at cudaLaunchCooperativeKernel

在使用cudaLaunchCooperativeKernel时出现: cudaErrorCooperativeLaunchTooLarge (error 82) due to “too many blocks in cooperative launch” on CUDA API call to cudaLaunchCooperativeKernel. 问题: 在使用cudaLaunchCooperativeKernel时&…

ffmpeg音视频开发从入门到精通——ffmpeg实现音频抽取

文章目录 FFmpeg 实现音频流抽取1. 包含FFmpeg头文件与命名空间声明2. 主函数与参数处理3. 打开输入文件4. 获取文件信息5. 查找音频流6. 分配输出文件上下文7. 猜测输出文件格式8. 创建新的音频流9. 打开输出文件10. 写入文件头信息11. 读取并写入音频数据12. 写入文件尾部信息…