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;
    }
    
  • 相关阅读:
    C++中迭代器失效的问题
    怎么转载别人的博客
    Linux下模拟实现shell
    Linux下的文件描述符与文件指针及其区别
    智能指针
    C++模板(下)
    C++中的模板(上)
    僵尸进程和孤儿进程
    Linux下的atexit函数
    多线程练习
  • 原文地址:https://www.cnblogs.com/flyingrun/p/13466797.html
Copyright © 2011-2022 走看看