boyer mooer算法c语言,BoyerMoore字符串匹配算法好后缀表构建

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

书里面对好后缀的构建讲的内容太少,实现算法的时候发现有许多的问题,因此在这里详细介绍一些应该如何构造好后缀表。l:字符串的长度

goodSuffix:好后缀表数组名

后缀表数组

好后缀表可以用一个长度为l的数组来存着,暂且称之为goodSuffix数组,那么goodSuffix[i]就是我们要查的好后缀为i时候的移动值。goodSuffix[0]初始化为l。

构造开始

我们从i为1开始,构建好后缀表。

判断1

我们试图去找i-1时候的那条好后缀,它的前面的匹配的字符串,在这条字符串前面的一个位置的字符串,是不是与i时候,新增加的那个字符相等。

举例来说,ABABAB这条字符串,我进行到i=3的时候,我找不到匹配了,然后我检查i=2的时候的好后缀,其匹配的是下标2-3的AB。i=3的时候新增了B,于是我看看2-3的AB前面的一个字符,刚好也是B,所以i=3时候的BAB,根据i=2的结果,找到了i=3时候的匹配字符串,goodSuffix[3]就等于goodSuffix[2]。

当然,goodSuffix[0]初始化为长度,i=1的时候是没有匹配的,这个情况是不会符合的,进入判断2。

判断2

我们试图寻找好后缀的除去好后缀之外的在字符串中的最后一个匹配。

通常字符串比较算法都是从字符串前面开始扫描,找到第一个匹配就停止的。我们要找最后一个匹配,所以我先把字符串反转过来,然后再开始寻找,那么这样就可以找到这个后缀,在这条字符串中的最后一个匹配的位置。

如果找到了这个匹配,则直接在goodSuffix[i]填入这个所需的移动值就行了。

否则进入判断3。

判断3

如果去掉了好后缀的第一个字符,是否在最前面有匹配呢?

如果有的话,那么我们可以移动字符串,就将去掉这个字符后的这个好后缀,对齐最前面匹配的这个前缀。

比如,在CABDDDDCABEECAB中,i为4的时候,goodSuffix[3]指代的下标为6-8的CAB,其前面是D,不匹配ECAB,不符合判断1。那么在前面也无法找到ECAB,不符合判断2。但是,我们去掉E之后,发现CAB在最前面有匹配。此时,因为这已经是字符串最前面了,再之前是啥都不用管,因此可以放心的移动字符串,将后面CAB的那个位置,对齐到前面的CAB。

对齐完了以后,goodSuffix后面的所有值,都是当前的这个值了。因为当前这个好后缀,在整条模式中,没有匹配的子串,随着i的增大,更加不会匹配。

如果没有,就彻底找不到了,我们就要移动这个字符串了,连同i+1之后的所有情况都是。

go语言实现

// 计算好后缀table.goodSuffix=make([]int,len(pattern))// 定义好后缀0为整条的长度table.goodSuffix[0]=len(pattern)//将字符串转过来reversePattern:=reverseString(pattern)fori:=1;i1&&len(pattern)-table.goodSuffix[i-1]-(i-1)-1>=0&&pattern[len(pattern)-(i-1)-1]==pattern[len(pattern)-table.goodSuffix[i-1]-(i-1)-1]{// 如果匹配,则我们可以用上一个的值table.goodSuffix[i]=table.goodSuffix[i-1]}elseifgoodIndex:=strings.Index(reversePattern[i:],reversePattern[:i]);goodIndex!=-1{// 借用库函数来寻找第一个好后缀。index是找到的这个好后缀在整条模式字符串中,从后面开始数过来的下标值。实际情况肯定不能用库函数,可以用一个匹配函数,只要不是这个就行,否则就成了递归了。table.goodSuffix[i]=goodIndex+i}else{// 我们只能寄希望字符串的长度为i-1的前缀,// 等于i-1时候的好后缀,如果不是,则彻底没有匹配,接下来都需要整条所有字符串ifpattern[:i-1]==pattern[len(pattern)-(i-1):]{table.goodSuffix[i]=len(reversePattern)-(i-1)}else{table.goodSuffix[i]=len(reversePattern)}// 这里只会进来一次,找不到一次,后面更不会找到,用i-1的值填入即可// 这个包含了i-1时在最前面有匹配的情况,此时也是用i-1的值填充接下来的所有值fori+=1;i

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值