KMP C语言实现与理解 (小甲鱼)

//从小甲鱼数据结构视频中学习的. codeblock可运行

#include<stdio.h>


typedef char* String;
// BF 需要回溯,理解起来就是条条大路通罗马,哪里跌倒,哪里爬起,效率低.
// KMP核心:避免回溯, str或S叫目标串,两个串中比较长的那个,ptr或T是模式串,两个串中比较短的那个.
// 问题由模式串决定,因为目标串不回溯,在当前位置匹配失败,目标串当前下标不变,通过next数组改变模式串的下标.


// 求模式串的next数组,i 指向模式串后缀,j指向模式串前缀,前缀是不变的,后缀是相对的,abab的前缀有a, ab, aba,后缀有b, ba, bab
// 初始next[1] = 0, next[2] = 1(这个是j == 0的情景j++, i++, T[i] != T[j]时, next[i] =j得到的)
// 如果当前i, j 指向的字符相等,i++, j++,这时正好是要求得next[i]的值,j此时为匹配前缀长度+1.

// next数组指导模式匹配串下一步改用下标是几号的元素与当前目标串下标元素进行匹配.next[i]的值为到下标i为止,匹配前缀的长度+1.

// !!!!next理解 --->匹配失败时,如果当前下标前的所有元素值都不一样,就回到j = 1(0位置我存了字符串长度,这个可以自行定义 ).j = 1 可以理解为当前下标的前缀长度为0,0+1 = 1 = j. 如果当前下标前的所有元素值有部分一样的,假设(前缀 = 后缀)的最大长度为2,那么如果匹配失败,就回溯到2+1 = 3 = j = next[j]的位置.

void get_next(String T, int *next)
{
    int i = 1;
    int j = 0;
    next[1] = 0;
    while(i <= T[0])
    {
        if(0 == j || T[i] == T[j]) // i, j 指向的元素值相等
        {
            i++;
            j++;
            if(T[i] != T[j])// 这个判断用于在相邻元素相等时,next值依次为01234时,在不匹配时,会一个劲的回到j = next[j],效率低.
                next[i] = j;
            else
                next[i] = next[j]; //等于j的next值,优化,可以让next数组不再是01234了,而是01111.
        }
        else  //i, j指向的元素值不等,那么目标串下标i不动,模式串下标移动next[j]表示到j为止,前面前缀长度+1
            j = next[j];
    }
}
// 返回子串T在主串S第pos个字符之后的位置
// 若不存在,则返回0
int Index_KMP(String S, String T, int pos) //KMP算法
{
    int i = pos;
    int j = 1;
    int next[255];
    get_next(T, next);
    while(i <= S[0] && j <= T[0])  //两个串一个到尾就结束
    {
        if(j == 0 || S[i] == T[j])  //如果模式串next到j = 0位置或者当前两个字符匹配, 就i++, j++  !!!!这个J== 0很重要.
        {
            i++;
            j++;
        }
        else   // 若不匹配,就根据next值确定模式串回溯的下标位置
            j = next[j];
    }
    if(j > T[0]) // 匹配成功
        return i - T[0];
    else
        return 0;   //匹配失败
}
int main()
{
    char str[255] = " ababaaaba"; //字符串定义方式,0位置存字符串长度.
    char ptr[255] = " baac";
    ptr[0] = 4;
    str[0] = 9;
    int next[255];


    get_next(str, next);
    for(int i = 1; i < 10; ++i)
        printf("%d", next[i]);
    printf("\n");
    int index = Index_KMP(str, ptr, 0);
    printf("%d", index);


}

猜你喜欢

转载自blog.csdn.net/qq_23534759/article/details/80634188
今日推荐