串的应用--模式匹配算法

朴素的模式匹配算法

子串的定位操作通常称为串的模式匹配,是串中最重要的操作之一。

假设要从下面的主串S=”goodgoogle”中,找到T=”google”这个子串的位置,通常通过以下几个步骤:

  1. 主串S第一位开始,S和T前三个字母都匹配成功,但S第四个字母是d而T的是g。第一位匹配失败。
  2. 主串S第二位开始,主串S首字母是o,要匹配的T首字母是g,匹配失败。
  3. 主串S第三位开始,主串首字母是o,要匹配的T首字母是g,匹配失败。
  4. 主串S第四位开始,主串S首字母是d,要匹配的T首字母是g,匹配失败。
  5. 主串S第五位开始,S与T,6个字母全匹配,匹配成功。

简单来说,就是对主串的每个字符作为子串开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做T的长度的小循环,知道匹配成功或全部遍历完成为止。之前使用串其他操作实现模式匹配(Index方法),现不用串其他操作,使用基本的数组实现,假设主串S和要匹配的子串T的长度均保存在S[0]和T[0]中,具体代码如下:

/*返回子串T和主串S中第pos个字符之后的位置。若不存在,则函数返回值为0*/
/*T非空,1<=pos<=StrLength(S)*/
int Index(String S,String T,int pos){
   int i=pos; //i-主串S中当前位置下标,若pos不为1,从pos位置开始匹配
   int j=1; //j用于子串T中当前位置的下标值
   while(i <= S[0] && j <= T[0]){ //i小于S长度且j小于T长度时循环
      if(S[i]==S[j]){ //两字母相同时,继续循环,向后移动
         ++i;
         ++j;
      }else{ //俩字母不同时,i退回到上次匹配首位的下一位,j重置为1
         i=i-j+2;
         j=1;
      }
   }
   if(j>T[0]) return i-T[0];  //若j比T的长度大时,返回首位,否则返回0
   else return 0;
}

小结:最好情况的时间复杂度为 O(n+m) ,最坏情况的时间复杂度为 O[(nm+1)m] 。所以,这个算法太低效了。

KMP模式匹配算法

算法原理

对于所有在子串中有与首字符相等的字符,是可以省略一部分不必要的判断步骤。朴素的模式匹配中有很多重复的遍历步骤,主串的i是需要不断回溯来完成,而分析发现,这种回溯可以是不需要的,而KMP模式匹配算法就是避免这种不必要的回溯发生。

既然i值不回溯,也就是不能变小,要考虑的变化就是j值,观察发现,T串的首字符与自身后面字符比较,发现如果有相等字符,j值的变化会不同,即,j值的变化与主串没什么关系,关键取决于T串的结构是否有重复的问题。

j值得多少取决于当前字符之前的串的前后缀的相似度。

T串各位置的j值变化定义为一个数组next,那么next的长度就是T串的长度,函数定义如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值