数据结构(邓俊辉)学习笔记】串 12——BM_BC算法:性能分析

2024-08-30 11:20

本文主要是介绍数据结构(邓俊辉)学习笔记】串 12——BM_BC算法:性能分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1. 最好情况
  • 2. 最坏情况

1. 最好情况

在这里插入图片描述

以下,就让我们从最好情况的角度,来考察坏字符策略的性能。实际上,在最好情况下的性能之好,要远远超过我们的想象。具体来说,此时的时间成本可以度量为 O(n/m)。没错,除法。你能构造出这样的一个具体实例吗?这就是一个:

可以看到,模式串完全由0组成,而文本串呢?则由与模式串等长的若干个片段依次拼接而成。在每一个片段中,末字符都不是0,比如说取作1,而其余的字符实质上都无所谓,因此笼统的记作 x。我不妨就此例来走一遍 BM 算法。

  1. 第一次对齐的位置在这里,而首次比对就是0/1的失配。在这里,0就是坏字符,而且在模式串中,根本就找不到足以与 1 匹配的字符。
  2. 于是,BM法将会把模式串整体的移过这个失配的位置,并使之与文本串中的下一个片段彼此对齐。而接下来的故事,与刚才的那个片段完全一样。首先末字布 0 无法与 1 匹配,而且其余的 0 也不能与之匹配。
  3. 因此,算法将再次整体的后移模式串。以致再次、再再次、持续地整体移动下去。

纵观整个过程,每经过常数次的比对,我们就可以向后整体的移动 m 个字符。既然文本串累计不过 n 个字符,因此在这种情况下,算法至多会移动 n/m 次。

由此可见,在这种情况下,算法的确只需要运行这么多的时间,即便是相对于 KMP 而言,这也是一个极大的提高,更不用说蛮力算法了。这个例子并不失一般性,实际上只要 P 中的字符都是坏字符,那么每次我们都可以整体地对它进行移动,也就是说我们只需要常数次的比较,就可以整体地排除掉 m 的对齐位置。

由此可见,如果说 KMP 算法是个利用经验的高手,那么 BM 算法则是非常善于借鉴教训的高手。从这个意义上讲,BM 算法更加欢迎失败比对的出现。那么在什么情况下更容易出现失败的比对呢?

也就是说,对于任何一对随机出现的字符所做的比对,失配的概率在什么情况下更小呢?在这里我们再次回到那样一个重要的指标,也就是字母表的规模。实际上字母表的规模越大,单次匹配成功的概率也就越小,失配的概率也就越大,从而 BM 算法的优势也就更为明显

比如在处理汉字甚至 unicode 编码时,BM算法就是再适合不过的了。

2. 最坏情况

然而另一方面很遗憾,BM算法在最差情况下的性能也的确非常差。

具体来说,它的算法复杂度有可能会退化到蛮力算法的水平,也就是 O(n*m)。就此,你能举出一个具体的实例吗?我可以给你一点提示,你不妨去参考一下蛮力算法最坏情况的那个实例。
在这里插入图片描述
是的,我想你已经想到了,就是这个。这一次文本串倒是完全由0组成的,而模式串也几乎是由 0 组成的,唯一的例外是它的首字符。按照 BM 算法的流程,我们首先需要从末字符开始进行比对,而且我们会经历一系列的成功,直到最后一步才失败。可以看到,在这次失败之前,我们已经花费了 O(m) 的成本。

然而最糟糕的还不是这个,因为我们花费了如此之高的成本所换来的那个教训,居然对我们不会有太多的帮助。因为此时正属于我们此前所讲的那种最为特殊的情况,也就是说坏字符的替代者应该是 0。但是在模式上中,最后出现的那个 0 过于靠后,以至于如果我们需要将它与此前的适配字符对齐,将导致模式串的左移而不是右移。因此在这种情况下,我们只好搬出那个假想的通配哨兵,并用那通配的哨兵与这个失配的字符相对齐。

非常可惜,这样的效果只相当于模式串向右移动一个单位。没错,我们每花费 O(m) 的成本,换来的收获只是向后移动了一步,而总体共有 n。因此在这种情况下的总体计算成本的确应该是 n 与 m 的乘积。
在这里插入图片描述

我们不妨来反思一下, BM 算法当前的这个版本为何还有可能会出现如此之差的情况呢?没错,经验。我们已经看到 BM 算法目前的这个版本的确已经能够很好地借鉴教训。也正因为此,它才能够在最好情况下有出色的表现。然而,很遗憾,到目前为止,它还没能够有效地利用好经验。具体来说,也就是此前的那些成功比对所提供的有益信息。实际上,完整的 BM 算法的确也可以同时很好地利用这方面的信息。

因此,我们需要给 BM 算法增加一个策略,也就是所谓的好后缀策略。这个策略再加上我们刚刚介绍的坏字符策略,就可以使得 BM 算法变得几乎完美。

这篇关于数据结构(邓俊辉)学习笔记】串 12——BM_BC算法:性能分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120674

相关文章

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6