美文网首页
数据结构与算法-字符串匹配之KMP算法

数据结构与算法-字符串匹配之KMP算法

作者: MrDemon_ | 来源:发表于2020-05-18 00:45 被阅读0次

KMP描述:
KMP 算法 是由 D.E.Knuth,J.H.Mores 和 VR.Pratt共同发表模式匹配算法,称之克鲁特-莫里斯-普拉特算法。简称 KMP 算法,可以大大避免重复遍历的情况
KMP思路:

  1. 遍历模式串S,i 是用来标记主串的索引; 遍历模式串T, j 是用来标记模式串的索引;
  2. 结束条件是当i > S.length 和 j > T.length;
    (1)如果 i > S.length 但是j 却小于T.length 表示遍历了整个主串,都没有找到与模 式串匹配的情况
    (2)只有1种可能,就是j > T.length 表示,已经在主串中找到模式串了.
    因为你已经顺 利的把T模式串中的每个字符串正常的依次比较下去了,直到它结束;
  3. 当 j = 0 时,表示此时你需要将模式串从1这个位置与主串i+1这个位置开始比较;
  4. 当 T[i] == T[j], 表示此时当前模式串j 与 主串i 这个2个字符是相等,则j++,i++;
  5. 当 j != 0 并且T[i] != T[j] 时,表示此时需要移动模式串的 j ,那么我们让 j = next[j]; 来节省重复的比较次数;

代码实现

#include "string.h"
#include "stdio.h"
#include "stdlib.h"

#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */

typedef int Status;        /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;    /* ElemType类型根据实际情况而定,这里假设为int */
typedef char String[MAXSIZE+1]; /*  0号单元存放串的长度 */

//----字符串相关操作---
/* 生成一个其值等于chars的串T */
Status StrAssign(String T,char *chars)
{
    int i;
    if(strlen(chars)>MAXSIZE)
        return ERROR;
    else
    {
        T[0]=strlen(chars);
        for(i=1;i<=T[0];i++)
            T[i]=*(chars+i-1);
        return OK;
    }
}

Status ClearString(String S)
{
    S[0]=0;/*  令串长为零 */
    return OK;
}

/*  输出字符串T。 */
void StrPrint(String T)
{
    int i;
    for(i=1;i<=T[0];i++)
        printf("%c",T[i]);
    printf("\n");
}

/* 返回串的元素个数 */
int StrLength(String S)
{
    return S[0];
}

//----KMP 模式匹配算法---
//1.通过计算返回子串T的next数组;
//注意字符串T[0]中是存储的字符串长度; 真正的字符内容从T[1]开始;
void get_next(String T,int *next){
    int i,j;
    j = 1;
    i = 0;
    next[1] = 0;
    //abcdex
    //遍历T模式串, 此时T[0]为模式串T的长度;
    //printf("length = %d\n",T[0]);
    while (j < T[0]) {
        //printf("i = %d j = %d\n",i,j);
        if(i ==0 || T[i] == T[j]){
            //T[i] 表示后缀的单个字符;
            //T[j] 表示前缀的单个字符;
            ++i;
            ++j;
            next[j] = i;
            //printf("next[%d]=%d\n",j,next[j]);
        }else
        {
            //如果字符不相同,则i值回溯;
            i = next[i];
        }
    }
}

//输出Next数组值
void NextPrint(int next[],int length)
{
    int i;
    for(i=1;i<=length;i++)
        printf("%d",next[i]);
    printf("\n");
}

int count = 0;
//KMP 匹配算法(1)
//返回子串T在主串S中第pos个字符之后的位置, 如不存在则返回0;
int Index_KMP(String S,String T,int pos){
    
    //i 是主串当前位置的下标准,j是模式串当前位置的下标准
    int i = pos;
    int j = 1;
    
    //定义一个空的next数组;
    int next[MAXSIZE];
    
    //对T串进行分析,得到next数组;
    get_next(T, next);
    count = 0;
    //注意: T[0] 和 S[0] 存储的是字符串T与字符串S的长度;
    //若i小于S长度并且j小于T的长度是循环继续;
    while (i <= S[0] && j <= T[0]) {
        
        //如果两字母相等则继续,并且j++,i++
        if(j == 0 || S[i] == T[j]){
            i++;
            j++;
        }else{
            //如果不匹配时,j回退到合适的位置,i值不变;
            j = next[j];
        }
    }
    
    if (j > T[0]) {
        return i-T[0];
    }else{
        return -1;
    }
    
}

//KMP 匹配算法(2)
//求模式串T的next函数值修正值并存入nextval数组中;
void get_nextVal(String T,int *nextVal){
    int i,j;
    j = 1;
    i = 0;
    nextVal[1] = 0;
    while (j < T[0]) {
        if (i == 0 || T[i] == T[j]) {
            ++j;
            ++i;
            //如果当前字符与前缀不同,则当前的j为nextVal 在i的位置的值
            if(T[i] != T[j])
                nextVal[j] = i;
            else
            //如果当前字符与前缀相同,则将前缀的nextVal 值赋值给nextVal 在i的位置
                nextVal[j] = nextVal[i];
        }else{
            i = nextVal[i];
        }
    }
}

//KMP 匹配算法(2)
//返回子串T在主串S中第pos个字符之后的位置, 如不存在则返回0;
int Index_KMP2(String S,String T,int pos){
    
    //i 是主串当前位置的下标准,j是模式串当前位置的下标准
    int i = pos;
    int j = 1;
    
    //定义一个空的next数组;
    int next[MAXSIZE];
    
    //对T串进行分析,得到next数组;
    get_nextVal(T, next);
    count = 0;
    //注意: T[0] 和 S[0] 存储的是字符串T与字符串S的长度;
    //若i小于S长度并且j小于T的长度是循环继续;
    while (i <= S[0] && j <= T[0]) {
        
        //如果两字母相等则继续,并且j++,i++
        if(j == 0 || S[i] == T[j]){
            i++;
            j++;
        }else{
            //如果不匹配时,j回退到合适的位置,i值不变;
            j = next[j];
        }
    }
    
    if (j > T[0]) {
        return i-T[0];
    }else{
        return -1;
    }
    
}


int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, KMP匹配算法实现!\n");
    int i,*p,*t;
    String s1,s2;
    int Status;
    
    /*关于next数组的求解*/
    StrAssign(s1,"aaaaax");
    printf("子串为: ");
    StrPrint(s1);
    i=StrLength(s1);
    p=(int*)malloc((i+1)*sizeof(int));
    get_next(s1,p);
    printf("Next为: ");
    NextPrint(p,StrLength(s1));
    t=(int*)malloc((i+1)*sizeof(int));
    get_nextVal(s1, t);
    printf("NextVal为: ");
    NextPrint(t,StrLength(s1));
    printf("\n");
    
    //KMP算法调用
    StrAssign(s1,"abcababca");
    printf("主串为: ");
    StrPrint(s1);
    StrAssign(s2,"abcdex");
    printf("子串为: ");
    StrPrint(s2);
    Status = Index_KMP(s1,s2,1);
    printf("主串和子串在第%d个字符处首次匹配(KMP算法)[返回位置为负数表示没有匹配] \n",Status);
    Status = Index_KMP2(s1, s2, 1);
    printf("主串和子串在第%d个字符处首次匹配(KMP_2算法)[返回位置为负数表示没有匹配] \n\n",Status);
    
    StrAssign(s1,"abccabcceabc");
    printf("主串为: ");
    StrPrint(s1);
    StrAssign(s2,"abcce");
    printf("子串为: ");
    StrPrint(s2);
    Status = Index_KMP(s1,s2,1);
    printf("主串和子串在第%d个字符处首次匹配(KMP算法)[返回位置为负数表示没有匹配] \n",Status);
    Status = Index_KMP2(s1, s2, 1);
    printf("主串和子串在第%d个字符处首次匹配(KMP_2算法)[返回位置为负数表示没有匹配] \n\n",Status);
    
    StrAssign(s1,"aaaabcde");
    printf("主串为: ");
    StrPrint(s1);
    StrAssign(s2,"aaaaax");
    printf("子串为: ");
    StrPrint(s2);
    Status = Index_KMP(s1,s2,1);
    printf("主串和子串在第%d个字符处首次匹配(KMP算法)[返回位置为负数表示没有匹配] \n",Status);
    Status = Index_KMP2(s1, s2, 1);
    printf("主串和子串在第%d个字符处首次匹配(KMP_2算法)[返回位置为负数表示没有匹配] \n\n",Status);
    
    
    return 0;
}

相关文章

  • KMP算法文章合集

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

  • 字符串匹配算法

    以下为学习 《数据结构与算法之美 -- 字符串匹配》 的记录。 BF算法 即暴力匹配算法,循环遍历匹配。 RK算法...

  • 深入解析KMP算法

    标签(空格分隔): 数据结构与算法 KMP算法是一个经典的字符串匹配算法,但是原理比较晦涩难懂,这里推荐一篇个人感...

  • leetcode字符串匹配算法之KMP算法

    本篇介绍一种高效的字符串匹配算法——KMP算法。 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J....

  • 数据结构与算法——基础篇(一)

    前置问题 经典问题与算法 8皇后问题(92种摆法)——回溯算法 字符串匹配问题——KMP算法(取代暴力匹配) 汉诺...

  • 字符串匹配与KMP算法

    1.朴素字符串匹配算法 2.KMP算法 求前缀函数 实现KMP算法 3.测试代码

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

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

  • KMP算法

    字符串匹配算法之KMP KMP算法最主要的地方是求next数组,next数组保存的是当前失配节点(下标index)...

  • KMP字符串匹配算法

    KMP字符串匹配算法 先总结一下之前的几种字符串匹配算法 1 BF算法, 最简单的字符串匹配算法, 可以直接使用s...

  • KMP算法

    KMP算法是解决字符串匹配问题的有高效算法 代码:

网友评论

      本文标题:数据结构与算法-字符串匹配之KMP算法

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