04-串的模式匹配

04-串的模式匹配

串-基础

串的顺序存储结构

定长的存储结构
typedef struct{
	char str[maxSize+1];
	int length;
}Str;

maxSize为已经定义的常量,表示串的最大长度;

str数组长度定义为maxSize+1,是因为多出一个’\0’作为结束标记。

变长的存储结构
typedef struct{
	char *ch;
	int length;
}Str;

Eg:

Str S;
S.length = L;//L表示串长度
S.ch = (char*)malloc((L+1) * sizeof(char));//**********************
S.ch[length范围内位置] = 某字符变量;
某字符变量 = S.ch[length范围内位置];
free(S.ch);

串的基本操作

赋值操作
typedef struct{
	char *ch;
	int length;
}Str;
int strAssign(Str &str,char *ch){
	if(str.ch)
		free(str.ch);
	int len = 0;
	char *c = ch;
	while(*c){
		++len;
		++c;
	}
	if(len == 0){
		str.ch = NULL;
		str.length = 0;
		return 1;
	}else{
		str.ch = (char*)malloc(sizeof(char) * (len+1));
		//判断内存中是否还有空间,即malloc分配空间是否成功
		if(str.ch == NULL){
			return 0;
		}else{
			c = ch;
			for(int i=0;i<len;++i,++c){
				str.ch[i] = *c;
			}
			str.length = len;
			return 1;
		}
	}
}
取串长度操作
typedef struct{
	char *ch;
	int length;
}Str;
int strLength(Str str){
	return str.length;
}
串比较操作

设两串C1和C2中待比较字符分别为a和b;

1.若ASCIIa<ASCIIb,则返回C1<C2标记(一个负数);

2.若ASCIIa>ASCIIb,则返回C1>C2标记(一个正数);

3.若ASCIIa=ASCIIb,则按照之前的规则继续比较两串中下一对字符;

4.经过上述步骤没有比较出C1和C2的大小情况下,先结束的串为较小串,两串同时结束则返回两串相等标记(0);

typedef struct{
	char *ch;
	int length;
}Str;
int strCpmpare(Str s1,Str s2){
	for(int i=0;i<s1.length&&i<s2.length;++i){
		if(s1.ch[i]!=s2.length[i]){
			return s1.ch[i] - s2.ch[i];//拿两个字母的ASCII码做减法
		}
	}
	return s1.length - s2.length;
}
串连接操作
typedef struct{
	char *ch;
	int length;
}Str;
int concat(Str &str,Str str1,Str str2){
	if(str.ch){
		free(str.ch);
		str.ch = NULL;
	}
	str.ch = (char*)malloc(sizeof(char) * (str1.length+str2.length+1));
	if(!str.ch) return 0;//分配空间失败则整个函数执行失败
	int i=0;
	while(i<str1.length){
		str.ch[i]=str1.ch[i];
		++i;
	}
	int j=0;
	while(j<=str2.length){
		str.ch[i+j]=str2.ch[j];
		++j;
	}
	str.length = str1.length + str2.length;
	return 1;
}
求子串操作
typedef struct{
	char *ch;
	int length;
}Str;
//从str取一个以pos为起点长度为len的子串,substr存储的是截取到的结果
int getSubString(Str &substr,Str str,int pos,int len){
	if(pos<0 || pos>=str.length || len<0 || len>str.length-pos) return 0;
	if(substr.ch){
		free(substr.ch);
		substr.ch=NULL;
	}
	if(len==0){
		substr.ch=NULL;
		substr.length=0;
		return 1;
	}else{
		substr.ch = (char*)malloc(sizeof(char) * (len+1));
		int i=pos;
		int j=0;
		while(i<pos+len){
			substr.ch[j]=str.ch[i];
			++i;
			++j;
		}
		substr.ch[j]='\0';
		substr.length=len;
		reutn 1;
	}
}
串清空
typedef struct{
	char *ch;
	int length;
}Str;
int clearString(Str &str){
	if(str.ch){
		free(str.ch);
		str.ch=NULL;
	}
	str.length = 0;
	return 1;
}

KMP算法(快速从母串中找出子串)

公共前后缀的长度 < 子串的长度;

主串比较的当前位置 = 最大公共前后缀长度+1;

i可以不动,我们只需要移动j

img

利用已经部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置

KMP的重点就在于当某一个字符与主串不匹配时,我们应该知道j指针要移动到哪?

img

C和D不匹配了,我们要把j移动到哪?显然是第1位。为什么?因为前面有一个A相同啊

img

如下图也是一样的情况:

img

可以把j指针移动到第2位,因为前面有两个字母是一样的:

img

至此我们可以大概看出一点端倪,当匹配失败时,j要移动的下一个位置k。存在着这样的性质:最前面的k个字符和j之前的最后k个字符是一样的。

在这里插入图片描述

void getNext(Str substr, int next[]){
	int j=1,t;
	next[1]=0;
	while(j<substr.length){
		if(substr.ch[j] == substr.ch[t]){
			next[j+1] = t+1;
			++j;
			++t;
		}else{
			t=next[t];
		}
	}
}

int KMP(Str str,Str substr,int next[]){
	int i=1,j=1;
	while(i<=str.length && j<=substr.length){
		if(j==0||str.ch[i]==substr.ch[j]){
			++i;
			++j;
		}else{
			j=next[j];
		}
	}
	if(j>substr.length){
		return i=substr.length;
	}else{
		return 0;
	}
}

KMP算法改进

求解nextval数组

image-20211026230849587
void getNextval(Str substr, int nextval[], int next[]){
	int j=1,t;
	nextval[1]=0;
	while(j<substr.length){
		if(t=0||substr.ch[j] == substr.ch[t]){
			if(substr.ch[j+1]!=substr.ch[t+1]){
				nextval[j+1]=t+1;
			}else{
				nextval[j+1]=nextval[t+1];				
			}
			++j
			++t;
		}else{
			t=nextval[t];
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Black_Me_Bo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值