串匹配问题

给定两个字符串S和T,在主串S中查找子串T的过程称之为串匹配(模式匹配),T称之为模式。这样一类的问题在实践中应用非常广泛。在文本处理系统、操作系统、编译系统、数据库系统以及Internet信息检索系统中,串匹配都是使用最频繁的操作。

一般来说,串匹配问题具有以下的特征:

  • 问题输入规模很大,常常要在大量信息中进行匹配。因此,算法执行依次的时间也不可忽视
  • 匹配操作经常被调用,执行频率很高,因此,算法改进的累积效益往往比表面看起来要高

解决串匹配问题可以使用蛮力法或者KMP模式匹配。

首先介绍一下BF算法(朴素的模式匹配算法):
从主串的S的第一个字符开始和模式T的第一个字符进行比较,若相等,则继续比较二者的后序字符;若不相等,则从主串S的第二个字符开始和模式T的第一个字符进行比较,重复上述过程,若T中的字符全部比较完毕,则说明本趟匹配成功;若S中的字符全部比较完毕,则匹配失败。这个算法称之为BF算法。

BF算法的基本思想如上图。
设有主串S=“abcabcacb”,模式T=“abcac”,则其匹配执行过程如下:

上述BF算法可描述为以下伪代码:

输入:主串S,模式T
输出:T在S中的位置1. 初始化主串开始比较位置index=02. 在串S和串T中设置比较的起始下标i=0,j=03. 重复以下操作:直到其中一个串比较完毕if S[i]==T[j] i++;j++elseindex++;i=index;j=0
4. 如果T中所有字符均比较完毕,则返回匹配的开始位置,否则返回0

其算法用C++语言描述如下:

int BF(char S[],char T[]){int index=0;      //主串从下标0开始第一趟匹配int i=0,j=0;        //设置比较的起始下标while((S[i]!='\0')&&(T[j]!='\0')){if(S[i]==T[j]){i++;j++}else{index++;i=index;j=0;}
}

对BF算法分析:
BF算法在某趟匹配失败后,对于主串S要回溯到本趟匹配开始字符的下一个字符,模式T要回溯到第一个字符,这就造成了BF算法的效率低下,而这些显然是不必要的:

  • 观察上图匹配过程,在第一趟匹配过程中,S[0]~S[3] 和T[0] ~ T[3]匹配成功 ,S[4]!=T[4]匹配失败,因此有了第二趟。因为第一趟中有S[1]=T[1],而T[0]!=T[1],故T[0]!=S[1],所以第二趟是不必要的,同理,第三趟也是不必要的,可以直接到第四趟。进一步分析第四趟中的第一对字符S[3]和T[0]的比较是多余的,因为第一趟中已经比较了S[3]和T[3],并且S[3]=T[3],而T[0]=T[3],因此必有是S[3]=T[0],因此第四趟比较可以从第二对字符S[4]和T[1]开始进行,也就是说,第一趟匹配失败后,下标i不回溯,而是将下标j回溯至第二个字符,从T[1]和S[4]开始进行比较.

而关键的问题在于S[i]和T[j]匹配失败后,下标i不回溯,下标j回溯至某个位置k,从T[k]和S[i]开始比较。这个其中的k是如何确定的?

下面我们观察部分匹配成功时的特征,某趟在S[i]和T[j]匹配失败后,下一趟比较从S[i]和T[k]开始,则有T[0]~T[k-1] =S[i-k] ~S[i-1]成立,如下图a所示;在部分匹配成功时,有T[j-k] ~T[j-1]=S[i-k] ~S[i-1]成立。如图b所示。

所以可得:T[0]~T[k-1]= T[j-k] ~T[j-1]。
这说明:模式中每个字符都对应一个k值,而且该k值仅依赖于模式本身,于主串无关。

例如主串S=“ababaababcb”,模式T=“ababc”,其模式T的next值为{-1,0,0,1,2}。而其对应的KMP(改进的串匹配)算法过程如下:

该KMP算法匹配的伪代码如下:

输入:主串S,模式T
输出:T在S中的位置1. 初始化主串开始比较位置index=02. 在串S和串T中设置比较的起始下标i=0,j=03. 重复以下操作:直到其中一个串比较完毕if S[i]==T[j] i++;j++elsej=next[j]          //将下标j回溯到next[j]的位置if  j=-1  i++;j++ 准备下一趟比较
4. 如果T中所有字符均比较完毕,则返回匹配的开始位置,否则返回0

KMP算法的C++代码实现:

/**在求得模式T的next值后,KMP算法只需将主串扫描一遍。所以其时间复杂度为O(n).
**/
void getNext(char T[],char S[]){int len=-1,i,j;next[0]=-1;for(j=1;T[j]!='\0';j++){                 //依次求next[j]for(len=j-1;len>=1;len--){          //相等子串的最大长度为j-1for(int i=0;i<len;i++)                             //依次比较T[0]~T[len-1]与T[j-len]~T[j-1]if(T[i]!=T[j-len+i])break;if(i==len){next[j]=len;break;}}if(len<1)next[j]=0;                   //其他情况,无子串相等}
}
int KMP(char S[],char T[]){int i=0,j=0;int next[80];      //假定模式最长为80个字符GetNext(T,next);while(S[i]!='\0'&&T[j]!='\0'){if(S[i]==T[j]){i++;j++;}else{j=next[j];if(j==-1){i++;j++}}}if(T[j]=='\0') return (i-strlen(T)+1);       //返回本趟匹配的开始位置else return 0;
}

BF算法和KMP算法详解相关推荐

  1. BF算法和KMP算法

    给定两个字符串S和T,在主串S中查找子串T的过程称为串匹配(string matching,也称模式匹配),T称为模式.这里将介绍处理串匹配问题的两种算法,BF算法和KMP算法. BF算法 (暴力匹配 ...

  2. Algorithm:C++语言实现之字符串相关算法(字符串的循环左移、字符串的全排列、带有同个字符的全排列、串匹配问题的BF算法和KMP算法)

    Algorithm:C++语言实现之字符串相关算法(字符串的循环左移.字符串的全排列.带有同个字符的全排列.串匹配问题的BF算法和KMP算法) 目录 一.字符串的算法 1.字符串的循环左移 2.字符串 ...

  3. 若S作主串,P作模式串,试分别写出利用BF算法和KMP算法的匹配过程。

    目   录 题目: 百度文库-答案: (1) (2) MOOC标准答案: (1) (2) mooc答案-截图: 数据结构(C语言版)-严蔚敏2007 题目: 设字符串S='aabaabaabaac', ...

  4. A算法和A*算法详解

    字太多了 直接放笔记的图片吧,如有不对请指正 A算法和A*算法都适用 1.用初始节点初始化搜索图G (动态变化),将初始节点放入open表(还没有扩展的节点)中,然后初试closed(已经扩展完成的节 ...

  5. 【算法篇-字符串匹配算法】BF算法和KMP算法

    目录 前言 1. BF算法 1.1 画图分析 1.3 BF 算法的时间复杂度 2. KMP 算法 2.1 KMP 算法和 BF 算法 的区别 2.1.1 为什么主串不回退? 2. 2 next 数组 ...

  6. 数据结构之字符串匹配算法(BF算法和KMP算法)

    字符串匹配算法: 就是给定两个串,主串(s)和子串(sub), 查找子串是否在主串里面,如果找到便返回子串在主串中第一个元素的位置下标,否贼返回-1,. 在这里我 们讨论的时候主要用字符串来举例实现. ...

  7. 字符串匹配—BF算法和KMP算法

    BF算法 本章重点是是KMP算法,但是由于其较难理解,先从更简单朴素的BF算法开始. 其思路非常简单 也就是,对这样两个字符串(称短的为模式串,长的为主串): 让主串和模式串的每个字符逐个匹配,如果从 ...

  8. 模式串匹配的BF算法和KMP算法

    KMP是三位大牛:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的.为了解决模式匹配问题,也即寻找模式串(子串)在主串中第一次出现的位置,若模式串在主串中不存在则返回-1. 简单 ...

  9. 串的BF算法和KMP算法个人总结

    子串(模式串)的定位操作通常称作串的模式匹配 其中包含最初始的BF算法(Brute-Force)即简单匹配算法或者称作朴素的模式匹配算法,利用穷举法的思路 另一种就是改进后的KMP算法,还有对KMP算 ...

  10. Dijkstra算法和Floyd算法详解(MATLAB代码)

    一.Dijkstra算法 1.算法简介 Dijkstra算法是由E.W.Dijkstra于1959年提出,又叫迪杰斯特拉算法,它应用了贪心算法模式,是目前公认的最好的求解最短路径的方法.算法解决的是有 ...

最新文章

  1. 大一新生,你为何逃课?
  2. Script:列出数据库中子表上没有对应索引的外键
  3. 微信小程序AES加密解密
  4. 精通python能干什么-Python学到什么程度才算精通?天津Python培训
  5. 算法导论之红黑树的学习
  6. JavaScript核心语法总结
  7. 9张表格学会,子网划分
  8. Linux之后台运行(nohup和)
  9. 3D特征:关于HFM和HBB
  10. 前端学习(684):循环导读
  11. java 第二天,Java复习第二天
  12. 安装完centos6没有eth0,只有回环地址
  13. 使用PowerShell和SQL的示例可用性监视服务的插图
  14. 读邹欣老师《师生关系》有感
  15. Laravel中的日志与上传
  16. 机器学习:使用python生成训练集和测试集的方法实现
  17. 基于hilbert变换的数字信号_通过Hilbert变换实现移相算法
  18. led灯光衰怎么解决_影响LED灯具光衰的原因及解决方法
  19. JavaScript throw 语句
  20. 管理者如何抓绩效管理?

热门文章

  1. 在VS2017中添加WTL窗口
  2. effect和watch 的区别详解
  3. 如何查看路由器中的宽带密码
  4. build Variants创建不同配置的app(图文详解)
  5. Java坑人面试题系列: 包装类(中级难度)
  6. OCLint + Infer + Jenkins + SonarQube 搭建iOS代码静态分析系统
  7. fastlane二开java_iOS中使用Fastlane实现自动化打包和发布
  8. Combating the Elsagate Phenomenon: Deep Learning Architectures for Disturbing Cartoons
  9. Java常用类--java.lang.StringBuilder
  10. Win7开机提示任务管理器已停止工作解决方法