串的模式匹配KMP(c实现)

串的模式匹配(c实现)

KMP模式匹配的核心思想
省略一部分不必要的判断步骤(即去掉没必要的回溯步骤)

主串和匹配串分别的改变方式:
主串:是不会跳跃性改变,而只是会依次的递增比较下去
匹配串:根据匹配失败的串的后缀串与前缀串的匹配程度,从而确定回溯的位置

算法的实现:
分两块(两个函数):
First:一个能计算出匹配串中每一个位置匹配失败后,需回溯的位置的函数。
Second:一个能将匹配串和主串相比较匹配的函数。

KMP算法的重点考研考点: next数组
1.理解KMP使用前后缀来进行子串匹配:即在子串和主串比较时,j值得多少取决于当前字符之前的串的前后缀的相似程度。
在这里插入图片描述

2.next数组理解:用来高效地判断子串中是否含有相同的前后缀及匹配失败时如何利用这些信息。

在这里插入图片描述
更多例题:
在这里插入图片描述

代码实现:

///KMP模式匹配算法实现
///计算出匹配串中每一个位置匹配失败后,需回溯的位置
///即生成next数组

void get_next(String T,int *next){
	int i,j;
	int i = 1;
	int j = 0;
	next[1] = 0;
	while(i<T[0])	//	此处的T[0]表示串T的长度
	{
		if(j==0||T[i]==T[j]){
			//T[i]表示后缀的单个字符
			//T[j]表示前缀的单个字符
			++i;
			++j;
			next[i] = j; 
		} 
		else	j = next[j];	//若字符不相同,则j回溯 
	} 
} 
 #define MAX 255
///KMP模式匹配算法实现
///计算出匹配串中每一个位置匹配失败后,需回溯的位置
///即生成next数组

void get_next(String T,int *next){
	int i,j;
	int i = 1;
	int j = 0;
	next[1] = 0;
	while(i<T[0])	//	此处的T[0]表示串T的长度
	{
		if(j==0||T[i]==T[j]){
			//T[i]表示后缀的单个字符
			//T[j]表示前缀的单个字符
			++i;
			++j;
			next[i] = j; 
		} 
		else	j = next[j];	//若字符不相同,则j回溯 
	} 
} 

///返回子串T在主串S中第pos个字符之后的位置。若不存在则返回0 
int Index_KMP(String s,String T,int pos){
	int i = pos;	//i用于表示主串S当前位置下的标值
	int j = 1;
	int next[MAX];	//定义一next数组
	get_next(T,next);	//得到next数组
	while(i<=s[0]&&j<=T[0]){
		if(j==0||s[i]==T[j]){
			++i;
			++j;
		}
		else{
			j = next[j];
		}
	} 
	if(j>T[0])	return i-T[0];
	else	return 0;
} 
 
#include<stdio.h>
#include <string.h>
#define MaxSize 100
/*
	实现KMP算法:
		1.get_next(String T,int *next)//传入一个匹配串得到他的next数组
		2.Index_KMP(String S,String T)//返回模式串在匹配串中的位置
*/

//define a String,store from 1
typedef struct {
	char ch[MaxSize];
	int len;
}String;

//next[i]记录的为此前串中的最长公共前后缀的长度
//回溯的含义:当前第i个位置不匹配,但我们之前的i-1个位置都是匹配的,我们可以找到它的最长公共前后缀进行移动再比较
void get_next(String T, int* next) {
	int i, j;//只有j进行回溯
	i = 1;
	j = 0;
	next[1] = 0;
	while (i < T.len) {
		if (next[i] == next[j]) {
			i++;
			j++;
			next[i] = j;
		}
		else
		{
			j = next[i];//匹配失败进行回溯
		}
	}
		
}

int Index_KMP(String S, String T) {
	int i = 1, j = 1;
	int next[100];
	get_next(S, next);
	while (i <= S.len && j <= T.len) {
		if (j == 0 || S.ch[i] == T.ch[j]) {
			i++;
			j++;
		}
		else {
			j = next[j];
		}
	}
	if (j > T.len) {
		return i - T.len;
	}
	else
	{
		return 0;
	}
}



int main() {
	//printf("Start");
	String T;
	String S;
	T.len = 5;
	//printf("Start1");
	strcpy(T.ch,"0abbaa");
	S.len = 11;
	strcpy(S.ch, "0abbabbabbaa");
	//printf("Start2");
	
	printf(S.ch);
	printf("\n");
	printf(T.ch);
	printf("\n");
	//int next[5];
	//get_next(T, next);
	//for(int i=0;i<5;i++)
	//	printf("%d",next[i]);
	//printf("\n");

	int locat = Index_KMP(S, T);
	printf("Start3");
	printf("locat:%d", locat);
	return 0;
}


疫情期间,希望自己能放下心中的躁动,用学习丰富自己。
在这里插入图片描述

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值