数据结构(邓俊辉)学习笔记】串 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

相关文章

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重

关于MyISAM和InnoDB对比分析

《关于MyISAM和InnoDB对比分析》:本文主要介绍关于MyISAM和InnoDB对比分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录开篇:从交通规则看存储引擎选择理解存储引擎的基本概念技术原理对比1. 事务支持:ACID的守护者2. 锁机制:并发控制的艺

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三