• 字符串匹配_KMP算法_C语言



    在这里插入图片描述

    一、KMP是什么?

    KMP 算法(Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法
    KMP分别取三个学者名字的首字母
    KMP:当字符串出现不匹配的情况下,不再重复进行前一部分已经匹配成功的内容,避免从头匹配。

    二、前缀表

    前缀表是用来回退使用的,他记录了模式串和主串发生不匹配的时候,模式串应该从哪里开始重新匹配,应该回退几个。
    前缀表:记录下标i之前(包括i)的字符串中,有多大长度的相同前后缀,即最大公共前后缀

    前缀:指的是不包括最后一个字符的所有以第一个字符开头的连续子串
    后缀:指的是不包括第一个字符的所有以最后一个字符结尾的连续子串
    最长相等的前后缀的长度(最长公共前后缀):一个字符串中前后缀相等的最大长度
    在这里插入图片描述前缀表
    在这里插入图片描述

    使用前缀表进行匹配的过程:
    在这里插入图片描述开始匹配时,主串和模式串每个字符进行比对,比较完成后进行向后移动一位,进行比较,遇到冲突不匹配的位置,找模式串该位置前一位的子串的最长相等前后缀,这里的最长相等前后缀就记录在前缀表中,在以上例子中标红的2即为最长相等前后缀,意味着这里的后缀aa前面也有一个与之相等的aa。跳到前缀的后面的一个字符,前缀的后一个字符的下标即为前缀的长度(因为索引从0开始),模式串跳转到前缀后面的一个字符后,继续向后移动匹配,不在进行前面匹配成功字符串匹配。

    三、prefix和next数组

    prefix存放前缀表 ,next有时会对前缀表进行调整,两者都可以
    next数组有些进行右移一位 然后起始位置 “-1”
    有些进行将前缀表进行统一减1。
    有些也可以直接使用前缀表也可以完成KMP算法。
    只是对KMP的不同的实现,不必太过于纠结。

    四、代码部分

    #include<stdio.h>
    #include<string.h>
    
    void get_next(char *T, int next[]) {
        int strs_len = strlen(T);
        int i = 0, j = -1;
        next[0]=-1;
        while (i < strs_len) {  //遍历
            if (j == -1 || T[i] == T[j]) {
                i++;
                j++;
                next[i] = j;
            } else {
                j=next[j];
            }
        }
    }
    
    int kmp(char *str_main,char * str_branch){
        int next[100];
        int str_main_len = strlen(str_main);
        int str_branch_len = strlen(str_branch);
        int i,j;
        get_next(str_branch,next);
        i=0;
        j=0;
        /*kmp 核心
            当主串i和子串j相等的时候,i++,j++;
            反之 j = next[j];
            当 j==-1 的时候,i++,j++
        */
        while ( i < str_main_len && j < str_branch_len )
        {
            if(str_main[i]==str_branch[j]){
                i++;
                j++;
            }else{
                j = next[j];
                if(j==-1){
                    j++;
                    i++;
                }
            }
        }
        if(j>=str_branch_len){
            /*此时说明在主串中找到了子串*/
            return i-str_branch_len;
        }else{
            return -1;//没有找到的话返回-1
        }
    
    }
    
    int main() {
        char str1[100] = "aabaabaaf";
        char str2[100]= "aabaaf";
        if(kmp(str1,str2) != -1){
            printf("子串在主串中开头位置为:%d\n",kmp(str1,str2));
        }else
        {
            printf("没有在主串中找到该子串");
        }
        return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    执行结果:
    在这里插入图片描述

    注:学习笔记,如有错误,还请指正。
    感谢各位阅读。

  • 相关阅读:
    Spring中的BeanFactory和ApplicationContext的区别
    【nlp】2.4 GRU模型
    最近公共祖先算法详解 + 模板题 建议新手收藏 信息学奥赛一本通 祖孙询问
    基于Java的疫苗接种管理系统设计与实现(源码+lw+部署文档+讲解等)
    数据库进阶教学——索引
    Vue使用脚手架(nextTick、Vue封装的过度与动画、vue脚手架配置代理)(九)
    【Mybatis】基础部分
    高颜值测试报告- XTestRunner
    Abaqus血管支架仿真攻略之几何创建与网格划分
    Android对接华为AI - 文本识别
  • 原文地址:https://blog.csdn.net/m0_59519697/article/details/124939540