朴素串匹配算法说明

串匹配算法最常用的情形是从一篇文档中查找指定文本。需要查找的文本叫做模式串,需要从中查找模式串的串暂且叫做查找串吧。

为了更好理解KMP算法,我们先这样看待一下朴素匹配算法吧。朴素串匹配算法是这样的,当模式串的某一位置失配时将失配位置的上一位置与查找串的该位置对齐再从头开始比较模式串的每一个位置。如下图所示。

KMP串匹配算法解析

KMP串匹配算法是Knuth-Morris-Pratt算法的简称,KMP算法的思想就是当模式串的某一位置失配时,能不能将更前面的位置与查找串的该位置对齐,并且直接从该位置开始比较。按照这个思路走,问题叫变成了:当模式串的某一位置失配时要找到一个更前面的位置与查找串的该位置对齐。模式串的某个位置失配时的这个更前面的位置就叫做回溯位,通常用next表示,它的计算公式是:

next[i]= { 0; 当 i = 1
                        k; 对于串P,存在1 <= k < 使得 P1..Pk-1 == Pi-k+1..Pi-1
                        1; 其他情况                                }

这个公式对应的串的下标是从1开始的。这个公式只说明:模式串中某一位置(不包含此位置)之前部分具有首尾相同的子串(即自匹配,比如ABCABA最后一个A之前头部和尾部都包含了子串AB)时,如果该位置失配可以直接将头部子串的下一个位置和该处对齐(比如模式串ABCABA在最后一个A处失配可以直接滑动模式串将C对齐原来最后那个A对齐的位置),这样可以去掉模式串在某位置失配时该位置之前的子串在朴素匹配算法中存在的冗余比较(如果用朴素匹配算法,需要将模式串ABCABA移动三次才能使得C对齐原来最后那个A对齐的位置)。模式串中某一位置(不包含此位置)之前部分不具有首尾相同的子串时,在该位置失配时可以直接让模式串的开始位置对齐该位置。如下图。

这里只给出了算法的说明,但是如何能够证明算法是正确的呢?这个说麻烦也麻烦,说简单也简单。为什么麻烦呢?因为我没办法用形式化的语言给出证明过程,就像数学里面的证明过程一样。其实自己通过形象思维演示一下串匹配的滑动过程就能够相信这个算法肯定是正确的。我也懒得给出证明过程。

接下来给出KMP算法的完整代码。

#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <cstdlib>

using namespace std;

void get_next(const string & M,vector<int> & next);

int  KMP_match(const string & S,const string & M,int pos);

int main( )
{
    string S="abcdefghabcdefghhiijiklmabc";
    string T="hhiij";
    );

    cout<<"\n"<<pos<<endl;
    system("pause");
    ;
}

void get_next(const string & M,vector<int> & next)
{
    //按模式串生成vector<int> next(M.size(),-1);
    //这里的串的第1个元素下标是0
    , j = ;
    ;
    do
    {
     ) || (M[i] == M[j]))
     {
      i++; j++;
      next[j] = i;
     }
        else
      i = next[i];
  cout<<)<<i
            <<)<<j
            <<)<<next[j]<<endl;
     }while( j < M_len);
}

int  KMP_match(const string & S,const string & M,int pos)
{
    ;//这里的串的第1个元素下标是0
    int S_len = S.size();
    int M_len = M.size();

    if((S_len-pos) < M_len)
        ;

    vector<);

    get_next(M,next);

    while (i<M_len && j<S_len)
    {
         || S[j]==M[i])
        {
            ++i;
            ++j;
        }
        else i = next[i];//j不变,i跳动
    }   

    if (i == M_len) return j-i;//匹配成功
    ;
}

KMP串匹配算法的优化

接着看上面EBAEB的匹配例子。其中第2次比较根本没有必要,可以直接跳到第3次。这次比较有一个特点:当模式串滑过一段距离后模式串中参与比较的字符和前次参与比较的字符相同,都是B。按照上面那个公式求上述模式串回溯位置时的一个情形如下:

此时确定的是模式串中索引为4的元素失配时模式串的回溯位置,这时索引位下一个元素和比较位的下一个元素相同(都为B)。同时这也是模式串中索引为4的字符失配后滑动完成的情形,即最后一个B和查找串种的D不匹配时,由于next[4] = 1,需要把索引为1的字符(就是第2个字符)B对其到D。但是这个B和D是不是已经比较过一次了啊。这是因为不仅模式串失配位置之前的部分能够自匹配,而且模式串中包含失配位置的之前部分也能自匹配。模式串中包含失配位置的之前部分组成的子串也具有相同的首尾时,失配位置的回溯位置可以直接采用首部字串的回溯位置,对于串EBAEB,可以让next[4]直接等于next[1]。那么优化的next函数如下:

             next[i]= { ; 当i =
                        k; 对于串P,存在1 <= k < 使得 P1..Pk- == Pi-k+..Pi- & Pk != Pi
                        next[k]; 对于串P,存在  <= k < i使得 P1..Pk == Pi-k..Pi
                        ; 其他情况                                      }

接下来给出改进后的就next数组的代码。

void get_next(const string & M,vector<int> & next)
{
    //按模式串生成vector<int> next(M.size(),-1);
    //这里的串的第1个元素下标是0
    , j = ;
    ;

    do
    {
     ) || (M[i] == M[j]))
     {
      i++; j++;
                if(M[i] != M[j])
          next[j] = i;
                else  next[j] = next[i];
 }
        else
  i = next[i];
     }while( j < M_inx);
}

KMP串匹配算法解析与优化的更多相关文章

  1. KMP算法解析(转自图灵社区)

    KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载 ...

  2. 串匹配算法讲解 -----BF、KMP算法

      参考文章: http://www.matrix67.com/blog/archives/115     KMP算法详解 http://blog.csdn.net/yaochunnian/artic ...

  3. BM串匹配算法

    串匹配算法最常用的情形是从一篇文档中查找指定文本.需要查找的文本叫做模式串,需要从中查找模式串的串暂且叫做查找串吧. BM算法好后缀规则 公式: 对于长度为m的模式串P,在i处失配时,模式串向前滑动的 ...

  4. KMP(Knuth-Morris-Pratt)算法

    一.朴素匹配算法 也就是暴力匹配算法.设匹配字符串的长度为n,模式串的长度为m,在最坏情况下,朴字符串匹配算法执行时间为O((n - m + 1)m). 假设m = n / 2, 那么该算法的复杂度就 ...

  5. 地理围栏算法解析(Geo-fencing)

    地理围栏算法解析 http://www.cnblogs.com/LBSer/p/4471742.html 地理围栏(Geo-fencing)是LBS的一种应用,就是用一个虚拟的栅栏围出一个虚拟地理边界 ...

  6. python常见排序算法解析

    python——常见排序算法解析   算法是程序员的灵魂. 下面的博文是我整理的感觉还不错的算法实现 原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode 本篇主要实现九(八)大排序算法 ...

  7. GBDT+LR算法解析及Python实现

    1. GBDT + LR 是什么 本质上GBDT+LR是一种具有stacking思想的二分类器模型,所以可以用来解决二分类问题.这个方法出自于Facebook 2014年的论文 Practical L ...

  8. 区块链~Merkle Tree(默克尔树)算法解析~转载

    转载~Merkle Tree(默克尔树)算法解析 /*最近在看Ethereum,其中一个重要的概念是Merkle Tree,以前从来没有听说过,所以查了些资料,学习了Merkle Tree的知识,因为 ...

  9. 程序员收藏必看系列:深度解析MySQL优化(二)

    程序员收藏必看系列:深度解析MySQL优化(一) 性能优化建议 下面会从3个不同方面给出一些优化建议.但请等等,还有一句忠告要先送给你:不要听信你看到的关于优化的“绝对真理”,包括本文所讨论的内容,而 ...

随机推荐

  1. EXt form属性

    配置项: success:执行成功后回调的函数,包括两个参数:form和action failure:执行失败后回调的函数,包括两个参数:form和action method:表单的提交方式,有效值包 ...

  2. [SQL]分组排练进行更新

    --方法(一):分组排练进行更新 ----------------------------------------------------------------------------------- ...

  3. 推荐一个代码生成工具:freemarker

    freemarker:http://freemarker.org/ 还有velocity:http://velocity.apache.org/

  4. 合并 hdfs 文件

     待研究,只做保存 将HDFS中不同目录下面的数据合在一起,并存放在指定的目录中,示例如: sqoop merge –new-data /test/p1/person –onto /test/p2 ...

  5. DragonBone在FlashDevelop编译

    http://dragonbones.github.io/ dragonbones是一个强大的骨骼动画编辑器,基于Starling,用AS3语言编写,可以导出骨骼动画数据供其他程序使用. 下面来讲一下 ...

  6. 慕课网-安卓工程师初养成-4-6 Java条件语句之 switch

    来源:http://www.imooc.com/code/1358 当需要对选项进行等值判断时,使用 switch 语句更加简洁明了.例如:根据考试的名次,给予前 4 名不同的奖品.第一名,奖励笔记本 ...

  7. 怎样用VB编写.DLL动态链接库文件

    VB一般可以生成两种特殊的DLL,一个是ActiveX DLL和ActiveX Control(*.ocx).这两种DLL都是VB支持的标准类型,在VB自身的例子中有,你可以参考.更详细的介绍可以参考 ...

  8. python --那些你应该知道的知识点

    1.python函数参数(含星号参数)http://blog.useasp.net/archive/2014/06/23/the-python-function-or-method-parameter ...

  9. dell ipmi sol

    http://blog.arnoudvermeer.nl/post/52375062605/howto-setup-ipmi-sol-on-a-dell-r-series-server http:// ...

  10. Bypass pattern lock on Sony Xperia Z2 and backup all data

    Yesterday she came to me with a Sony Xperia Z2 D6503. Guess what? She forgot the pattern so she coul ...