实现顺序串的各种模式匹配算法

Posted hzyb2018

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现顺序串的各种模式匹配算法相关的知识,希望对你有一定的参考价值。

目的:掌握串的模式匹配算法(BF和KMP )设计

内容:编写一个程序exp4-3.cpp,实现顺序串的各种模式匹配运算,并在此基础上完成以下功能:
1、建立目标串s="abcabcdabcdeabcdefabcdefg"和模式串t="abcdeabcdefab";
2、采用简单匹配算法求t在s中的位置;
3、由模式串t求next数组值和nextval数组值;
4、采用KMP算法求t在s中的位置;
5、采用改进的KMP算法求t在s中的位置;

写在前面

今天学习了如何对顺序串相关的算法,主要是看老师的PPT,问题主要分两方面:

  1. 算法的理解
  2. 算法的实现
    以下主要就从这两个方面进行讨论

算法的理解

这道题目主要涉及的算法有BF,KMP。这两个算法都是用来判定模式串t是否为目标串s的子串问题,其中BF算法感觉还挺简单的,就是从s的每一个字符开始依次与t的字符进行匹配
匹配过程如下:

  1. [S: color{red}aquad aquad aquad aquad aquad b ]

[T:color{red}aquad aquad aquad b ]

此时i=0,y=0 s[0]=t[0]
i,j继续后移,即i++, j++,直到出现s[i]≠t[j]
2. $$S: aquad aquad aquad color{red}aquad aquad b$$

[T:aquad aquad aquad color{red}b ]

此时i=3,y=3 s[3]≠t[3] 匹配失败
i回退,j重置为0(i=i-j+1,j=0)
循环执行1,2步
3. $$S: aquad aquad aquad aquad aquad color{red}b$$

[T:aquad aquad aquad color{red}b ]

此时i=6,y=4 s[6]=t[4] 匹配成功!


总的说来,BF算法的关键在于匹配失败时对i,j的处理。

算法的实现
//BF算法
int BF(SqString s,SqString t)
{
   int i=0,j=0;
   while (i<s.length && j<t.length )
   {
       if(s.data[i]==t.data[j] )
       {
           i++;
           j++;//继续匹配下一个字符,依次匹配
       }
       else
       {
           i=i-j+1;//主串的指针回溯
           j=0;
       
       }//进行下一次匹配
   }
         
   if(j>=t.length )
      
   return (i-t.length );//返回匹配的第一个位置的下标,因为是依次进行匹配,所以最终i的值会有包含字串t的长度。
   else return (-1);
      
}

在阅读这段代码的时候while语句里的循环条件:while (i<s.length && j<t.length )不是很好理解,后来仔细检查发现i,j都是从0开始,那么它们代表的是字符串中字符位置的下标,取
0--(length-1)

//主函数
int main() {
    SqString s,t;
    
    char a[]="abcabcdabcdeabcdefabcdefg",b[]="abcdeabcdefab";
    StrAssign  (s,a);
    StrAssign  (t,b);
    
    cout<<BF(s,t)<<endl;//输出结果

//类型声明,自定义函数
#define MaxSize 100
typedef struct 
{
    char data[MaxSize ];
    int length;
}SqString;//此为非紧缩存储格式

void StrAssign(SqString &s,char cstr[])
{
    int i;
    for(i=0; i<(int)strlen(cstr); i++)
        s.data[i]=cstr[i];
    s.length=i;
}//字符串的生成

KMP算法的初步理解

既然都是匹配字符串,第一步都是相同的,置$$i=0,j=0$$,对比BF算法,唯一的区别的地方就是在s[i]≠t[j]时(即匹配失败时)对i,j处理的不同

此时,在t[j]字符前若找到k个字符使得
(t_0t_1...t_{k-1}=t_{j-k}t_{j-k+1}...t_{j-1}t_j)
即t[j]前有k个字符与t开头的k个字符相等,说明t[j]字符前已有k个字符被成功匹配,
下一趟应从t[k]开始匹配,即置j为k(next[j]=k)

初读这段话,感觉真的是云里雾里,难以理解,怎么就匹配成功了呢?沉思许久,终于找到一个合理的解释
将上面那段话翻译一下:
s[i]前有k个字符与t开头的k个字符相等,说明t开头的k个字符被成功匹配,因为此时s[i]与t[j]前的字符是已经匹配好了的。


小结

至此KMP算法的核心思想总算初步搞明白了,只是还有许多细节的地方感觉不是很懂,在算法实现的时候对求next数组部分感到难以理解,看来还是没有理解透彻,"革命尚未成功,同志仍需努力"呀

写在最后

这是笔者第一篇关于学习记录的博客,在写作过程遇到了许多问题,好在总算完成了,因为记忆力不好,希望以这种方式记录下自己的思考过程,最后,哪怕前路漫漫,也愿以笔为刃,与诸君共勉。

以上是关于实现顺序串的各种模式匹配算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构—串KMP模式匹配算法

《数据结构(C语言版)》之“串的模式匹配算法”

字符串的模式匹配算法

求出子串(模式串)的next函数值,利用kmp算法实现模式与主串的匹配算法

数据结构学习笔记——串的基本知识(顺序存储结构实现串)

串串的模式匹配算法(子串查找)BF算法KMP算法