字符串的模式匹配算法

模式匹配算法

前言

对于数据结构中串的章节,最为重要的莫过于串的模式匹配算法:即为求给定子串在主串中的出现的位置。从最开始的朴素模式匹配到后来的KMP算法,再到改良的KMP算法,算法逐渐改良,理解难度也逐渐加大。本人曾经多次阅读相关内容,怪于自身理解能力有限仅一知半解,但心中甚为挂念。今再次读之理解更深入之,遂记之以铭后效。

注解:

本文字符串结构皆为顺序存储结构,且使用下标为0的数组分量表示字符串的长度
主串标记为字符数组S,子串或者模式注为字符数组T


朴素模式匹配算法

//返回子串T在主串S中第pos个字符开始之后的位置。不存在返回0
int Index(SString S,SString T,int pos)
{
	int i=pos,j=1;//i是主串的字符指针,j是模式的字符指针
	while(i<=S[0]&&j<=T[0])
	{
		if(S[i]==T[j])//
		{
			i++;
			j++;
		}else{
			i=i-j+2;//对i进行回溯,回溯到pos的后续位置
			j=1;//j回溯到1
		}
	}
	if(j>T[0])
		return i-T[0];//返回子串在pos之后的第一个位置
	else
		return 0;//没有找到子串
}

算法思想步骤

  1. i为主串S的字符指针,j为模式的字符指针
  2. 令i指向pos代表的字符,j指向模式第一个字符
  3. 令S[i]和T[j]进行比较
    • 若相等,则i++,j++
    • 若不相等,i=i-j+2,j=1
  4. 转步骤[3]
  • 匹配成功:
    模式T中的每个字符依次和主串S中的一个连续字符序列相等。函数值为该对应相等连续字符序列中第一个字符在主串S中的位置
  • 匹配不成功:函数值返回0
  • 一般情况下的时间复杂度:O(m+n)
  • 最坏情况下的时间负责度:O(m*n)
  • 缺点:主串中存在多个与模式字符串“部分匹配”的子串,因此导致指针i的不断回溯

KMP模式匹配算法

改进的点:
在每一趟匹配过程中出现字符串比较不相等时,不需要回溯指针i,而是利用已经匹配得到的结果,将模式尽可能向右滑动一段距离,继续比较。

问题解决思路:

  1. 问:当主串和模式匹配过程出现不相等,该怎么办?
    答:避免将指针i回溯,i保持不动,尝试将模式进行右滑
  2. 问:将模式右滑的是指什么?
    答:i指针不变,找到下一个与i指针指向字符进行比较的模式中的字符
  3. 问:右滑的意义在哪?为什么要右滑?
    答:利用上轮匹配得到部分的“匹配结果”,提高查找模式串的效率,避免指针i不断回溯导致的效率低下,只要让j进行回溯就好
  4. 问:假设我们有匹配结果,即失配的j>1,那么上轮匹配得到的“匹配结果”是什么?
    答:假设是S[i]!=T[j]导致发生失配,则之前的匹配结果为:
    p1p2pi…pj−1=si−j+i…si−1. \begin{aligned}p_{1}p_{2}p_{i}\ldots p_{j-1}=s_{i-j+i}\ldots s_{i-1}\\ .\end{aligned}p1p2pipj1=sij+isi1.
  5. 问:如何利用部分“匹配结果”?
    答:假设存在:p1p2pi…pk−1∈p1p2pi…pj−1 p_{1}p_{2}p_{i}\ldots p_{k-1}\in p_{1}p_{2}p_{i}\ldots p_{j-1}p1p2pipk1p1p2pipj1且有:Si−k+1Si−k+2…si−1∈si−j+i…si−1 S_{i-k+1}S_{i-k+2}\ldots s_{i-1}\in s_{i-j+i}\ldots s_{i-1} Sik+1Sik+2si1sij+isi1 并且有p1p2pi…pk−1=Si−k+1Si−k+2…si−1 p_{1}p_{2}p_{i}\ldots p_{k-1}=S_{i-k+1}S_{i-k+2}\ldots s_{i-1}p1p2
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值