问题定义:
字符串匹配即是在所有文本T中,找出模式P的所有出现。
字符串匹配常用的算法有:
朴素算法
Rabin-Karp算法
有限自动机算法
KMP算法
所有算法中,算KMP算法效率最高。也较为难理解。作者曾经认真看了3遍严蔚敏的《数据结构》,遗憾的是没有看懂,搞得我一度怀疑自己的智商很低。今天看《算法导论》一遍就懂了,当然了,今天的快速理解也是建立在之前三遍的懵懂的基础之上,但是我还是倾向于相信,严蔚敏老师的写书得不够好,不然我不会认真看了三遍都不理解。
学习KMP算法建议还是看书,网上的资料不会比《算法导论》讲的好,不过我这里有三点要提出来,以便帮助读者理解KMP算法:
1)KMP算法需要用到一个辅助数组和一个前缀函数,辅助数组包含了模式与自身的位移进行匹配的信息。
2辅助数组的实现也采用了KMP算法
3)
代码示例:
/* *Copyright(c) Computer Science Department of XiaMen University * *Authored by laimingxing on: 2012年 03月 03日 星期六 18:33:05 CST * * @desc: * * @history */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #define MAX_LENGTH 100000 int *pi; void KMP_MATCHER( char *T, char *P); void COMPUTE_PREFIX_FUNCTION( char *P); int main(int argc, char* argv[]) { FILE *fp = NULL; int ch; int i = 1; char sourceString[ MAX_LENGTH + 1]; char patternString[ MAX_LENGTH + 1]; //具体实现时sourceString[0]和patternString[0]是不使用的,但是不能让其取默认值 //如果默认值是0的话,则获取sourceString和patternString的字符串长度就是错误的。 sourceString[0] = patternString[0] = 'A'; fp = fopen("test.txt","r"); if( fp == NULL ) { printf("open file error\n"); exit(0); } while( i < MAX_LENGTH && (ch = fgetc( fp )) != EOF ) { sourceString[ i++ ] = ch; } sourceString[i] = '\0'; printf("Please input pattern string:"); gets( patternString + 1); KMP_MATCHER( sourceString, patternString); return 0; } void KMP_MATCHER( char *T, char *P) { assert(T && P); int n, m, q, i; n = strlen( T ) - 1; m = strlen( P ) - 1; COMPUTE_PREFIX_FUNCTION( P ); q = 0; for( i = 1; i <= n; i++ ) { while( q > 0 && P[ q + 1 ] != T[ i] ) q = pi[q]; if( P[q + 1] == T[i] ) q++; if( q == m ) { printf("Pattern occurs with shift: %d\n", i - m + 1 ); q = pi[q]; } } } void COMPUTE_PREFIX_FUNCTION( char *P) { assert(P); int m, k, q; m = strlen( P ); pi = new int[m + 1]; pi[1] = 0; k = 0; for( q = 2; q <= m; q++) { while( k > 0 && P[ k + 1 ] != P[q] ) { //这里改为 k = 0 也是可行的 //且更好理解,当前字符与期望的字符不匹配,则pi[q] = 0 k = pi[ k]; } if( P[ k + 1] == P[q] ) k++; pi[q] = k; } }