• KMP复习整理


    现在看来下面写的不是很好,以后在整理

    next数组的求法及原理应该注意的是由于在编号的时候将next中的第一个元素编排成0了,因此next[i]其实记录不但是与从开头的对称数,并且是i+1所要匹配的元素的下标

    当出现失配的情况时,如下图在str[14]!=str[7]的时候,就接着进行如下操作


    也就是说再接着从失配的位置(7)之前的那个字母在重新匹配,但是这时实际应该是从开头的那个位置来说的所以是匹配的3位置,而不是6位置,再好好想想。。。

    #include <iostream>
    #include <cstring>
    using namespace std;
    int main ()
    {
     char str[1000];
     cin>>str;
     int next[1000];
     int len=strlen(str);//模式字符串长度。
     next[0]=0;
     for(int i=1; i<len; i++)
     {
      int k=next[i-1];
      while( str[i] != str[k]  &&  k!=0 )
       k=next[k-1];     //继续递归
      if( str[i] == str[k])//找到了这个子对称,或者是直接继承了前面的对称性,这两种都在前面的基础上++
       next[i]=k+1;
      else
       next[i]=0;       //如果遍历了所有子对称都无效,说明这个新字符不具有对称性,清0
     }
     return 0;}

    较为低级的求next数组的方法

    //这中算法是字母的下标和next数组中的下标正好相等了,也就是说这样求的next数组所储存的值
    //正好相当于从开头开始计算的连续字母数,但是这样虽看起来挺好的,都储存了各自的next数组量
    //但是不好用,在查询的时候没有结束标志,整体来说这样的话操作 相对容易

    #include <iostream>
    #include <cstring>
    using namespace std;
    int main ()
    {
     char str[1000];
     cin>>str;
     int next[1000];
     int len=strlen(str);//模式字符串长度。
     next[0]=0;
     int i;
     for(i=1; i<len; i++)
     {
      int k=next[i-1];//k是记录的当前字母的前一个
      while( str[i] != str[k]  &&  k!=0)//如果没有找到相同的且不是到next[]为零或者是第一个(即为第一个数)
       k=next[k-1];     //继续递归
      if( str[i] == str[k])//找到了这个子对称,或者是直接继承了前面的对称性,这两种都在前面的基础上++
       next[i]=k+1;
      else
       next[i]=0;       //如果遍历了所有子对称都无效,说明这个新字符不具有对称性,清0
     }
        for(i=0; i<len; i++)
      cout<<str[i]<<"  ";
      cout<<endl;
        for(i=0; i<len; i++)
      cout<<next[i]<<"  ";
     return 0;
    
    }
    
    <img src="http://img.blog.csdn.net/20140912193849256?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDY2NTAxMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />


     

    以上的是这种方式不好找结束条件,不是很好,下面的稍作修改就有了...

    使用较为低级的方法求next数组的方法匹配

    #include<iostream>
    #include<string>
    #include<cstring>
    using namespace std;
    const int maxsize=100;
    void getnext(string str,int next[])
    {
     int len=str.length();//模式字符串长度。
     next[0]=-1;
     next[1]=0;
     int i;
     for(i=1; i<len; i++)
     {
      int k=next[i-1];
      while( str[i] != str[k]  &&  k!=0 && k!=-1 )//如果没有找到相同的且不是到next[]为零或者是第一个(即为第一个数)
       k=next[k-1];     //继续递归
      if( str[i] == str[k])//找到了这个子对称,或者是直接继承了前面的对称性,这两种都在前面的基础上++
                            //这个地方如果k是-1的时候不会报错,并且也正好不满足这个条件,所以这样就会运行处正确的结果
       next[i+1]=k+1;
      else
       next[i+1]=0;   //如果遍历了所有子对称都无效,说明这个新字符不具有对称性,清0
     }
    }
    void kmpindex(string s,string t)
    {
     int next[maxsize],i=0,j=0;
     memset(next,-1,sizeof(next));
     getnext(t,next);
     j=0;
                        /*  while(j<t.length())
                          {
                           cout<<t[j]<<"   ";
                           j++;
                          }
                           j=1;
                           cout<<endl;
                          while(j<t.length())
                          { 
                           cout<<next[j]<<"   ";
                           j++;
                          } */
     int m=1;
     j=0;
     while( i<s.length() && j<int(t.length()) )//s为原串(主串 目标串),t为匹配串(模式串)
     { 
      if( j==-1 || s[i] == t[j] )
       i++,j++;
      else
       j=next[j],m++;//返回的时候在增加一趟
      // 其实,为什么没有用到next[]最后一个,这是因为在每一次用到的是上一个字母的位置,至于最后一个是没有用到的
     }
                                                                                      //    cout<<endl<<"*******************************************"<<endl;
     if(j=int(t.length() ))               //说明匹配串已经遍历完毕了,也就是说匹配成功了
           cout<<m<<' '<<i-t.length()+1<<endl;    //匹配成功时第一个字母的位置   
     else
      cout<<0<<endl;
                                                                                          // cout<<"*******************************************"<<endl;
    }
    int main()
    {
     string a,b;
     cin>>a>>b;
     kmpindex(a,b);
     return 0;
    }
    
    



    /*一直不太清楚为什么在next数组中没有左最后一个的值,其实原因很简单,就是用不到

    因为在匹配时是从该字母的上一个的*/

    #include<iostream>
    #include<string>
    #include<cstring>
    using namespace std;
    const int maxsize=100;
    void getnext(string t,int next[])
    {
     int j,k;
     j=0; k=-1;
     next[0]=-1;
     while(j<t.length())
     {
      if(k==-1 ||t[j]==t[k])
      {
       j++;
       k++;
       next[j]=k;
      }
      else
       k=next[k];
     }
                                                                     // cout<<"j"<<"   "<<j<<endl;
    }
    void kmpindex(string s,string t)
    {
     int next[maxsize],i=0,j=0;
     memset(next,-1,sizeof(next));
     getnext(t,next);
     j=0;
     cout<<' ';
                    /* while(j<t.length())
                     {
                      cout<<t[j]<<"   ";
                      j++;
                     }
                      j=0;
                     cout<<endl;
                     while(j<t.length())
                     { 
                      cout<<next[j]<<"   ";
                      j++;
                     }*/
     int m=1;
     j=0;
     while( i<s.length() && j<int(t.length()) )
     { 
      if( j==-1 || s[i] == t[j] )
       i++,j++;
      else
       j=next[j],m++;//返回的时候在增加一趟
                        //注意第一个next是-1,其他的都像后推
     }
                                                                   //cout<<endl<<"*******************************************"<<endl;
     if(j>=int(t.length() ))
            cout<<m<<' '<<(i-t.length())+1<<endl;
     else
      cout<<0<<endl;
                                                                      // cout<<"*******************************************"<<endl;
    }
    int main()
    {
     string a,b;
     cin>>a>>b;
     kmpindex(a,b);
     return 0;
    }
    



     

  • 相关阅读:
    解决pip3的ImportError: cannot import name 'main'
    linux 安装Python3.6
    Linux安装redis和部署
    redis密码管理
    CentOS7使用firewalld打开关闭防火墙与端口
    scrapy 从Windwos平台移植到 Linux平台之实操
    Linux 环境下安装Maven
    解决:安装Jenkins时web界面出现该jenkins实例似乎已离线
    持续集成工具Jenkins结合SVN的安装和使用
    Linux下的SVN服务器搭建
  • 原文地址:https://www.cnblogs.com/zswbky/p/5432085.html
Copyright © 2020-2023  润新知