C语言KMP算法

KMP算法(Knuth-Morris-Pratt algorithm)是一种用于字符串匹配的高效算法,它的时间复杂度为O(m+n),其中m为模式串的长度,n为文本串的长度。KMP算法通过利用模式串中的重复信息,避免了朴素算法中不必要的比较,提高了匹配的效率。

KMP算法的核心思想是使用一个辅助数组next[],用于存储模式串中每个位置的最长公共前后缀长度。通过利用这些信息,可以在匹配过程中跳过一些不必要的比较,从而提高匹配的效率。

下面是KMP算法的实现代码:

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

// 构建next数组
void getNext(char* pattern, int* next) {
    int patternLength = strlen(pattern);
    next[0] = -1;
    int i = 0, j = -1;

    while (i < patternLength - 1) {
        if (j == -1 || pattern[i] == pattern[j]) {
            i++;
            j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
}

// 使用KMP算法进行字符串匹配
void kmpMatch(char* text, char* pattern) {
    int textLength = strlen(text);
    int patternLength = strlen(pattern);
    int next[patternLength];
    getNext(pattern, next);

    int i = 0, j = 0;
    while (i < textLength) {
        if (j == -1 || text[i] == pattern[j]) {
            i++;
            j++;
            if (j == patternLength) {
                printf("在位置 %d 处找到匹配\n", i - j);
                j = next[j];
            }
        } else {
            j = next[j];
        }
    }
}

int main() {
    char text[] = "ABABDABACDABABCABAB";
    char pattern[] = "ABABCABAB";
    kmpMatch(text, pattern);    // 使用KMP算法进行字符串匹配
    return 0;
}

注释和讲解:

  1. getNext函数用于构建next数组。初始化next[0]为-1,然后利用两个指针i和j从头开始遍历模式串,根据当前字符是否匹配来更新next数组。如果j为-1或者当前字符匹配成功,则将i和j都向后移动一位,并将next[i]赋值为j。如果当前字符匹配失败,则将j更新为next[j],即回退到前一个字符的最长公共前后缀长度。
  2. kmpMatch函数使用KMP算法进行字符串匹配。首先计算文本串和模式串的长度,然后构建模式串的next数组。使用两个指针i和j分别表示文本串和模式串的索引,在匹配过程中,根据当前字符是否匹配来决定指针的移动。如果匹配成功,则将指针i和j都向后移动一位,如果j等于模式串的长度,则说明找到了匹配,打印匹配的位置,并将j更新为next[j]。如果匹配失败,则将指针j更新为next[j],即回退到上一个字符的最长公共前后缀长度。
  3. 在主函数中,我们定义了文本串和模式串,并调用kmpMatch函数进行字符串匹配。

KMP算法通过利用模式串中的重复信息,在匹配过程中避免了不必要的比较,提高了匹配的效率。通过构建模式串的next数组,可以在匹配失败时快速回退到合适的位置,避免了朴素算法中的大量重复比较。因此,KMP算法在实际应用中具有较高的效率。

### C语言中实现KMP算法 #### 构建Next数组 为了提高模式匹配的效率,KMP算法通过预先处理模式串来创建`next`数组。该数组记录了模式串中各个位置字符之前的最长公共前后缀长度[^2]。 ```c void build_next(const char *pattern, int next[]) { int length = strlen(pattern); next[0] = -1; int k = -1; for (int q = 1; q < length; ++q) { while (k >= 0 && pattern[k + 1] != pattern[q]) k = next[k]; if (pattern[k + 1] == pattern[q]) ++k; next[q] = k; } } ``` 这段代码实现了`next`数组的构建过程。对于每一个索引位置`q`,计算其对应的`next[q]`值,即最大相等的真前缀和真后缀长度减一。 #### 主函数实现 基于上述准备好的`next`数组,可以编主逻辑来进行字符串匹配: ```c #include <stdio.h> #include <string.h> // 前面定义过的build_next函数... int kmp_search(const char *text, const char *pattern) { int m = strlen(text), n = strlen(pattern); // 初始化next数组用于存储部分匹配表 int* next = malloc(n * sizeof(int)); memset(next, 0, n * sizeof(int)); build_next(pattern, next); int i = 0, j = 0; while (i < m && j < n) { if (j == -1 || text[i] == pattern[j]) { i++; j++; } else { j = next[j]; // 不匹配则跳转至next所指位置继续尝试 } } free(next); // 清理动态分配的空间 if (j == n) return i - j; // 返回起始下标 else return -1; // 表示未找到子串 } int main() { const char *str = "ABCDABC"; const char *substr = "BCD"; printf("Index of substring is %d\n", kmp_search(str, substr)); return 0; } ``` 此程序展示了如何使用C语言完成完整的KMP搜索操作。首先调用了辅助方法`build_next()`初始化必要的数据结构;接着执行核心循环逐步对比文本串与模式串直至发现完全一致的部分或遍历结束[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值