关于字符串模式匹配,暂定目的是找到目标串当中的模式串出现的最先位置
本文参照了
http://kenby.iteye.com/blog/1025599
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
两篇文章,这两篇文章详细介绍了KMP算法的原理和实现。
现在增加一点我的体会。
KMP算法相比原先的暴力算法来讲,不是一个字符一个字符的向前移动,而是根据模式串前缀数组跳跃式前进。
next[] 数组:用于表示在模式串的前n个字符当中前后对称的个数。
以000#xxx0000
为例:
算法需要:默认next[0] = next[1] = 0;
next[2] = 1; next[3] = 2; next[4] = 0; next[5] = 0; next[6] = 0; next7] = 0; next[8] = 1; next9] = 2; next10] = 3; next[11] = 3;
现在讲述如何利用这些前缀数组进行匹配。
比如已经匹配了前n个字符,发现第n+1 个字符不匹配,那么将模式串向前移动 n - next[n] 个距离,然后从p[ next[n] ] 和 上次已经匹配的src[k] 进行匹配。
比如
0000
000# 已经匹配了前三个,第四个不匹配,那么移动 3 - next[3] = 1个位置,然后比较 p[next[3]] = p[2] 开始与 src[ ] 的后面进行比较
比如上图
已经匹配了6个字符
然后next[6] = 2 ,然后向前移动 6 - 2 = 4 个位置,然后
用p【next[6]】 = p[2] 与后面的数据进行比较。
下面讲述如何求解next[]数组
000#xxx0000
这个字符串
首先next[0] = next【1】 = 0;
void compute_prefix(int *next, char *p) { int i, n, k; n = strlen(p); next[1] = next[0] = 0; k = 0; /* 第i次迭代开始之前,k表示next[i-1]的值 */ for (i = 2; i <= n; i++) { for (; k != 0 && p[k] != p[i-1]; k = next[k]); if (p[k] == p[i-1]) k++; next[i] = k; } }
KMP算法C语言版本
#include<stdio.h> #include<string.h> void compute_prefix(int *next, char *p) { int i, n, k; n = strlen(p); next[1] = next[0] = 0; k = 0; /* 第i次迭代开始之前,k表示next[i-1]的值 */ for (i = 2; i <= n; i++) { for (; k != 0 && p[k] != p[i-1]; k = next[k]); if (p[k] == p[i-1]) k++; next[i] = k; } } void kmp_match(char* text,char* p,int* next) { int m,n,q,s; m = strlen(p); n = strlen(text); s = 0;// s表示这次迭代从text的哪个字符开始比较 q = 0;// q表示上一次迭代匹配了多少个字符 while(s<n) { for(q=next[q];q<m&&p[q]==text[s];s++,q++); if(q==0)s++; else if(q==m){ printf("pattern occurs with shift %d\n", s-m); } } } int main() { int next[101], n; char *p = "000"; char *text = "000#xxx0000"; compute_prefix(next, p); kmp_match(text, p, next); int i = 0; for(;i<4;i++) { printf("%d ",next[i]); } return 0; }