一直以来,对算法都是理论大于实际,甚至没有实际.
最近由于项目需要.从新了解了一下KMP算法.唉,讨厌这种被动的学习过程.
不过KMP算法还是很有意思的,用了两天的时间才总算是弄懂了.期间参考了网上的博文和数据结构.下面分享一下KMP算法的心得.
KMP的总体思想是利用模式串本身的特性来优化匹配的步骤.如何利用自身的特性呢,KMP借助一个数组来实现,也就是大多数教程中提到的next数组.后面我会介绍next数组是如何构建和使用的.
前面提到KMP算法需要模式串满足一定的条件,那么这个条件是什么呢.这里直接引用数据结构书中的等式:
当k < j 时, t1t2…tk-1tk = tj-(k-1)tj-k… tj-1 tj.
如果没有这个等式,那么KMP算法无异于浪费了next大小的空间的最普通的字符串匹配算法.
下面用一张图来描述一下这个等式在匹配子串的时候起到的作用:
(本图片假定数组下标从1开始)首先我们找到等式: t1t2 = t6t7.所以当t8不匹配的时候,KMP算法会自动对齐t1 t2 然后用t3和母串进行匹配.
那么根据以上的分析,我们可以得出以下的几个结论(可能得出的有点仓促,同学们还是需要结合课本来进行理解)
1. next数组和模式串的下标是一一对应的.
2. 每个字符对应的next保存的是其前一个字符匹配的前缀的下标.从上面的图中可以看到next[8]保存的是3.
3. 第一个字母没有前缀,所以它的next保存的是一个无效的下标.在实际编程中,可以是-1
4. 如果一个字符的前面没有满足等式的子串,则其next保存的是模式串的首字母的下标.
根据我们的结论,下面给出KMP算法的实现:
void kmp_get_next(char *pattern, int next[]) { int i = 0, j = 0; next[i] = -1; while (i < strlen(pattern) - 1) { if (j == i || pattern[i] == pattern[j]) { if (j != i) { j++; } i++; next[i] = j; } else if (j != 0) { j = next[j]; } else { i++; } } } void kmp_print_next(char *pattern, int next[]) { int i = 0; if (NULL == pattern) { return; } printf("%s 's next array is : \n", pattern); for (i = 0; i < strlen(pattern); i++) { printf("%d\t", next[i]); } } int kmp_is_match(char *pattern, char *basestr, int next[]) { int i = 0; int j = 0; while (i < strlen(basestr)) { if (basestr[i] == basestr[j]) { if (j == strlen(pattern)) { return 0; } i++; j++; } else { j = next[j]; if (j == -1) { i++; } } } return -1; } int kmp_get_match(char *pattern, char *basestr, int next[]) { int i = 0; int j = 0; while (i < strlen(basestr)) { if (basestr[i] == basestr[j]) { if (j == strlen(pattern)) { return i; } i++; j++; } else { j = next[j]; if (j == -1) { i++; } } } return -1; }
#include "kmp.h" int main(int argc, char **argv) { int ret = 0; int i = 0; char *pattern = "abaabc"; int next[10] = {0}; char *basestr = "abcabcabcabccacabdabaabcabceadb"; kmp_get_next(pattern, next); printf("%s matched\n", kmp_is_match(pattern, basestr, next) == 0 ? "is" : "not"); ret = kmp_get_match(pattern, basestr, next); return 0; }
可能是我理解的还不够深把,写之前觉得有很多内容可以分享,但是开始写以后发现不知道该写什么.希望能够对同学们有所启发.
原文:http://blog.csdn.net/cp3alai/article/details/46293223