KMP算法C语言实现.
KMP(Knuth-Morris-Pratt)算法是一种在文本串中查找子串的高效算法,由唐纳德·克努斯、弗雷德里克·莫里斯和劳伦斯·普拉特在1970年提出。该算法避免了在匹配过程中不必要的回溯,提高了字符串匹配的效率。下面我们将详细探讨KMP算法的原理、C语言实现以及如何扩展到找出所有匹配串。 **KMP算法原理** KMP算法的核心在于构造一个“部分匹配表”(也称为“失配表”),用于记录在匹配过程中,当发生不匹配时,如何利用已知信息避免回溯。这个表给出了当当前字符不匹配时,需要将子串移动多少位以继续匹配。具体步骤如下: 1. **构建部分匹配表(LPS - Longest Proper Prefix which is also a Suffix)**:对于子串,找到它的所有前缀和后缀,找出最长的公共前缀,记录其长度作为对应位置的值。例如,子串"ABCDABD"的LPS为"ABD",对应的LPS数组为[0, 0, 1, 0, 1, 2, 0]。 2. **匹配过程**:使用部分匹配表进行匹配。当比较的字符不匹配时,根据部分匹配表中的值,决定子串向右移动多少位。如果部分匹配表值为0,表示没有公共前缀,子串需要回溯到最左边;否则,子串可以向前移动对应的位数,继续与文本串匹配。 **C语言实现KMP算法** 以下是一个基本的C语言实现KMP算法的示例: ```c #include <stdio.h> #include <string.h> // 函数计算部分匹配表 void computeLPS(char* pattern, int lps[], int len) { int index = 0; for (int i = 1; i < len; i++) { while (index > 0 && pattern[i] != pattern[index]) { index = lps[index - 1]; } if (pattern[i] == pattern[index]) { index++; } lps[i] = index; } } // KMP主算法 void KMP(char* text, char* pattern) { int lps[pattern.length()]; computeLPS(pattern, lps, pattern.length()); int i = 0, j = 0; while (i < strlen(text) && j < strlen(pattern)) { if (text[i] == pattern[j]) { i++; j++; } else { if (j > 0) { j = lps[j - 1]; } else { i++; } } } if (j == strlen(pattern)) { printf("Pattern found at index %d\n", i - j); } } int main() { char text[] = "ABABCABABCAB"; char pattern[] = "ABAB"; KMP(text, pattern); return 0; } ``` 在这个例子中,`computeLPS`函数用于计算部分匹配表,`KMP`函数执行实际的匹配操作。在`main`函数中,我们调用这两个函数来查找文本串中的目标子串。 **扩展到找出所有匹配串** 要找到文本串中所有出现的目标子串,只需在KMP算法的匹配过程中记录下每次匹配成功的起始位置即可。当找到一个匹配后,不回溯,而是直接从下一个字符开始继续匹配。以下是扩展后的C代码: ```c void findAllKMP(char* text, char* pattern) { int lps[pattern.length()]; computeLPS(pattern, lps, pattern.length()); int i = 0, j = 0; while (i < strlen(text)) { if (text[i] == pattern[j]) { i++; j++; } else { if (j > 0) { j = lps[j - 1]; } else { i++; } } if (j == strlen(pattern)) { printf("Pattern found at index %d\n", i - j); j = lps[j - 1]; } } } int main() { char text[] = "ABABCABABCAB"; char pattern[] = "ABAB"; findAllKMP(text, pattern); return 0; } ``` 这段代码在找到一个匹配后,会将子串移到下一个可能的匹配位置(即`j = lps[j - 1]`),而不是回溯到文本串的起始位置。这样,就可以找出所有匹配的子串了。 KMP算法是一种高效的字符串匹配方法,通过构建部分匹配表避免了不必要的回溯。在C语言中实现KMP算法,并扩展到找出所有匹配串,可以提高文本处理的效率,尤其在处理大量数据时。