我得承认,我对KMP的理解没有达到百分百,所以在阐述解释时都不能将KMP算法的妙处讲清楚。
一、实现思想
- 通过对子串每一个字符进行扫描,会得出一个数组,这个数组可以用来帮助主串和子串比较时跳跃式前进(避免了一些不必要的比较)
- 还是看图理解一下吧。(真的讲不清楚)
二、图例实现
BF表现出来的缺点
KMP算法
三、代码实现
了解自身结构的函数,有了这个我们就可以知道在比较发生不匹配时可以跳过哪些,或者说是否要从头开始。这个函数我是看着课本的数学关系写出来的,所以我也解释不清。
1 //得到next数组 这个函数就是用来了解自身结构的,但是妙处我描述不清楚,忏愧。 2 int *find_next(char t[]) 3 { 4 int len = strlen(t); 5 6 int *next = new int[len]; //建立在堆区的next数组 7 8 for (int i = 0; t[i] != '\0'; i++) 9 { 10 11 if (i == 0) 12 next[i] = -1; 13 else if (i == 1) 14 next[i] = 0; 15 else 16 for (int p_start = i - 1; p_start > 0; p_start--) //b部分的起点总是0,p部分的终点总是i-1,p_start作为p数组的起点 17 { 18 // int flag = 0; //flag是b数组的长度 //原来我能够写出来完全是因为书本的公式,原来我还没有理解的 19 int a = 0; //a先是作为b数组的起点,然后自增到终点 20 int b = i - p_start; //b先是作为q数组的起点,然后自增到终点 21 22 while (t[a] == t[b] && b <= i - 1) 23 { 24 // flag++; 25 a++; 26 b++; 27 } 28 if (b == p_start) //这里的一些数字关系真的是太妙了,我很难解释清楚 29 { 30 next[i] = p_start; 31 break; 32 } 33 else 34 next[i] = 0; 35 } 36 } 37 return next; 38 }
KMP执行
1 //KMP实现 有了那个next数组,我们就可以知道哪些是可以跳过的 2 int KMP(char s[], char t[]) 3 { 4 int *next = find_next(t); 5 int i = 0; 6 int j = 0; 7 int begin = i; 8 while (s[i] != '\0' && t[j] != '\0') 9 { 10 if (s[i] == t[j]) 11 { 12 i++; 13 j++; 14 } 15 else 16 { 17 begin = begin + j - next[j]; 18 j = next[j]; 19 } 20 if (j == -1) 21 { 22 i++; 23 j++; 24 begin = i; 25 } 26 } 27 return begin; 28 }
全部代码
1 #include <stdio.h> 2 #include <string.h> 3 //得到next数组 这个函数就是用来了解自身结构的,但是妙处我描述不清楚,忏愧。 4 int *find_next(char t[]) 5 { 6 int len = strlen(t); 7 8 int *next = new int[len]; //建立在堆区的next数组 9 10 for (int i = 0; t[i] != '\0'; i++) 11 { 12 13 if (i == 0) 14 next[i] = -1; 15 else if (i == 1) 16 next[i] = 0; 17 else 18 for (int p_start = i - 1; p_start > 0; p_start--) //b部分的起点总是0,p部分的终点总是i-1,p_start作为p数组的起点 19 { 20 // int flag = 0; //flag是b数组的长度 //原来我能够写出来完全是因为书本的公式,原来我还没有理解的 21 int a = 0; //a先是作为b数组的起点,然后自增到终点 22 int b = i - p_start; //b先是作为q数组的起点,然后自增到终点 23 24 while (t[a] == t[b] && b <= i - 1) 25 { 26 // flag++; 27 a++; 28 b++; 29 } 30 if (b == p_start) //这里的一些数字关系真的是太妙了,我很难解释清楚 31 { 32 next[i] = p_start; 33 break; 34 } 35 else 36 next[i] = 0; 37 } 38 } 39 return next; 40 } 41 42 //KMP实现 有了那个next数组,我们就可以知道哪些是可以跳过的 43 int KMP(char s[], char t[]) 44 { 45 int *next = find_next(t); 46 int i = 0; 47 int j = 0; 48 int begin = i; 49 while (s[i] != '\0' && t[j] != '\0') 50 { 51 if (s[i] == t[j]) 52 { 53 i++; 54 j++; 55 } 56 else 57 { 58 begin = begin + j - next[j]; 59 j = next[j]; 60 } 61 if (j == -1) 62 { 63 i++; 64 j++; 65 begin = i; 66 } 67 } 68 return begin; 69 } 70 int main(void) 71 { 72 char s[] = "ababadababac"; 73 char t[] = "ababac"; 74 int location = KMP(s, t); 75 printf("location = %d\n", location); 76 for (int i = 0; i < strlen(t); i++) 77 { 78 printf("%c ", s[location]); 79 location++; 80 } 81 return 0; 82 } 83 /* 84 输出 85 ———————————————————————— 86 location = 6 87 a b a b a c 88 ———————————————————————— 89 */
四、总结
这次虽然没能够完全理解KMP算法,但是对基本原理的印象加深了许多,并且意识到课本真的很厉害,虽然不能够很通俗易懂,但是该有的知识点都不会漏。