【数据结构-KMP算法(学习篇)】
数据结构-KMP算法(学习篇)
- KMP算法核心
KMP算法核心
KMP 的两次 “回溯” 本质是针对不同目标的指针回退,且都围绕next数组联动,具体区别如下
另外附上代码 有需要的小伙伴可以放心取走
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAXSIZE 255
typedef struct{char *s; // 主串char *t; // 模式串
}KMPTest,*KMPTestPtr;// 构造字符串
void createString(KMPTest *str){// 分别分配内存str->s = (char*)malloc(sizeof(char) * MAXSIZE);str->t = (char*)malloc(sizeof(char) * MAXSIZE);if(str->s == NULL || str->t == NULL){printf("内存分配失败!\n");exit(1);}// 输入主串printf("请输入主串(不超过255个字符): ");fgets(str->s, MAXSIZE, stdin);// 去除fgets带来的换行符str->s[strcspn(str->s, "\n")] = '\0';// 输入模式串printf("请输入模式串(不超过255个字符): ");fgets(str->t, MAXSIZE, stdin);str->t[strcspn(str->t, "\n")] = '\0';
}// 求模式串的next数组
void getNext(char *t, int *next){int i = 0; // 模式串指针,从0开始next[0] = -1; // 第一个字符的next值为-1int j = -1; // 最长前缀后缀长度int len = strlen(t); // 模式串长度 索引 0-len-1while(i < len - 1){// 当j为-1或当前字符匹配时,i和j同时后移if(j == -1 || t[i] == t[j]){i++;j++; next[i] = j;} else {j = next[j]; // 回溯}}for(int k = 0; k < len; k++){printf("next[%d] = %d\n", k, next[k]);}
}// KMP算法
int KMP(KMPTest str){int i = 0; // 主串指针int j = 0; // 模式串指针int sLen = strlen(str.s); // 主串长度int tLen = strlen(str.t); // 模式串长度// 若模式串为空或主串长度小于模式串长度,直接返回-1if(tLen == 0 || sLen < tLen) return -1; // 创建并获取next数组int *next = (int*)malloc(sizeof(int) * tLen);// 构建next数组getNext(str.t, next);// KMP匹配过程while(i < sLen && j < tLen){if(j == -1 || str.s[i] == str.t[j]){i++;j++;} else {j = next[j]; // 模式串回溯}}free(next); // 释放next数组内存// 若模式串匹配完成,返回匹配起始位置if(j == tLen){return i - j;} else {return -1; // 未找到匹配}
}void test(){KMPTestPtr str = (KMPTestPtr)malloc(sizeof(KMPTest));createString(str);printf("主串为: %s\n", str->s);printf("模式串为: %s\n", str->t);// 执行KMP算法 返回匹配位置int position = KMP(*str);if(position != -1){printf("模式串在主串中的起始位置为: %d (从0开始计数)\n", position);} else {printf("主串中未找到模式串\n");}// 释放内存 依次释放free(str->s);free(str->t);free(str);
}int main(){test();return 0;
}