KMP算法

作者: 王王王王王景 | 来源:发表于2019-08-21 14:16 被阅读0次

kmp.hpp

//
//  kmp.hpp
//  test
//
//  Created by 王璟 on 2019/4/17.
//  Copyright © 2019年 王璟. All rights reserved.
//

#ifndef kmp_hpp
#define kmp_hpp

#include <iostream>
#include <string>
using namespace std;

int* get_next(const string& T);
int* get_nextval(const string& T);
int index_kmp(const string& S, const string& T, int *next);
int get_index(const string& S, const string& T);
#endif /* kmp_hpp */

kmp.cpp

//
//  kmp.cpp
//  test
//
//  Created by 王璟 on 2019/4/17.
//  Copyright © 2019年 王璟. All rights reserved.
//

#include "kmp.h"

/*
 算法讲解:
    KMP算法主要是通过模式串自身生成一个next数组,在模式串和主串匹配不上的时候利用next数组尽可能的向右推进一部分距离,
 因为模式串里面可能存在部分相同区域(例如ABA),主串要是已经完成了第二个A区域的匹配,那么模式串只需要回到第一个A的位置继续与主串匹配,而不是直接回到一开始进行匹配,
 算法的时间复杂度在O(m+n)
 */


/*
 KMP算法中获取模式串T的next数组
|   j  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|   p  | a | b | a | a | b | c | a | c |
| next | 0 | 0 | 0 | 1 | 1 | 2 | 0 | 1 |

 next[0] = 0, next[1] = 0;
 后面的next的值要看从该坐标前面的和0开始的串能匹配多少个;
 eg:坐标为 3的‘a’,前面是坐标为2的‘a’,与0开始的串匹配到了长度为1的串‘a’,因此其next[4] = 1
     坐标为5的‘c’,前面是“ab”匹配z坐标0到1的“ab”,因此其next值为2
*/
int* get_next(const string& T)
{
    int T_len = T.size();
    int *next = new int[T_len];
    next[0] = 0;
    next[1] = 0;
    int i = 0, j = 0; // i为快下标 j为慢下标(为了完成模式串中例如ABA中A与A的匹配)
    for(i = 2; i < T_len;){
        if(T[i-1] == T[j]){
            // 如果当前快下标i的前一个元素T[i-1]和慢下标T[j]匹配上了,
            // 那么证明该快下标i对应next[i]数组的数值为j+1,到时候可以直接回到j+1的位置,因为前面已经成功匹配过一次了
            next[i] = ++j;  
            ++i;
        }else if(0 == j){
            // 如果此时存在 T[j] != T[i-1],当快下标的前一个元素和慢下标元素没有匹配上,而且此时的慢下标j==0,
            // 那么当前的next数值肯定为0,说明当前快下标前面的元素都没有完成一个与慢下标的匹配关系,那么就只能直接回到下标为0的位置重新匹配
            next[i] = 0;
            ++i;
        }else{
            // 如果此时存在 T[j] != T[i-1] 同时 j!=0那么将j进行回溯
            j = next[j];
        }
    }
    return next;
}


// 改进的KMP算法中获取模式串T的next数组
/*
 改进的KMP算法主要针对于"aaaab"这种类型进行了优化,在原来next数组里面为0 0 1 2 3,
 但是在模式串与主串aaaacaaaab的匹配中,第一次匹配到T[j=4] = b, T[i=4] = c的时候m,两者匹配不成功,
 此时如果利用next数组的话,就是先回到3->2->1->0;但是我们可以发现T[3] = T[2] = T[1] = T[0]都是等于a的,可以直接从3就回到了0;
 所以在构造改进的nextval的时候,在匹配上的时候,需要注意如果我们发现T[i] = T[j+1]的时候,直接让nextval[i] = nextval[++j];
 分析:在匹配上的时候,如果我们当前的T[i]在原有的算法里面是直接next[i] = ++j; 如果T[i] == T[j+1]的话,主串在匹配不上T[i]的时候同样等于直接匹配不上T[j+1],所以存在如上的结果;
 (要注意j的数值还是要继续前进的),只要存在匹配成功的情况,都要将匹配的信息保留在j中
 */
int* get_nextval(const string& T)
{
    int T_len = T.size();
    int *nextval = new int[T_len];
    nextval[0] = 0;
    nextval[1] = 0;
    int i = 0, j = 0; // i为快下标 j为慢下标(为了完成模式串中例如ABA中A与A的匹配)
    for(i = 2; i < T_len;){
        if(T[i-1] == T[j]){
            // 如果当前快下标i的前一个元素T[i-1]和慢下标T[j]匹配上了,
            // 那么证明该快下标i对应next[i]数组的数值为j+1,到时候可以直接回到j+1的位置,因为前面已经成功匹配过一次了
            if(T[i] == T[j+1]) nextval[i] = nextval[++j];
            else nextval[i] = ++j;
            ++i;
        }else if(0 == j){
            // 如果此时存在 T[j] != T[i-1],当快下标的前一个元素和慢下标元素没有匹配上,而且此时的慢下标j==0,
            // 那么当前的next数值肯定为0,说明当前快下标前面的元素都没有完成一个与慢下标的匹配关系,那么就只能直接回到下标为0的位置重新匹配
            nextval[i] = 0;
            ++i;
        }else{
            // 如果此时存在 T[j] != T[i-1] 同时 j!=0那么将j进行回溯
            j = nextval[j];
        }
    }
    return nextval;
}

// 通过KMP算法进行模式串和主串的匹配,返回第一次匹配成功的下标(没有匹配成功返回-1)
int index_kmp(const string& S, const string& T, int *next)
{
    int i = 0, j = 0;
    while(i < S.size() && j < T.size()){
        if(S[i] == T[j]){ // 匹配上的时候
            ++i;
            ++j;
        }else{
            if(0 == j) ++i; // 全部都匹配不上的时候主串需要向前移动了
            else j = next[j];
        }
    }
    if(j >= T.size()){ // 表示完成匹配
        return  i - j;
    }else return -1;
}


// 普通匹配算法
int get_index(const string& S, const string& T)
{
    int i = 0, j = 0;
    while(i < S.size() && j < T.size())
    {
        if(S[i] == T[j]){
            ++i;
            ++j;
        }else{
            i = i - j + 1;
            j = 0;
        }
    }
    if(j >= T.size()) return i - j;
    else return -1;
}

相关文章

  • KMP 专题整理

    KMP 学习记录 kuangbin专题十六——KMP KMP 学习总结 朴素 KMP 算法 拓展 KMP 算法(E...

  • 对KMP算法的一些理解

    最近学到KMP算法,下面讲讲对KMP算法的一些个人理解,希望对大家有帮助! 对于KMP算法的理解: 整个KMP算法...

  • KMP算法文章合集

    字符串的查找:朴素查找算法和KMP算法 暴力匹配算法与KMP算法(串的匹配) 字符串查找算法BF和KMP 字符串匹...

  • 串的模式匹配算法

    KMP算法 算法匹配

  • 问答|KMP算法学习笔记

    问题 目录KMP是什么,做什么用的KMP算法的高效体现在哪如何KMP算法的next数组KMP的代码KMP的时间复杂...

  • KMP算法——寻找子串位置

    KMP算法——寻找子串位置 1、KMP算法简介: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J....

  • 字符串匹配 - KMP算法

    前面我们介绍非常高效的 BM 算法,今天我们介绍另一个非常出名且高效的 KMP 算法。 KMP 算法思想 KMP ...

  • KMP算法及优化

    转载请注明出处: KMP算法及优化 今天看到同学在复习数据结构书上的KMP算法,忽然发觉自己又把KMP算法忘掉了,...

  • KMP算法(字符串匹配问题)

    一、是什么? 注意,是KMP算法,不是MMP哈,我没有骂人。KMP算法是用来做字符串匹配的,除了KMP算法分,还有...

  • KMP算法

    KMP算法

网友评论

      本文标题:KMP算法

      本文链接:https://www.haomeiwen.com/subject/qlvbsctx.html