kmp模式匹配

  1. kmp 匹配的目的是 询问一个字符串s1 len(s1)<=len(s2) 是否是 字符串s2 的子串
  2. s1 叫做 pattern模式串
  3. 暴力匹配都知道
  4. abcde 前缀:a ab abc abcd abcde 真前缀不包括abced 后缀同理
  5. 所以我们求出s1prefix[]要后移一位,才是最长公共(真)前后缀

为什么prefix[]右移???

当不断比较s2[i]prefix[j] ,相同就比较下一个,不同
就把pattern串的上一个字符pattern[j-1](公共前后缀最大)的第一个后缀字符拿来与当前s2[i]比较,所以prefix[j]右移一位,j位保存的是j-1位的最长前后缀的 (第一个) 后缀下标

  • 先求出prefix[]前缀表,最长公共的(真)前后缀
    例如
aa 1
aba 1
abc 0
abcda 1

怎么求prefix[]

  • 不断的拿ilen相比较,相同则 prefix[j]=++len;
  • 不同 就 找len = prefix[len - 1]前一个字符的前子缀的最后一个字符与pattern[i]相比较,一直循环到相同即可,

prefix[]求出后,开始拿模式串进行匹配

  • 遇到不同则 比较pattern串的上一个字符的后缀字符,
  • 如果模式串上一个字符的后缀字符是-1(此时模式串在第一个字符pattern[0]),仍然将-1移到s2[i]这点来,但是不比较,那么数组模拟就是同时i++ j++去比较下一个,(实际效果与移动的效果是一样的)
// 字符串最长公共前后缀
#include 
#include 
#include 



void prefix_table(char pattern[],int prefix[],int n) {
	prefix[0] = 0; // 第一个的公共前后缀为0
	int len = 0;
	int i = 1;
	while ( i < n ) {
		if ( pattern[i] == pattern[len] ) {
			len++;
			prefix[i] = len;
			i++;
		}
		else {
			if ( len > 0 ) {  // 避免在 len = 0 的时候指向不明内存区域
				len = prefix[len - 1]; // i 此轮不变,while () 进入下一路寻找 公共子缀合
			}
			else { // len = 0
				prefix[i] = len;
				i++;
			}
		}
	}
}
// 第一个改成-1   暂时还不知道为什么
void move_prefixtable(int prefix[],int n) {
//  抹掉了最后一个prefix,
		
	for (int i = n-1; i > 0; i--) {
		prefix[i] = prefix[i-1];
	}
	prefix[0] = -1;
}
void kmp_serach(char text[] ,char pattern[]) { // text是原字符串,pattern是 需要查询的字符串 , 查询他是不是为text的子串
	int n = strlen(pattern);
	int* prefix = malloc( sizeof(int) * n); // malloc 在堆中分配内存别忘了 用指针
	prefix_table(pattern,prefix,n);
	move_prefixtable(prefix,n);

	int m = strlen(text);
	int i = 0, j = 0;
	while (i

你可能感兴趣的:(kmp模式匹配)