📜  用于模式搜索的KMP算法的C程序(1)

📅  最后修改于: 2023-12-03 14:56:21.751000             🧑  作者: Mango

用于模式搜索的KMP算法的C程序

KMP算法是一种常用的字符串匹配算法,可以用于判断一个字符串是否包含另一个字符串。该算法的本质是利用已经匹配过的信息,尽量减少无效的比较次数,从而提高算法效率。

算法原理

KMP算法的核心是构建一个跳转表,该表记录了当前匹配的字符序列与模式串不匹配时应该跳转到模式串的哪个位置继续匹配。在匹配过程中,当发现当前匹配的字符序列与模式串不匹配时,直接根据跳转表跳转到指定位置进行接下来的匹配。

跳转表的构建可以使用前缀匹配法。对于一个长度为N的模式串,定义一个长度为N的数组next,其中next[i]表示当模式串的第i个字符与当前匹配的字符不匹配时,应该跳转到模式串的第next[i]个字符与当前匹配的字符继续匹配。例如,如果模式串为"ABCABD",那么next数组应该为[0, 0, 0, 1, 2, 0]。可以使用动态规划的思想依次求出next数组的每个元素,具体步骤如下:

  1. 初始化next[0]=0,next[1]=0;
  2. 从i=2开始遍历,对于每个i,首先令j=next[i-1],表示当前字符前面已经匹配的最长前缀的下一个字符所在的位置;
  3. 如果模式串的第i个字符与模式串的第j+1个字符相等,则令next[i]=j+1;
  4. 如果模式串的第i个字符与模式串的第j+1个字符不相等,则不断令j=next[j],直到模式串的第i个字符与模式串的第j+1个字符相等或者j=0为止,令next[i]=j。

构建好跳转表后,就可以实现KMP算法。具体步骤如下:

  1. 定义i,j分别表示文本串和模式串当前匹配的位置,初始值为0;
  2. 当i小于文本串的长度并且j小于模式串的长度时进行循环:
    1. 如果文本串的第i个字符和模式串的第j个字符相等,则i,j均加1。
    2. 如果文本串的第i个字符和模式串的第j个字符不相等,则根据跳转表将j跳转到指定位置,继续匹配。
    3. 如果j等于模式串的长度,则匹配成功,返回文本串中的匹配位置。
C程序实现

下面是基于上述原理编写的KMP算法的C程序,其中search函数实现了算法的流程,getNext函数实现了next数组的求解:

#include <stdio.h>
#include <string.h>

void getNext(char *pattern, int *next) {
    int i, j;
    int len = strlen(pattern);

    next[0] = -1;
    for (i = 1; i < len; i++) {
        j = next[i - 1];
        while (j >= 0 && pattern[i] != pattern[j + 1]) {
            j = next[j];
        }
        if (pattern[i] == pattern[j + 1]) {
            next[i] = j + 1;
        } else {
            next[i] = -1;
        }
    }
}

int search(char *text, char *pattern) {
    int i, j;
    int n = strlen(text), m = strlen(pattern);
    int next[m];

    getNext(pattern, next);

    i = j = 0;
    while (i < n && j < m) {
        if (text[i] == pattern[j]) {
            i++;
            j++;
        } else if (j > 0) {
            j = next[j - 1] + 1;
        } else {
            i++;
        }
    }
    if (j == m) {
        return i - m;
    } else {
        return -1;
    }
}

int main() {
    char text[] = "ABABABCABDABABCABCA";
    char pattern[] = "ABABCABCA";
    int pos = search(text, pattern);

    if (pos == -1) {
        printf("未找到匹配项\n");
    } else {
        printf("匹配项在第%d个位置\n", pos);
    }
    return 0;
}

需要注意的是,搜索函数返回的是匹配项在文本串中的位置,如果没有找到匹配项则返回-1。在使用时,只需要将要搜索的文本串和模式串传入search函数即可。

总结

KMP算法是一种高效的字符串匹配算法,其核心就是构建一个跳转表,该表记录了当前匹配的字符序列与模式串不匹配时应该跳转到模式串的哪个位置继续匹配。通过合理地利用已经匹配过的信息,可以尽量减少无效的比较次数,从而提高算法效率。