直接上代码,都在注释里了。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 //KMP 5 //判断已经不等过的,不在重新判断 6 //判断过已经相等的,也不再重新进行判断 7 /* 8 与朴素模式相比,KMP算法省去了回溯的重复问题,对判断到的相等或者不等的情况进行合理重复利用,避免多次判断的时间复杂度提升。 9 */ 10 11 //算法代码实现 12 //这段代码的目的就是为了计算出当前要匹配的串T的next数组 13 void get_next(char * T, int *next) 14 { 15 int i, j; 16 i = 1; 17 j = 0; 18 next[1] = 0; 19 while (i < T[0]) 20 { 21 if ((j == 0) || (T[i] == T[j])) //T[i]表示后缀的单个字符,T[j]表示前缀的单个字符 22 { 23 j++; 24 i++; 25 next[i] = j; 26 } 27 else 28 { 29 j = next[j]; //若字符不相同,则j值回溯 30 } 31 } 32 } 33 34 /* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。 */ 35 /* T非空,1≤pos≤StrLength(S)。 */ 36 /* 37 KMP算法的时间复杂度为O(n+m),与朴素模式的O((n-m+1)*m)相比,优化不少。 38 但是也需要强调的是,KMP算法在模式与主串之间存在许多“部分匹配”的情况下才能体现出它的优势 39 否则两者差异并不明显 40 */ 41 int Index_KMP(char *S, char *T, int pos) 42 { 43 int i = pos; //i用于主串S当前位置下标值,若pos不为1,则从pos位置开始匹配 44 int j = 1; //j用于子串T中当前位置下标 45 int next[255]; //定义一组next数组 46 get_next(T, next); //对串T做分析,得到next数组 47 while (i <= S[0] && j <= T[0]) //若i小于S的长度且j小于T的长度时,循环继续 48 { 49 if (j == 0 || S[i] == T[j]) //两字母相等时则继续,与朴素算法相比,增加了j=0的判断 50 { 51 i++; 52 j++; 53 } else { 54 j = next[j]; // j回到合适的位置,i值不变 55 } 56 } 57 58 if (j > T[0]) { 59 return i - T[0]; 60 } else { 61 return 0; 62 } 63 } 64 65 //KMP模式匹配算法改进 66 //求模式串T的next函数修正值并存入数组nextval 67 void GetNextVal(char *T, int *nextval) 68 { 69 int i, j; 70 i = 1; 71 j = 0; 72 nextval[1] = 0; 73 while (i < T[0]) { 74 if (j == 0 || T[i] == T[j]) { 75 i++; 76 j++; 77 if (T[i] != T[j]) //若当前字符与前缀字符不同 78 nextval[i] = j; //则当前的j为nextval在i位置的值 79 else 80 nextval[i] = nextval[j]; //如果与前缀字符相同,则将前缀字符的nextval值赋值给nextval[i] 81 } else 82 j = nextval[j]; //若字符不相同,则j值回溯 83 } 84 } 85 86 //实际匹配算法则只需要将"get_next(T, next)"改为"GetNextVal(T, next)"即可。 87 88 int main() 89 { 90 printf("hello world\n"); 91 return 0; 92 }