KMP 解决串的模式匹配问题

论坛 期权论坛     
选择匿名的用户   2021-5-23 11:51   144   0
<div class="blogpost-body" id="cnblogs_post_body">
<h1><span style="font-size:24px;">初学KMP的时候,一直不得要领。后来学习AC自动机的时候,一下子明白了KMP实际上是AC自动机的特殊情况。<br></span></h1>
<h1><span style="font-size:24px;">首先贴三段代码,一组是回溯法,暴力求解,另外两个是KMP串模式匹配</span></h1>
<div>
  <pre class="blockcode"><code class="language-cpp">/*
   回溯法字符串匹配算法就是用一个循环来找出所有有效位移,
   该循环对n-m&#43;1个可能的位移中的每一个index值,检查条件为P[0…m-1]&#61; S[index…index&#43;m-1]
   (因为模式串的长度是m,索引范围为0…m-1)。该算法思维比较简单(但也常被一些公司做为面试题),
   很容易分析出本算法的时间复杂度为O(pattern_length*target_length)
   int search(char const*, int, char const*, int)
   查找出模式串patn在主串src中第一次出现的位置
   plen为模式串的长度
  返回patn在src中出现的位置,当src中并没有patn时,返回-1

*/
int search(char const* src, int slen, char const* patn, int plen)
{
int i &#61; 0, j &#61; 0;
while( i &lt; slen &amp;&amp; j &lt; plen )
{
  if( src[i] &#61;&#61; patn[j] )  //如果相同,则两者&#43;&#43;,继续比较
  {
   &#43;&#43;i;
   &#43;&#43;j;           
  }
  else
  {
   //否则,指针回溯,重新开始匹配
   i &#61; i - j &#43; 1;  //退回到最开始时比较的位置
   j &#61; 0;
  }
}
if( j &gt;&#61; plen )
  return i - plen;  //如果字符串相同的长度大于模式串的长度,则匹配成功
else
  return -1;
}</code></pre>
  <div>
   <pre class="blockcode"><code class="language-cpp">/*
  KMP算法可以在O(n&#43;m)的时间数量级上完成串的模式匹配操作。
  其基本思想是:每当匹配过程中出现字符串比较不等时,不需回溯i指针,
  而是利用已经得到的“部分匹配”结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
  算法的核心关键在于查找匹配串的码表(确定部分匹配后要滑动距离)
*/

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
int index_KMP(char *s,char *t,int pos);
void get_next(char *t,int *);
   
char s[10]&#61;&#34;abcacbcba&#34;;
char t[4]&#61;&#34;bca&#34;;
int next[4];
int pos&#61;0;

int main()
{
    int n;
    get_next(t,next);
    n&#61;index_KMP(s,t,pos);
    printf(&#34;%d&#34;,n);
    return 0;
}

int index_KMP(char *s,char *t,int pos)
{
    int i&#61;pos,j&#61;1;
    while (i&lt;&#61;(int)strlen(s)&amp;&amp;j&lt;&#61;(int)strlen(t))
    {
        if (j&#61;&#61;0||s[i]&#61;&#61;t[j-1])
        {
            i&#43;&#43;;
            j&#43;&#43;;
        }
        else j&#61;next[j];
    }
    if (j&gt;(int)strlen(t))
        return i-strlen(t)&#43;1;
    else
        return 0;
}

void get_next(char *t,int *next)
{
   
    int i&#61;1,j&#61;0;
    next[0]&#61;next[1]&#61;0;
    while (i&lt;(int)strlen(t))
    {
        if (j&#61;&#61;0||t[i]&#61;&#61;t[j])
        {
            i&#43;&#43;;
            j&#43;&#43;;
            next[i]&#61;j;
        }
        else j&#61;next[j];
    }
   
}</code></pre>
   <pre class="blockcode"><code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;time.h&gt;
#include &lt;string.h&gt;

int next[1000];  //记录跳转位置
int kmp_next(char *base)
{
    int i,j;
    i&#61;0;     
    j&#61;-1;
    next[0]&#61;-1;      //记录第一个字符的跳转位置为-1
    while(base[i]!&#61;&#39;\0&#39;)
    {
        //如果跳转到-1,说明只能从头开始匹配;
        //如果当前匹配点和跳转后的匹配点匹配
        if(j&#61;&#61;-1||(base[i]&#61;&#61;base[j]))
        {
           //查看下一匹配点的情况
           i&#43;&#43;;
           j&#43;&#43;;
           //如果下一匹配点还是匹配的,则下一跳地址一样
           if(base[i]&#61;&#61;base[j])
           {
               next[i]&#61;next[j];
           }
           //如果一匹配点不匹配,则下一跳地址为当前前缀地址
           else
           {
               next[i]&#61;j;
           }
        }
        else
        {
            j&#61;next[j];
        }
    }
}

int kmp(char *b,char *base)
{
     int i,j;
     i&#61;0;j&#61;0;
     //通过跳转数组,进行快速匹配
     while(b[i]!&#61;&#39;\0&#39;&amp;&amp;base[j]!&#61;&#39;\0&#39;)
     {
        if(b[i]&#61;&#61;base[j])
        {
            i&#43;&#43;;j&#43;&#43;;
        }
        else
        {
            j&#61;next[j];
            if(j&#61;&#61;-1)
            {
               i&#43;&#43;;j&#43;&#43;;
            }
        }
     }
     if(base[j]&#61;&#61;&#39;\0&#39;)
     {
         return i-j;
     }
     else
         return -1;
}

int main()
{
      char base[]&#61;&#34;abacba&#34;;
      char b[1000];
      kmp_next(base);
      for(int i&#61;0;i&lt;strlen(base);i&#43;&#43;)
      {
          printf(&#34;%d &#34;,next[i]);
      }
      printf(&#34;\n %s\n&#34;,base);
      while(scanf(&#34;%s&#34;,b)!&#61;EOF)
      {
          printf(&#34;%d \n&#34;,kmp(b,base));                  
      }
    system(&#34;pause&#34;);
}
</code></pre>
   <h2 style="color:rgb(51,51,51);font-family:Arial;line-height:
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP