模式匹配算法
前言
对于数据结构中串的章节,最为重要的莫过于串的模式匹配算法:即为求给定子串在主串中的出现的位置。从最开始的朴素模式匹配到后来的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;//没有找到子串
}
算法思想步骤:
- i为主串S的字符指针,j为模式的字符指针
- 令i指向pos代表的字符,j指向模式第一个字符
- 令S[i]和T[j]进行比较
- 若相等,则i++,j++
- 若不相等,i=i-j+2,j=1
- 转步骤[3]
- 匹配成功:
模式T中的每个字符依次和主串S中的一个连续字符序列相等。函数值为该对应相等连续字符序列中第一个字符在主串S中的位置- 匹配不成功:函数值返回0
- 一般情况下的时间复杂度:O(m+n)
- 最坏情况下的时间负责度:O(m*n)
- 缺点:主串中存在多个与模式字符串“部分匹配”的子串,因此导致指针i的不断回溯
KMP模式匹配算法
改进的点:
在每一趟匹配过程中出现字符串比较不相等时,不需要回溯指针i,而是利用已经匹配得到的结果,将模式尽可能向右滑动一段距离,继续比较。
问题解决思路:
- 问:当主串和模式匹配过程出现不相等,该怎么办?
答:避免将指针i回溯,i保持不动,尝试将模式进行右滑- 问:将模式右滑的是指什么?
答:i指针不变,找到下一个与i指针指向字符进行比较的模式中的字符- 问:右滑的意义在哪?为什么要右滑?
答:利用上轮匹配得到部分的“匹配结果”,提高查找模式串的效率,避免指针i不断回溯导致的效率低下,只要让j进行回溯就好- 问:假设我们有匹配结果,即失配的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}p1p2pi…pj−1=si−j+i…si−1.- 问:如何利用部分“匹配结果”?
答:假设存在: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}p1p2pi…pk−1∈p1p2pi…pj−1且有: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} Si−k+1Si−k+2…si−1∈si−j+i…si−1 并且有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



被折叠的 条评论
为什么被折叠?



