朴素串匹配算法说明

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

为了更好理解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. EasyUI-datagrid-自动合并单元格(转)

    1.目标 1.1表格初始化完成后,已经自动合并好需要合并的行: 1.2当点击字段排序后,重新进行合并: 2.实现 2.1 引入插件 /** * author ____′↘夏悸 * create dat ...

  2. java代码中后台向前台传递list或map集合案例

    导入jar包 新建一个servert传递map集合 ajax.java代码: package servlet; import java.io.IOException; import java.io.P ...

  3. Heka–>Elasticsearch 索引数据过程的优化

    Heka 的参数配置跟Elasticsearch的参数没有关系,Heka只负责按照配置发送数据,所以索引的优化主要在 Elaticsearch端来完成. 下面是Elasticsearch的一些相关概念 ...

  4. [kuangbin带你飞]专题十 匹配问题

        A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找     ID Origin Title   61 / 72 Problem A HD ...

  5. Intent Receiver

    使用Intent Receiver让自己的应用对一个外部事件做出响应,比如当电话呼入时,或者当数据网络可用时,或者时间到晚上了.Intent Receiver不能显示用户界面,它只能通过Notific ...

  6. iOS UIButton 设置图片文字垂直排列

    后面经过测试,如果button的文字长度变更,会导致图片位置变化,经过多次修改UIEdgeInsets的值也没有达到期望效果,最终采用集成UIButton类,重写layoutSubviews函数实现, ...

  7. css列表

    列表是有三种形式: 1.无序列表,用来表示一个列表语义,并且每个项目与项目之间是不分先后顺序的 ul 的英文unordered list "无序列表" li  的英文  list ...

  8. [转载]:Endnote 自定义style文件的默认位置

    一般而言,安裝完EndNote 後,預設Output Styles.Filters.Connection Files 的電腦存放路徑如下–   C:\Program Files\EndNote X4 ...

  9. centos7 docker1.12 私有仓库

    docker1.12私有仓库 参考:http://www.cnblogs.com/xcloudbiz/articles/5497037.html 参考:http://www.07net01.com/2 ...

  10. Loadrunner:error -86401 Failed to connceted xxx.xxx.xxx.xxx:25问题解决

    [转自:http://www.51testing.com/html/00/130600-3578408.html]windows 2003上安装的LoadRunner11做为负载机在SMTP协议压测时 ...