zoukankan      html  css  js  c++  java
  • KMP算法完整教程 (上)

    KMP算法完整教程

    • 全称: Knuth_Morris_Pratt Algorithm(KMP算法)

    • 类型: 高级检索算法

    • 功能: 字符串匹配查找

    • 提出者: D.E.Knuth(克努兹),J.H.Morris(莫瑞斯),V.R.Pratt(普莱特)

    • 所属领域: 数据结构学

    • 应用场景: 统计软件

    • 时间复杂度: O(m+n)

    一。原始匹配字符串方法

        以前,我们要肉眼在一个长字符串中寻找一个关键字词,比如在word文档中找一个单词,我们的世界观决定的方法论就是穷举法:挨个搜寻单词的第一个字母,每找到一个就定位然后匹配下一个字母,当匹配错误时就会放弃之前的匹配,沿着刚才的进度继续搜索首字母.
    
    
    
       这种方法也叫作”暴力字符匹配”,和早期计算机检索算法共享着同样的思想,其中被检索的字符串数据库叫做”主串”,检索的字符串叫”模式串”.名字很怪异我也没办法.
    
        于是依照这种算法我们可以编写一个程序来实现它:
    
    int Index(SString S,SString T,int pos)
    
    {
    
      i=pos;j=1;
    
      while(i<=S[0]&&j<=T[0])
    
      {
    
        if(S[i]==T[j]){++i;++j;}
    
        else{i=i-j+2;j=1;}//主串指针回溯重新开始下一趟匹配.
    
      }
    
      if(j>T[0])return i-T[0];
    
      else return 0;
    
    }
    
    //返回模式串T在主串S第pos之后部分中的位置,若不存在则函数值为0.

    这里要注意i和j的指针回溯问题,注意细节,具体如下图:
    这里写图片描述
    然后问题就来了,这种算法在特定的情况下暴露出一些问题,在时间效率上不是很完美,因为它毕竟是一种穷举法,也符合人们的第一感觉,但是并不是最优的解决方案。比如说当在模式串中比较到第5个字符时才发现不匹配,那么之前四个字符都完全匹配,下一步就不需要再把模式串一位一位的向后移,而很可能直接把模式串向后移动四位就可以了,省去了三次比较,比如模式串是“aceddfaa”,主串是“acedabcd”的情况。

    二。初代KMP算法

       针对上面那个例子,我们可以展开思考,如果模式串匹配到第j个字符不匹配的话,接下来只需要在主串中这个位置从模式串中第f(j)的字符开始比较就行了,而不需要从第一个开始。而且f(j)只与模式串中第j个字符以前的所有字符有关。好了,这个f(j)我们用一个数组来存放,就是next【j】。求出next【j】就是KMP算法的核心。可以看出next【j】的值越小越好,优化的效率越高。
    

    KMP的next数组求法是很不容易搞清楚的一部分,也是最重要的一部分。我这篇文章就以我自己的感悟来慢慢推导一下吧!保证你看完过后是知其然,也知其所以然。

    如果你还不知道KMP是什么,请先阅读上面的链接,先搞懂KMP是要干什么。

    下面我们就来说说KMP的next数组求法。

    KMP的next数组简单来说,假设有两个字符串,一个是待匹配的字符串strText,一个是要查找的关键字strKey。现在我们要在strText中去查找是否包含strKey,用i来表示strText遍历到了哪个字符,用j来表示strKey匹配到了哪个字符。

    如果是暴力的查找方法,当strText[i]和strKey[j]匹配失败的时候,i和j都要回退,然后从i-j的下一个字符开始重新匹配。

    而KMP就是保证i永远不回退,只回退j来使得匹配效率有所提升。它用的方法就是利用strKey在失配的j为之前的成功匹配的子串的特征来寻找j应该回退的位置。而这个子串的特征就是前后缀的相同程度。

    所以next数组其实就是查找strKey中每一位前面的子串的前后缀有多少位匹配,从而决定j失配时应该回退到哪个位置。

    我知道上面那段废话很难懂,下面我们看一个彩图:
    这里写图片描述
    这个图画的就是strKey这个要查找的关键字字符串。假设我们有一个空的next数组,我们的工作就是要在这个next数组中填值。

  • 相关阅读:
    A New Approach to Line Simplification Based on Image Processing: A Case Study of Water Area Boundaries
    3D模型
    数码相机控制点的自动定位检校
    道路网匹配
    多线程操作数据拷贝要加线程锁
    编程琐事
    C++ 指定路径文件夹存在与否查询及文件夹创建
    C++ 网络编程之正确使用UDP广播及多播
    C++ 获得系统时间
    C++ 数据写入文件与读回
  • 原文地址:https://www.cnblogs.com/jinhengyu/p/10257812.html
Copyright © 2011-2022 走看看