KMP字符串匹配算法
有字符串 S,字符串 P 表示模式,在 S 中寻找是否有匹配 P 的子字符串
对于字符串 P,要找到一个 next 数组,用于匹配时候下标的跳转,跳转伪代码如下:
考虑 next 数组中元素的含义可能如下:
(1) 在 P 匹配的过程中,匹配到 S[i] != P[j],那么比较 S[i] 与 P[next[j]],j=next[j] ,不断回溯,直至 P[0] != S[i] ,宣告基于 S[i] 的搜索失败,从 S[i+1]、P[0] 重新开始比较尝试匹配
(2) next 是一个用于回溯的数组,根据 P 字符串自身的特性生成,与 S 无关。
假设 next[i]=-1,此处- 1 表示结束 P 基于 S[i] 的搜索,从判断 S[i+1] 和 P[0] 是否相等开始重新搜索
同时,容易知道,next[0] = -1,
考虑如下情况
1. 考虑有元素相等时,进行递推
若 P[far-near:far-1] == P[0:near-1],此处至少有 far-near>=1,即至少有一个元素相等
1.1 P[near]==P[far]
此时 S[i] != P[far], S[i] != P[near]
因此至少需要一次下标的跳转,所以有 next[far] = next[near]
注意,上述代码中 next[far]=next[near] 只有一次回溯,并不完整
后续应在(2)中进行回溯 near = next[near]
1.2 P[near]!=P[far]
此时 S[i] 的值可能与 P[near] 相等,至少有 near 个元素,因此 next[far] = near
1.3 考虑初始值
由 (1.2) 中看到 next[far]=near,next[0] = -1 ,则 near 可能为 -1,near应当初始化为 -1
考虑到 next[0]=-1 是已经确定的,而P[1]对应的next[1[需要考虑到P[0]的值,即当 near=0 时,far 值为 1
if near == -1 || P[far] == P[near]
far++
near++
if P[far]==P[near]
next[far]=next[near]
else
next[far]=near
由上可知,far 初始化的值为 0
2 考虑元素不等时进行回溯
如果 P[far]!=P[near] , 则 near = next[near] 不断回溯
直至最后 near 为-1,或者 P[far] == P[near],即 (1) 中两个判断条件
near == -1 || P[far] == P[near]
完整代码如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdbool.h> 5 6 typedef struct Matchinfo{ 7 unsigned int size; 8 unsigned int matchpos[]; 9 } MatchStruct; 10 11 MatchStruct * bruteForce(const char* S,const char* P){ 12 int lenS = strlen(S),lenP = strlen(P); 13 unsigned int matcharr[lenS]; 14 int pos = -1; 15 int i = 0,j = 0; 16 for(i = 0;i <= lenS - lenP; i++){ 17 bool flag = true; 18 for(j = 0 ; j < lenP ; ++j){ 19 if(S[i+j] != P[j]){ 20 flag = false; 21 break; 22 } 23 } 24 if(flag){ 25 pos++; 26 matcharr[pos] = i; 27 } 28 } 29 if(pos == -1){ 30 return NULL; 31 }else{ 32 //unsigned int* matchpos = (unsigned int *)malloc(sizeof(unsigned int)*(pos+1)); 33 MatchStruct * result = (MatchStruct*)malloc(sizeof(MatchStruct) + sizeof(unsigned int)*(pos+1)); 34 int start ; 35 for(start = 0; start <= pos;++start){ 36 result->matchpos[start] = matcharr[start]; 37 } 38 result->size = pos+1; 39 return result; 40 } 41 } 42 43 void GetNextArray(const char* P,int next[]){ 44 int size = strlen(P),far = 0,near = -1; 45 next[0] = -1; 46 int start = 0; 47 while(far < size){ 48 if(near==-1 || P[near]==P[far]){ 49 near++; 50 far++; 51 if(P[near]==P[far]) 52 next[far] = next[near]; 53 else 54 next[far] = near; 55 56 }else 57 { 58 near = next[near]; 59 } 60 } 61 } 62 63 MatchStruct * KMPSerch(const char* S,const char* P){ 64 int lenS = strlen(S),lenP = strlen(P); 65 unsigned int matcharr[lenS]; 66 int pos = -1; 67 int i = 0,j = 0; 68 69 int next[lenP]; 70 GetNextArray(P,next); 71 72 while(i <= (lenS - lenP)){ 73 //printf( "%d %d %c \n",i,j,S[i]); 74 if( S[i] != P[j] && j != -1){ 75 j = next[j]; 76 }else{ 77 if (j == (lenP-1)){ 78 pos++,matcharr[pos] = i-lenP+1,j=0; 79 }else{ 80 ++j; 81 } 82 ++i ; 83 } 84 } 85 86 if(pos == -1){ 87 return NULL; 88 }else{ 89 MatchStruct * result = (MatchStruct*)malloc(sizeof(MatchStruct) + sizeof(unsigned int)*(pos+1)); 90 int start ; 91 for(start = 0; start <= pos;++start){ 92 result->matchpos[start] = matcharr[start]; 93 } 94 result->size = pos+1; 95 return result; 96 } 97 } 98 99 int main(void){ 100 101 char *S="xwegxwegwaabaac",*P= "xweg"; 102 //MatchStruct* match = bruteForce(S,P); 103 MatchStruct* match = KMPSerch(S,P); 104 if(match == NULL) 105 printf("No substring match!\n"); 106 else{ 107 printf("Substring match!\n"); 108 int start = 0; 109 for(;start < match->size;start++){ 110 printf("%d\n",match->matchpos[start]); 111 } 112 printf("Search Finished!\n"); 113 } 114 115 return 0; 116 }

浙公网安备 33010602011771号