数据结构与算法 - 串

KMP字符串匹配算法

image
next数组的计算方法:
看该字符前的字符串的前缀和后缀有多少相同(可以交叉重叠),就让相同的数量值加一即为当前next值。
也可以这样计算:看前一个字符的next值处是否与前一个字符相同,若相同,则当前next值为上一next值加一;若不相同,则查看上一next值处的字符的next处于当前的字符是否相同,直到相同之后,让相同的值加一(如果到达最开头都不相同,则直接设置为1,总之就是到相同的位置的next值加一)。
下面是一个例子:
image

A B C A B C D
0 1 1 1 2 3 4

因此,在第一次失配时,如上图红框区域,j指针直接回到了next[j]的位置,当j位于第一个时(即第一个就失配),i++并且j不变,以此类推
nextval数组的计算方法
规则:
对比当前next值处的字符是否与当前字符相同,若相同,则nextval也与那字符的nextval相同;若不同,则nextval与其next值相同;
例子:

索引 1 2 3 4 5 6 7 8 9 10 11 12
字符串 a b a b a a a b a b a a
next数组 0 1 1 2 3 4 2 2 3 4 5 6
nextval数组 0 1 0 1 0 4 2 1 0 1 0 4
解释: 前一个是b,b和a不相同,到第一个,设置为1 前一个是a,与b不一样,和b还是不一样,和a一样,1+1=2
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
using namespace std;

#define MAXSTRLEN 255
typedef unsigned char SString[MAXSTRLEN + 1];

void strLength(SString S) {
    int m;
    for (m = 1; S[m] != '\0'; m++);
    S[0] = m - 1;
}

void get_next(SString T, int* next) {
    int j = 1, k = 0;
    next[1] = 0; // 初始化 next[1] 为 0

    while (j < T[0]) {  // T[0] 是串 T 的长度
        if (k == 0 || T[j] == T[k]) {
            j++;
            k++;
            next[j] = k;
        }
        else {
            k = next[k];
        }
    }
}

int Index_KMP(SString S, SString T, int pos, int* next) {
    int i = pos, j = 1; // i 指向主串 S 的当前字符,j 指向模式串 T 的当前字符
    get_next(T, next);  // 计算模式串 T 的 next 数组

    while (i <= S[0] && j <= T[0]) {
        if (j == 0 || S[i] == T[j]) {  // 如果匹配,或 j = 0(即从头匹配)
            i++;
            j++;
        }
        else {
            j = next[j];  // 如果失配,j 跳转到 next[j]
        }
    }

    if (j > T[0]) return i - T[0]; // 匹配成功
    else return 0;  // 匹配不成功
}

int main() {
    SString S, T;
    int pos;
    int next[MAXSTRLEN];
    int r;

    printf("输入主串 S: ");
    scanf("%s", S + 1);  // 跳过下标为 0 的元素
    printf("输入模式串 T: ");
    scanf("%s", T + 1);  // 跳过下标为 0 的元素
    printf("输入起始位置 pos: ");
    scanf("%d", &pos);

    strLength(S);   // 求主串 S 的长度
    strLength(T);   // 求模式 T 的长度

    if (r = Index_KMP(S, T, pos, next))
        printf("模式串在主串中的位置为:  %d \n", r);
    else printf("匹配失败!");

    return 0;
}
posted @   终末时代人  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示