KMP算法的改进思路

一.KMP算法的介绍

KMP算法(Knuth–Morris–Pratt Algorithm):这是一种利用已匹配的信息来跳过不必要的比较的字符串匹配算法,它的核心思想是计算模式串的前缀函数,表示模式串的每个前缀子串中,最长的既是前缀又是后缀的字符串的长度。然后在匹配过程中,如果发现不匹配,就根据前缀函数来决定模式串应该向右移动多少位,从而避免重复比较已匹配的部分。这种算法的时间复杂度是O(m+n)。

以下算法均采用主串T="acbccadbacbacc",模式串P="acbacc"。

KMP算法伪代码:

int KMP(char *T,char *P){
  int T_len=len(T); //文本串T的长度
  int P_len=len(P); //模式串P的长度
  int i=0,j=0;
  while(i<T_len&&j<P_len){
    if(T[i]==P[j]){
      i++;
      j++;
    }else{
      j=next[j]; //失配,指针回退到对应next数组对应的下标元素
    }
  }
  return j<P_len?-1:i-j; //成功返回下标,反之-1;
}

KMP算法的演示过程:

序号012345678910111213
文本串

a

c

b

c

c

a

d

b

a

c

b

a

c

c

第一次

a

c

b

a

c

c

第二次

a

c

b

a

c

c

第三次

a

c

b

a

c

c

第四次

a

c

b

a

c

c

第五次

a

c

b

a

c

c

第六次

a

c

b

a

c

c

第七次

a

c

b

a

c

c

二.BM算法的介绍

BM算法(Boyer–Moore Algorithm):这是一种从右往左匹配的字符串匹配算法,它的核心思想是利用模式串中的信息来跳过尽可能多的主串字符,从而达到快速匹配的目的。BM算法主要使用了两种规则:坏字符规则和好后缀规则。坏字符规则是指,如果在某个位置发现不匹配,就将模式串中最靠右的与主串中该字符相同的字符与之对齐,如果没有这样的字符,就跳过整个模式串。好后缀规则是指,如果在某个位置发现不匹配,就将模式串中与已匹配的后缀子串相同的最长子串与之对齐,如果没有这样的子串,就找到已匹配的后缀子串的最长前缀,使之与模式串的前缀对齐。这种算法的最坏时间复杂度是O(m*n)。

当然BM算法还有跟KMP算法一样。还有好后缀规则,改进算法思想中没有提及,感兴趣的同学可以自行查阅。

BM算法的演示过程:

序号012345678910111213
文本串

a

c

b

c

c

a

d

b

a

c

b

a

c

c

第一次

a

c

b

a

c

c

第二次

a

c

b

a

c

c

第三次

a

c

b

a

c

c

第四次

a

c

b

a

c

c

三.KMP算法的改进思路

KMP算法解决了BF算法中文本指针i的回溯问题,但它仍有局限性。在KMP算法中,指针i每次只能向前移动一位,且模式串的跳转距离总是小于当前的j值。这意味着当字符不匹配的可能性较时,j值通常较小,导致KMP算法的总体匹配效率并不理想。为了提高效率,研究者们提出了改进的KMP算法,如改进的next数组计算方法,这些改进旨在减少不必要的比较,使算法更加高效。改进算法在KMP算法不仅保证主串T指针i不回溯的问题,还能保证主串每次比较结束后,尽可能多的移动。改进算法的最坏时间复杂度为O(m+n),理论上也优于BM算法。

改进算法的执行过程描述如下:

首先,需要先对模式串进行处理,得到next数组和BM算法坏字符跳转距离数组BMc。

当发生不匹配时,第一个步骤是先调用KMP算法进行移动,移动之后再次比较。第二个步骤就是调用BM算法的坏字符跳转规则,使主串T再次移动。重复执行上述两个步骤,直到主串结束或匹配成功。

改进算法的流程图如下:

改进算法的主体伪代码描述:

while(i<T.length){
  if(j==-1||T[i]==P[j]){
    if(匹配成功){
      i++;j=0;//找到一个匹配,寻找下一个
    }
    else{i++;j++;}
  }
  else{//计算模式串移动next[j]后末字符在文本T中的
位置
   tLast=T[i+P_len-next[j]-1];
   //T该位置的文本字符与P末字符不匹配
   if(tLast!=PLast){
    j=0;
    i=i+坏字符跳转;
   }else{j=next[j]}//按照KMP继续匹配
  }
}

改进KMP算法的一般思路是增加预处理,最大程度利用部分匹配值,减少字符的比较次数。

改进算法的演示过程如下:

序号012345678910111213
文本串

a

c

b

c

c

a

d

b

a

c

b

a

c

c

第一次

a

c

b

a

c

c

第二次acbacc
第三次acbacc

在第一次遇到不匹配时,先计算出该位置的文本字符 为 tLast = T[i + m - next[ j] - 1] = T[3 + 6 - 0 - 1] = T[8] = ‘a’, 模式串的末字符为c,a与c不匹配,则用字符a进行坏字符匹 配,第一步next数组跳的距离为 j - next[ j] = 3 - next[3] = 3, 第二步用bmBc数组跳的距离 bmBc[a] = 2 ,两步的跳跃距 离和就是i移动的距离,即i值等于i + bmBc(a) - next[ j] = 5, 此时 j 值重新赋值为0,再进行下一次窗口的匹配,如表 4所示;若两字符匹配,则按照KMP的匹配过程进行比 较,即 j 值等于 next[ j] 值,再进行下一轮的比较。

四.代码能力较差,所以只给出了伪代码描述,作个人学习记录,如有不足之处请指正。

  • 42
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值