zoukankan      html  css  js  c++  java
  • 如何借助BM算法轻松理解KMP算法

      KMP 算法是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Pratt)的名字来命名的,算法的全称是 Knuth Morris Pratt 算法,简称为 KMP 算法。

      KMP 算法的核心思想,跟上一节讲的BM算法非常相近。我们假设主串是 a,模式串是 b。在模式串与主串匹配的过程中,当遇到不可匹配的字符的时候,我们希望找到一些规律,可以将模式串往后多滑动几位,跳过那些肯定不会匹配的情况。

      这里我们可以类比一下,在模式串和主串匹配的过程中,把不能匹配的那个字符仍然叫作坏字符,把已经匹配的那段字符串叫作好前缀。

      KMP 算法的时间复杂度是 O(n+m)。其中求next数组(失效函数)比较难理解,建议阅读大话数据结构p139的例子。

    C++版代码如下

    #include <iostream>
    #include <math.h>
    #include <cstring>
    using namespace std;
    
    #define MAXNUM 256
    
    // 朴素字符串匹配
    // 查找子串b在主串a中第pos个字符之后的位置,其中0<= pos <= n-1
    int indexBasical(char a[], int n, char b[], int m, int pos){
        int i = pos;
        int j = 0;
        while(i < n && j < m){
            if(a[i] == b[j]){
                i++;
                j++;
            }
            else{
                i = i - j + 1;
                j = 0;
            }
        }
        if(j >= m)
            return i - m;
        else
            return -1;
    }
    
    // KMP匹配算法
    // 计算next失效函数
    void getNext(char b[], int m, int next[]){
        int i, j;
        i = 0;
        j = -1;
        next[0] = -1;
        while(i < m - 1){
            if(j == -1 || b[i] == b[j]){
                i++;
                j++;
                next[i] = j;
            }
            else{
                // 若字符不相同,则j值回溯
                j = next[j];
            }
        }
    }
    
    int indexKMP(char a[], int n, char b[], int m, int pos){
        int i = pos;
        int j = 0;
        int next[MAXNUM];
        memset(next, 127, sizeof(next));
        getNext(b, m, next);
        while(i < n && j < m){
            // 相对于BF(朴素匹配)算法增加了j=-1判断
            if(j == -1 || a[i] == b[j]){
                i++;
                j++;
            }
            else
                // 相对于BF算法,i并不会回溯,并且j不会退回到0,而是退回到合适的位置
                j = next[j];
        }
        if(j >= m)
            return i - m;
        else
            return -1;
    }
    
    
    int main()
    {
        int next[MAXNUM];
        memset(next, 127, sizeof(next));
        char a[10] = "oodgoogle";
    
        memset(next, 127, sizeof(next));
        char c[7] = "google";
        getNext(c, 6, next);
    
        // BF算法
        cout<<indexBasical(a, 9, c, 6, 0)<<endl;
        // KMP算法
        cout<<indexKMP(a, 9, c, 6, 0);
        return 0;
    }
    
  • 相关阅读:
    (转)SpringBoot使用@Value给静态变量注入
    关于Oracle to_date函数的高级用法
    Nginx实践篇(5)- Nginx代理服务
    SpringBoot @Autowired中注入静态方法或者静态变量
    SpringBoot MAVEN编译报错Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:
    SpringBoot项目中禁用HttpClient那些嘈杂的日志
    生成SQL Server数据字典
    SqlServer 查看最近执行过的语句
    为二级域名注册ssl证书,并强制使用https对http进行跳转
    CentOS 7 配置nginx并默认强制使用https对http进行跳转
  • 原文地址:https://www.cnblogs.com/flyingrun/p/13466797.html
Copyright © 2011-2022 走看看