数码资讯
串的模式匹配算法
串的模式匹配算法
目录- 串的模式匹配算法
- BF(Brute-Force)算法
- 算法步骤
- 算法实现
- KMP算法
- 定义
- 核心思想
- 举例说明
- 实现
- next函数
- 算法实现
- next函数背后的原理
- 图解原理
- 算法的改进
- BF(Brute-Force)算法
BF(Brute-Force)算法#
模式匹配不一定是从主串的第一个位置开始,可以指定主串中查找的起始位置pos。如果采用字符串顺序存储结构,可以写出不依赖于其他串操作的匹配算法。
算法步骤#
-
分别利用计数指针
? 和? 指示主串? 和模式串? 中当前正待比较的字符位置,? 初值为 pos,? 初值为 1。 -
如果两个串均未到串尾,即
? 小于等于? 的长度且? 小于等于? 的长度时,则循环执行以下操作:-
?[?] 和?[?] 比较,若相等,则? 和? 分别指示串中下个位置,继续比较后序字符; -
若不等,指针后退重新开始匹配,从主串的下一个字符
(?=?−?+2) 起重新和模式串的第一个字符(?=1) 比较。
-
-
如果
? 大于? 的长度,说明模式串? 中的每个字符依次和主串? 中的一个连续的字符序列相等,则匹配成功,返回和模式串? 中第一个字符相等的字符在主串? 中的序号(?−?的长度) ;否则称匹配不成功,返回0。
下面的一系列图展示了模式串
算法实现#
int StrIndex_BF(SString S,SString T,int pos)
{
int i,j;
if(pos <= 1 && pos <=S[0]){
i = pos;
j = 1;
while(i <= S[0] && j <= T[0]){
if(S[i] == T[j]){
i++;
j++;
}
else{
i = i - j + 2;
j = 1;
}
}
if(j > T[0])
return i - T[0];
else
return 0;
}
else{
return 0;
}
}
KMP算法#
定义#
该算法是由Knuth、Morris和Pratt同时设计实现的,因此简称KMP算法。其相较于BF算法,改进在于:每当一趟匹配过程中出现字符比较不相等时,不需要回溯i指针,而是利用已经得到的“部分匹配”的结果将模式串向右“滑动”尽可能远的一段距离后,继续进行比较。
核心思想#
移动模式串,使模式串中的公共前后缀里面的前缀移动到后缀的位置。
举例说明#
回顾BF匹配算法的过程示例,在第三趟的匹配中,当
现在再来讨论一般情况。假设主串为
假设此时应与模式串中第
而已经得到的"部分匹配"的结果是:
由上面两个式子可以推得下列等式:
反之,若模式 串中存在满足式(3)的两个子串,则当匹配过程中,主串中第
视频学习地址:KMP算法通俗易懂视频
实现#
若令
next函数#
- 从头开始的
?−1 个元素就是字符串的前缀 ? 前面的?−1 个元素就是字符串的后缀
举例如下:
在求得模式串的
算法实现#
//KMP算法实现过程
int StrIndex_KMP(SString S,SString T,int pos)
{
int i,j;
if(1 <= pos && pos <= S[0]){
i = pos;
j = 1;
while(i <= S[0] && j <= T[0]){
if( j == 0 || S[i] == T[j]){
i++;
j++;
}
else{
j = next[j];
}
}
if(j > T[0])
return i - T[0];
else
return 0;
}
esle{
return 0;
}
}
//next函数求取过程
void Get_Next(SString T,int next[])
{
int i = 1,j = 0;
next[1] = 0;
while(i < T[0]){
if(j == 0 || T[i]==T[j]){//T[i]表示后缀的单个字符,T[j]表示前缀的单个字符
i++;
j++;
next[i] = j;
}
else{
j = next[j];//若字符不相同,则j值回溯至字符相等或者j=0处
}
}
}
next函数背后的原理
- 求
????[?+1] ,则已知????[1]、????[2]⋯????[?] ; - 假设
????[?]=? ,则有?1?2⋯??−1=??−?+1??−?+2⋯??−1 (前?−1 位字符与后?−1 位字符重合); - 如果
??=?? ,则有?1?2⋯??−1??=??−?+1??−?+2⋯?? ,则此时????[?+1]=?+1 ,否则进入下一步; - 此时,
??≠?? ,假设????[?]=?1 ,则有?1⋯??1−1=??−?1+1⋯??−1 (前?1−1 位字符与后?1−1 位字符重合); - 第二第三步联合得到:
?1⋯??1−1=??−?1+1⋯??−1=??−?1+1⋯??1−?+?−1=??−?1+1⋯??−1 - 这时候,再判断如果
??1=?? ,则?1⋯??1−1??1=??−?1+1⋯??−1?? ,则????[?+1]=?1+1 ;否则再取????[?1]=?2
图解原理
2.求
- 如果
?8=?16 ,则非常明显可以看出????[17]=8+1=9
- 如果
?8≠?16 ,再假设????[8]=4 ,则有下图所示的关系:
从而又可以推出下图中所示的四个部分重合,此时需要再进行判断
-
如果
?4=?16 ,从上图可以看出有:?1⋯?4=?13⋯?16 ,则此时????[17]=4+1=5 -
如果
?4≠?16 ,再假设????[4]=2 ,此时有下图所示的关系:
- 此时,如果
?2=?16 ,则????[17]=2+1=3 - 如果
?2≠?16 ,?2=1 ,????[1]=0 ,遇到0时还没有结束,则递推结束,此时????[17]=1
视频学习地址:next函数代码理解视频
算法的改进#
前面定义的
//nextval函数求取过程
void Get_Next(SString T,int nextval[])
{
int i = 1,j = 0;
nextval[1] = 0;
while(i < T[0]){
if(j == 0 || T[i]==T[j]){
i++;
j++;
if(T[i] != T[j])
nextval[i] = j;
else
nextval[i] = nextval[j];
}
else{
j = nextval[j];
}
}
}