当前课程知识点:数据结构(下) > 第十一章 串(下) > (d1)BM_BC算法:以终为始 > 11d1-4: 以终为始
既然按照以上的分析
模式串中越靠后的字符对算法性能的优化作用更大
那么或许我们应该把计算的方向和次序颠倒过来
以终为始
此话怎讲呢
具体来说 在每一趟扫描中
我们都需要从末字符而不是首字符开始比对
也就是说 扫描的方向将变成自后向前而不再是自左向右
来看这样一个具体的例子
这就是由12个字符所构成的一个文本串
而待匹配的模式串
则由这3个字符组成
为了启动第一趟扫描
我们首先要将它们的首字符彼此对齐
然而这里 我们将首先从末字符开始比对
可以看到 这是一次失败的比对
实际上 这种失败的比对必然是更容易发生的
因为你注意到 我们在这里所采用的字母表是由汉字构成的
即便是只记录常用的汉字
其规模也至少超过5000
从多达5000个的候选中任取2个
二者相同的概率自然是非常非常之低的
反过来 不同的概率也就应该很高
所以对于这次失败 我们应该有足够的心理准备
因此接下来 或许我们应该静下心来 对这次失败好好地作一分析
或许你能从中悟出点什么
是的 表面上看这里是“名”与“道”之间的冲突
而实际上我们可以将这次教训进一步地概括为
如果需要在“道”的附近实现一次完整的匹配
那么 至少与它对应的那个字符
就应该也是“道”
而非“名”
现在 按照这一必要条件来反观我们的模式串
就会发现其实“道”根本就没有出现在其中
这一点非常重要
如果能够悟到这一点
我们就可以大胆地将这个模式串整体地移过这个位置
从而在这样一个新的位置对齐
接下来的这趟比对与上一趟基本类似
依然是“名”与“道”不符
所以再一次地
我们同样可以将整个字符串移过这个位置
从而在这样一个新的位置
继续对齐
接下来的这趟扫描
依然起始于末字符
可以看到 这是一次成功的比对
你应该觉得非常幸运
因为正如我们刚才所言
这种成功比对出现的概率是极低的
于是接下来 我们再去进而比对与之在左侧相邻的那一对字符
这依然是一次大概率的失败比对
然而 作为一次新的教训
它同样有可能让我们悟到点什么
是的 依然是这个失配位置处的“可”字
它同样给出了一个能够局部完全匹配的必要条件
然而 如果按照这个必要条件反观我们的模式串
就会发现 其中同样没有出现这个字符
因此接下来 我们可以将这个字符串同样整体地移过这个失配的位置
并在这样一个新的位置
继续对齐
然后 依然从末字符开始
继续比对
同样 依然是大概率的失败
而此后 只要我们能够静下心来对这一教训作一分析
就同样能够针对完全匹配
给出一个必要条件
我想 你已经看出这个必要条件来了
是的 如果能够在包括这个“常”字在内的局部
实现一次完全匹配
那么模式串中与之对齐的
就同样也应该是一个“常”字
这一回 我们以此反观模式串
就会发现的确存在一个“常”字
因此接下来 我们就不妨将整个字符串向右移动一个单位
从而让“常”字的确与“常”字相对
在满足了这样一个必要条件之后
我们就可以来开始新一轮比对
首先是末字符
这是成功的
而且接下来的各次比对
也都是成功的
这意味着我们终于发现了一次完全的匹配
整个算法也就可以随即终止
现在 我们来核算一下这个算法所花费的计算成本
也就是在其间所作的比对次数
按照我们这里标注的习惯
深色的都是成功的比对
灰色的则是失败的比对
而白色的 则是没有进行 从而节省下来的比对
可以看到 我们累计做了4次成功的比对
以及4次失败的比对
没错 4次
加4次
累计不过8次
这一结果意义非凡
因为我们注意到 即便忽略掉模式串
仅文本串 也至少有12个字符
而我们在算法过程中所执行的比对次数
居然要小于这一长度
换而言之 平均在每个字符上
所消耗的比对居然不足1次
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)概述
--07A-1 纵览
--07A-5 接口
-(a)概述--作业
-(b1)BST:查找
-第七章 二叉搜索树--(b1)BST:查找
-(b2)BST:插入
-(b2)BST:插入--作业
-(b3)BST:删除
-第七章 二叉搜索树--(b3)BST:删除
-(c)平衡与等价
-(c)平衡与等价--作业
-(d1)AVL树:重平衡
-第七章 二叉搜索树--(d1)AVL树:重平衡
-(d2)AVL树:插入
-(d2)AVL树:插入--作业
-(d3)AVL树:删除
-(d3)AVL树:删除--作业
-(d4)AVL树:(3+4)-重构
-(d4)AVL树:(3+4)-重构--作业
-本章测验
--章节测验
-(a1)伸展树:逐层伸展
--习题
-(a2)伸展树:双层伸展
--习题
-(a3)伸展树:算法实现
--习题
-(b1)B-树:动机
--习题
-(b2)B-树:结构
--习题
-(b3)B-树:查找
--习题
-(b4)B-树: 插入
--习题
-(b5)B-树: 删除
--习题
-(xa1)红黑树:动机
--习题
-(xa2)红黑树:结构
--习题
-(xa3)红黑树:插入
--习题
-(xa4)红黑树:删除
-本章测验
--习题
-(b)散列:原理
--09B-3 数组
--09B-4 原理
--09B-5 散列
--09B-6 冲突
--习题
-(c)散列:散列函数
--习题
-(d1)散列:排解冲突(1)
--习题
-(d2)散列:排解冲突(2)
--习题
-(e)桶/计数排序
--习题
-本章测验
--本章测试
-(a1)需求与动机
--习题
-(a2)基本实现
--习题
-(b1)完全二叉堆:结构
--习题
-(b2)完全二叉堆:插入与上滤
--习题
-(b3)完全二叉堆:删除与下滤
--习题
-(b4)完全二叉堆:批量建堆
--习题
-(c)堆排序
--习题
-(xa1)左式堆:结构
--习题
-(xa2)左式堆:合并
--习题
-(xa3)左式堆:插入与删除
-本章测验
--本章测试
-(a)ADT
--习题
-(b1)串匹配
--习题
-(b2)蛮力匹配
--习题
-(c1)KMP算法:从记忆力到预知力
--习题
-(c2)KMP算法:查询表
--习题
-(c3)KMP算法:理解next[]表
--习题
-(c4)KMP算法:构造next[]表
--习题
-(c5)KMP算法:分摊分析
--习题
-(c6)KMP算法:再改进
-(d1)BM_BC算法:以终为始
-(d2)BM_BC算法:坏字符
-(d3)BM_BC算法:构造bc[]
-(d4)BM_BC算法:性能分析
-(e1)BM_GS算法:好后缀
-(e2)BM_GS算法:构造gs表
-(e3)BM_GS算法:综合性能
-(f1)Karp-Rabin算法:串即是数
-(f2)Karp-Rabin算法:散列
-本章测验
--本章测试
-(a1)快速排序:算法A
-- 12a1-5: 实例
--习题
-(a2)快速排序:性能分析
--习题
-(a4)快速排序:变种
-(b1)选取:众数
-(b3)选取:通用算法
--习题
-(c1) 希尔排序:Shell序列
--习题
-(c2)希尔排序:逆序对
-本章测验
--本章测试