文章的一开头,仍是要强调下字符串匹配的思路:html
将模式串
和主串
进行比较算法
主串
和模式串
的下一个位置失配时,segmentfault
在模式串
中寻找一个合适的位置数组
主串
当前失配位置进行比较模式串
的头部与主串
失配位置的下一个位置进行比较主串
中找到一个合适的位置,从新与模式串
进行比较前面的 BF
和 KMP
算法,都是属于规规矩矩从前向后的操做,后者仅在寻找模式串
的合适位置上进行了优化,而 BM
算法的操做就显得骚了不少,它的优化点在于:数据结构
主串
中合适的位置关于算法的介绍和分析,网上有不少解释,这里推荐一下阮一峰的字符串匹配的Boyer-Moore算法,很清楚的讲解了整个优化的思路,能够先看完理解了再往下看,由于下面主要介绍一下坏字符规则
和好后缀规则
须要的数据结构的手工求法以及代码实现。框架
运用坏字符规则,在算法里主要体如今生成一张散列表,表的key值是字符集里每一个字符的ASCII码值,value值是模式串中该字符的位置,举个栗子:函数
假设字符串的字符集不是很大,用长度为256
的数组来存储,而且初值赋值为-1
。数组的下标对应字符的 ASCII
码值,数组中存储这个字符在模式串中出现的位置。这里要特别说明一点,若是坏字符在模式串里多处出现,选择最靠后的那个,由于这样不会让模式串滑动过多,致使原本可能匹配的状况被滑动略过。优化
好后缀规则体如今如何求出 suffix
和 prefix
两个数组以及移动规则
。spa
key值表示的是后缀子串的长度,value值表示的是在模式串
中跟好后缀 S 相匹配的最后一个子串 S' 的首字母在模式串
中的key值,以下图:3d
一样的,key值表示的是后缀子串的长度,而value值表示的是模式串
中,是否有和该长度下后缀子串相同的前缀子串,是的话为 true
,不然为 false
,以下图:
移动规则总结以下:
在模式串
中寻找跟好后缀 S 相匹配的最后一个子串 S'
模式串
移动到使得 S' 和主串
对齐的位置模式串
的前缀子串
中是否有和 好后缀 S
的后缀子串
匹配的位置,滑动模式串
以对齐。模式串
移动至主串
与模式串
末尾对齐的下一个位置下图分别对应三种状况:
参考字符串匹配的思路
主串
和模式串
的字符对比,因此须要两个指针 i
,j
分别指向主串
和模式串
,记录位置 须要一个循环来重复进行匹配操做,此时思考终止条件:
i
指向主串
每次匹配的合适位置,从前日后扫描;j
指向模式串
的尾部,从后往前扫描。考虑极端状况:主串
和模式串
对比完,仍然没法匹配。此时,i
的位置必定小于等于 主串
长度 n
与模式串
长度 m
的差值。具体可看下图。模式串
从后往前与主串
进行匹配,这也须要一个内层循环来驱动指针j
坏字符规则
和好后缀规则
计算出 i
须要移动的位置,选择两个值当中最大的,从新计算 i
的值,重复进行匹配。根据以上分析能够写出整个的逻辑框架代码:
框架写好后,接下来就是完善三个辅助函数便可
这个就没有什么能够多说的了,只要参考上面分析的,一步一步写出代便可:
suffix
和 prefix
拿下标从 0
到 i
的子串(i
能够是 0
到 m-2
)与整个模式串,求公共后缀子串。若是公共后缀子串的长度是 k
,那就记录 suffix[k]=j
(j
表示公共后缀子串的起始下标)。若是 j 等于 0
,也就是说,公共后缀子串也是模式串的前缀子串,就记录 prefix[k]=true
。能够本身动下手,模拟下代码的运行,尤为注意中k
值的运用,很巧妙。
根据上面此步的算法分析,也能够写出:
总的来讲,BM算法
另辟蹊径,经过从后往前的匹配的思路,加上坏字符规则和好后缀规则来优化移动的步数,从而提升算法的匹配效率。
“字符串匹配算法”是“重学数据结构与算法”系列笔记: