KMP算法是一种用于字符串匹配的算法,它可以在 O ( n ) O(n) O(n) 的时间复杂度内完成字符串匹配,其中 n n n 是文本串的长度。
以下是C语言实现KMP算法的示例代码:
1.
#include <stdio.h>
#include <string.h>
void computeLPS(char *pat, int M, int *lps) {
int len = 0;
lps[0] = 0;
int i = 1;
while (i < M) {
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
}
else {
if (len != 0) {
len = lps[len-1];
}
else {
lps[i] = 0;
i++;
}
}
}
}
void KMP(char *pat, char *txt) {
int M = strlen(pat);
int N = strlen(txt);
int lps[M];
computeLPS(pat, M, lps);
int i = 0;
int j = 0;
while (i < N) {
if (pat[j] == txt[i]) {
j++;
i++;
}
if (j == M) {
printf("Pattern found at index %d \n", i-j);
j = lps[j-1];
}
else if (i < N && pat[j] != txt[i]) {
if (j != 0) {
j = lps[j-1];
}
else {
i = i+1;
}
}
}
}
int main() {
char txt[] = "ABABDABACDABABCABAB";
char pat[] = "ABABCABAB";
KMP(pat, txt);
return 0;
}
在上面的示例代码中,computeLPS() 函数用于计算模式串的 LPS(Longest Prefix Suffix)数组,即在模式串中所有前缀和后缀相等的部分的最大长度。这个函数的实现基于 KMP 算法的原理。
KMP() 函数用于执行字符串匹配,它首先调用 computeLPS() 函数计算 LPS 数组,然后使用 LPS 数组进行字符串匹配。在执行字符串匹配时,算法通过比较模式串和文本串中的字符,来逐步匹配模式串。如果匹配成功,就打印出匹配的位置。如果匹配失败,就根据 LPS 数组来调整模式串的位置,以便进行下一次匹配。
在上面的示例中,输入的文本串是 “ABABDABACDABABCABAB”,模式串是 “ABABCABAB”,程序的输出为:
Pattern found at index 10
这表明模式串在文本串中的第一个匹配位置是 10。
2.
KMP算法是一种高效的字符串匹配算法,它利用模式串本身的信息来避免在匹配过程中重复比较文本串中已经匹配过的字符。下面是KMP算法的模式匹配实现步骤:
预处理模式串
对于模式串 p p p,可以先求出它的前缀函数(即部分匹配值),记为 n e x t next next 数组。 n e x t [ i ] next[i] next[i] 表示模式串 p p p 中以 p i p_i pi 结尾的子串的最长相等前后缀的长度。可以使用动态规划的思想来求解 n e x t next next 数组,其时间复杂度为 O ( m ) O(m) O(m),其中 m m m 为模式串的长度。
进行模式匹配
在文本串 s s s 中匹配模式串 p p p 的过程可以分为两个步骤:
(1)初始化
从文本串 s s s 的第一个字符开始,以及模式串 p p p 的第一个字符开始,逐个比较它们的值。如果匹配成功,则继续比较下一个字符,否则将模式串 p p p 向右移动一位,并从模式串 p p p 的第一个字符开始重新比较。
(2)匹配
如果文本串 s s s 和模式串 p p p 中的某些字符不匹配,就需要利用 n e x t next next 数组来调整模式串 p p p 的位置。具体地,设文本串 s s s 的当前位置为 i i i,模式串 p p p 的当前位置为 j j j,则当 s i ≠ p j s_i \neq p_j si=pj 时,可以根据 n e x t next next 数组的值来将模式串 p p p 向右移动 j − n e x t [ j ] j-next[j] j−next[j] 个字符,并将 j j j 更新为 n e x t [ j ] next[j] next[j]。这样做可以避免重复比较文本串 s s s 中已经匹配过的字符,提高匹配效率。
#include <stdio.h>
#include <string.h>
void get_next(char *p, int *next)
{
int i = 0, j = -1;
next[0] = -1;
while (p[i] != '\0') {
if (j == -1 || p[i] == p[j]) {
i++;
j++;
next[i] = j;
}
else {
j = next[j];
}
}
}
int kmp(char *s, char *p, int *next)
{
int i = 0, j = 0;
while (s[i] != '\0' && p[j] != '\0') {
if (j == -1 || s[i] == p[j]) {
i++;
j++;
}
else {
j = next[j];
}
}
if (p[j] == '\0') {
return i - j; // 返回模式串在文本串中第一次出现的位置
}
else {
return -1; // 模式串未在文本串中出现
}
}
int main()
{
char s[] = "ABABABABCABABABABCABABABABC";
char p[] = "ABABCABAB";
int next[strlen(p) + 1];
get_next(p, next);
int pos = kmp(s, p, next);
if (pos != -1) {
printf("The pattern first appears at position %d\n", pos);
}
else {
printf("The pattern does not appear in the text\n");
}
return 0;
}
在这个示例中,输入的文本串为“ABABABABCABABABABCABABABABC”,模式串为“ABABCABAB”,输出的结果为“ The pattern first appears at position 6”,表示模式串在文本串中第一次出现的位置是在第6个字符处。