/** * 看了 b站视频 BV1jb411V78H 对KMP有了一点理解,然后我写了这个代码 * 这个代码和视频里面的有一点不同,字符串是从 0 开始的,而不是从1 开始的 * 希望能够帮到学习KMP的人 */ #include <stdbool.h> #include <malloc.h> #include "KMP.h" // KMP.h 内容 /* #define MAXSIZE (255) typedef struct { char ch[MAXSIZE + 1]; int length; }SString; void Next(SString const *t); extern int *next; int IndexOf_KMP(SString const *s, SString const *t); */ int *next; // 计算 next数组 /** * 计算 0-based 模式串t的next数组 * @param t 模式串 */ void Next(SString const *t) { // 模式串 0 开始 int length = t->length; // 分配 next数组 所需要的空间 next = (int *)malloc(sizeof(int) * length); for (int *p = next; p < next + length; p++) { *p = 0; } for (int i = 0; i < length; i++) { if (i <= 1) // 前两个next[i]置为-1 { next[i] = -1; continue; } // 执行下面的语句的时候, 一定有 i >= 2 int maxlen = 0; // 存储最长公共前后缀的长度 /** * // len 表示前缀或后缀的最大长度, 可取的值是 [1..i-1] // i 为(模式串或next数组)的访问下标 * 这里主要是 对 模式串在i位置 求 它的最大公共前后缀的长度 * 从 1 开始 到 i-1 一个一个去试 * */ for (int len = 1; len < i; len++) { int val = 0; bool flag = false; for (int j = 0, k = i - len; j < len; j++, k++) { if (t->ch[j] == t->ch[k]) { } else { flag = true; // len 长度的公共前后缀匹配失败 break; } } if (flag == false) // 公共前后缀长度为len val = len; if (val > maxlen) // 这个比较不是必须的,因为找公共前后缀的长度的时候, len 从 1 到 i-1 maxlen = val; // maxlen 就是 next[i]的值了 } next[i] = maxlen; } } // 调用这个函数之前,一定要调用 Next函数,为模式串构建 next数组 int IndexOf_KMP(SString const *s, SString const *t) { // 开始匹配 int i = 0, j = 0; // i 表示主串的下标, j 表示模式串的下标 while (i < s->length) { if (j == -1 || s->ch[i] == t->ch[j]) { i++; j++; } else { j = next[j]; } // 匹配成功 if (j == t->length) { return i - t->length; } } // 匹配失败 return -1; }
模式串 从 0 开始的KMP算法
内容版权声明:除非注明,否则皆为本站原创文章。