串的简单匹配和KMP算法

一.简单模式匹配。

主串str1与模式串str2,如果str1[ i ]==str2[ j ],那么j++,i++,匹配两串的下一位,如果不相符,则str1回到起始点的下一位,即 i = i - j +2,str2回到第一位,即 j =1;比较完成若 j = str2.length,则表示 j 已经比较到最后一位的下一位,也就是比较成功。

#include <stdio.h>
#define maxsize 100
#define true 1
#define false 0
typedef struct{
	char ch[maxsize];
	int length;
}Str;

void InitString(Str& str){
	str.ch[0]='\0';
	str.length=0;
}

void strAssign(Str& str,char chars[]){
	int i=0;
	while(chars[i]!='\0'){
		str.ch[i+1]=chars[i++]; 
	}
	str.length=i+1; 
}

void printString(Str str){
	if(str.length==0)
		printf("该串为空串!");
	else{
		for(int i=1;i<str.length;i++)
			printf("%c ",str.ch[i]);
		printf("\n");	
	}	 
}

int index(Str str,Str substr){
	int i=1,j=1;
	//串长包含了数组为'\0'的值,使用有效字符数为length-1;
	//如str1的length为5,则有4个有效字符,当i<length即i<=4时str.ch[i]是有效字符
	//如果i<=length,那么i<=5,但str.ch[5]超出范围; 
	while(i<str.length && j<substr.length){
		if(str.ch[i]==substr.ch[j])
		{	++i;
			++j;  }
		else{
			j=1;
			i=i-j+2;
		}
	}
	//如果是j>substr.length,也就是j大于整个子串的长度(包含了'\0');上述条件j最多加到length就退出,
	//不满足条件,所以j最大就是子串的长度,使用当j等于子串长也就是大于子串长减一时匹配成功
	//如果i=5,j=3,那么返回的位置是3,因为i,j都是匹配位的下一位,当i=4,j=2时字符相等 ,子串有效字符长度为i-j
	//也就是i=3时开始匹配,所以子串第一次出现的位置是3,返回3,也就是i-j+1; 
	if(j>substr.length-1)
		return i-substr.length+1; 
	else
		return 0;	
}


int main(){
	Str str1,str2;
	char char1[]="abcdefj";
	char char2[]="cde";
	InitString(str1);
	InitString(str2);
	strAssign(str1,char1);
	strAssign(str2,char2);
	printString(str1);
	printString(str2);
	printf("子串在主串第一次出现的起始位置为%d",index(str1,str2));
} 

二.KMP算法

           核心思想是的到子串的next数组,也就是子串的最长相等前后缀的个数,当主串与子串不匹配时,子串回溯到当前值的next[ j ]值位置开始与i(不变)重新匹配,j=next[ j ],小于 j 的就是最长相等前后缀的前缀部分,重新开始匹配后该前缀部分与最长相等前后缀的后缀部分重合,也就是说这一部分不需要多余的匹配,如果重新匹配后的str.ch[i]!=str.ch[j],那么要回溯到j=next[j],也就是j=next[ next[ j ] ]的位置重新开始与i匹配,要是最长前后前后缀值为1,则回到子串开头与第i位的主串重新匹配。

输出如下 :

代码如下:

#include <stdio.h>
#define maxsize 100
#define true 1
#define false 0
typedef struct{
	char ch[maxsize];
	int length;
}Str;

void InitString(Str& str){
	str.ch[0]='\0';
	str.length=0;
}

void strAssign(Str& str,char chars[]){
	int i=0;
	while(chars[i]!='\0'){
		str.ch[i+1]=chars[i++]; 
	}
	str.length=i+1; 
}

void printString(Str str){
	if(str.length==0)
		printf("该串为空串!");
	else{
		for(int i=1;i<str.length;i++)
			printf("%c ",str.ch[i]);
		printf("\n");	
	}	 
}

void get_next(Str substr,int next[]){
	int i=1,j=0;
	next[1]=0;  //第一位的next值为0;
	/*如:abcdabd;
	当j=0是,满足if,得到next[2]=1;
	第二轮循环,a!=b,也就是str.ch[1]!=str.ch[2],则j=next[j]=next[1]=0;
	第三轮,j=0,i=2,得到next[3]=1;
	第四轮,j=1,i=3,但a!=c,所以j=next[1]=0;
	第五轮,j=0;得到j=1,i=4,next[4]=1;
	第六轮,a!=d,所以j=0;
	第七轮,j=0;j=1,i=5,next[5]=1;
	第八轮,a=a,得j=2,i=6,next[6]=2;
	第九轮,b=b,得j=3,i=7,next[7]=3; 
	 */
	while(i<substr.length){
	if(j==0||substr.ch[i]==substr.ch[j]){
		i++;
		j++;
		next[i]=j;
	}
	else{
		j=next[j];
	}
}
	for(int i=1;i<substr.length;i++){
		printf("next[%d]=%d ",i,next[i]);
	}
	printf("\n");
}


int index(Str str,Str substr,int next[]){
	int i=1,j=1;
	while(i<str.length && j<substr.length){
			//j==0,表示子串第一个字符与主串不匹配,此时要从i的下一位i+1开始与j=1匹配; 
		if(j==0||str.ch[i]==substr.ch[j])
		{	++i;
			++j;  }
		else{
			j=next[j]; 
		}
	}
	
	if(j>=substr.length)
		return i-substr.length+1; 
	else
		return 0;	
}


int main(){
	Str str1,str2;
	char char1[]="abcdabcdabd";
	char char2[]="abcdabd";
	int next[10];
	InitString(str1);
	InitString(str2);
	strAssign(str1,char1);
	strAssign(str2,char2);
	printString(str1);
	printString(str2);
	get_next(str2,next); 
	printf("子串在主串第一次出现的起始位置为%d",index(str1,str2,next));
} 



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值