数据结构 - 串的模式匹配

模式串: 想要在主串中找到某个子串

串的模式匹配: 设有主串s和子串t, 子串t的定位就是在主串s中找到一个与子串t相等的子串

通常把主串s成为目标串, 把子串t成为模式串, 模式串在子串的定位称作模式匹配

模式匹配算法

简单模式匹配

假设s=“40815150” , t=“150” 进行简单模式匹配
在这里插入图片描述
最终结果: i = 6 ; j = 1
在这里插入图片描述
基本思路:
从目标字符串的第一个字符开始和模式串的第一个字符比较:
若相等, 则继续逐个比较后续的字符;
否则, 从目标串下一个字符开始重新与模式串t的第一个字符进行比较

箱单模式匹配代码

int Index(SString S, SString T){
	int k = 1;
	int i = k, j = 1;
	while(i<=S.length && j<T.length){
		if(S.ch[i]==T.ch[i]){
			++i;
			++j;//继续比较后续字符串
		}else{
			k++;//检查后续字符串
			i=k;
			j=1;
		}
	}
	if(j>T.length){
		return k;
	}else{
		return 0;
	}
}

算法的性能分析:
假设主串s的长度为n, 模式串的长度为m, 进行简单模式匹配
最好的情况下, 匹配成功, 时间复杂度为O(m)
在这里插入图片描述
最好的情况: 匹配失败, 时间复杂度为O(n-m+1)
在这里插入图片描述
最坏情况: 匹配成功, 比较(n-m+1)*m次, 时间复杂度为O(nm)
在这里插入图片描述
最坏情况: 匹配失败, 比较(n-m+1)*m次, 时间复杂度为O(mn)

KMP算法

假设S为’abaabaabaabaabc’, 模式串t为’abaabc’

简单模式算法匹配, 每次失配后都要一格一格往后移动, 所以指针i经常回溯

能不能让主串i不回溯, 只让j回溯

KMP算法思路
消除了主串指针的回溯, 从而使算法效率有了某种程度的提高
在每趟匹配的过程中, 当发生字符比较不相等时, 不回溯i指针, 而是利用已经得到的部分匹配结果, 将模式串向右滑动尽可能远的一段距离后, 继续进行比较
在这里插入图片描述
前缀: 指除最后一个字符以外, 字符串的所有头部子串

后缀: 指除第一个字符外, 字符串的所有尾部子串

公共前后缀: 前缀和后缀相等的部分

最大公共前后缀: 前缀和后缀的最长相等前后缀长度

部分匹配值: 最大公共前后缀的长度;

next数组值: 当前位置之前子串的部分匹配值+1, next[1]默认值为0
在这里插入图片描述
求模式串T的next数组

void get_next(SString T, int next[]){
	int i=1, j=0;
	next[1]=0;
	while(i<T.length){
		if(j==0||T.ch[i]==T.ch[j]){
			++i;
			++j;
			next[i]=j;	
		}else{
			j = next[j];	
		}
	}
}
KMP算法
int Index_KMP(SString S, SString T, int next[]){
	int i =1, j=1;
	while(i<S.length&& j<T,length){
		if(j==0||S.ch[i]==T.ch[j]){
			++i;
			++j;/继续比较后续字符
		}else{
			j=next[j];//模式串向右移动	
		}
		if(j>T,length){//匹配成功
			return i-T.length;
		}else{
			return 0;
		}
	}
}

改进的KMP算法

nextval数组的求法:
判断当前位置元素与next[i]比较:
若相同: 则nextval [i] = nextval [ next [i] ];
相当于nextval数组保存实际需要比较开始的位置
若不同,则nextval [ i ] = next [ i ]
在这里插入图片描述
改进的KMP算法的代码

void get_nextval(SString T, int next[]){
	for(int j=2; j<T.length; j++){
		if(T.ch[next[j]]==T.ch[j]){
			nextval[j] = nextval[next[j]];//跳到实际要开始比较的地方	
		}else{
			nextval[j] = next[i];	
		}
	}
}

时间复杂度是(M+N)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

稻田里展望者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值