• BF算法与KMP算法


          BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。

    BF算法实现:

     1 int BF(char S[],char T[],int pos)
     2 {//c从第pos位开始搜索匹配
     3     int i=pos,j=0;
     4     while(S[i+j]!=''&&T[j]!='')
     5     {
     6         if(S[i+j]==T[j])
     7             j++;
     8         else
     9         {
    10             i++;
    11             j=0;
    12         }
    13     }
    14     if(T[j]=='')
    15         return i+1;
    16     else
    17         return -1;
    18 }
    BF算法比较直接,是一种蛮力算法,该算法最坏情况下要进行M*(N-M+1)次比较,时间复杂度为O(M*N),下面来看一个效率非常高的字符串匹配算法,即KMP算法。
    KMP算法完成的任务是:给定两个字符串S和T,长度分别为n和m,判断f是否在S中出现,如果出现则返回出现的位置。常规方法是遍历a的每一个位置,然后从该位置开始和b进行匹配,但是这种方法的复杂度是O(nm)。kmp算法通过一个O(m)的预处理,使匹配的复杂度降为O(n+m)。

    KMP算法思想:
    实例1
    优化的地方:如果我们知道模式中a和后面的是不相等的,那么第一次比较后,发现后面的的4个字符均对应相等,可见a下次匹配的位置可以直接定位到f了。说明主串对应位置i的回溯是不必要的。这是kmp最基本最关键的思想和目标。

    实例2

    由于abc 与后面的abc相等,可以直接得到红色的部分。而且根据前一次比较的结果,abc就不需要比较了,现在只需从f-a处开始比较即可。说明主串对应位置i的回溯是不必要的。要变化的是模式串中j的位置(j不一定是从1开始的,比如第二个例子)j的变化取决于模式串的前后缀的相似度,例2中abc和abc(靠近x的),前缀为abc,j=4开始执行。

    下面我们来看看Next()数组:

    定义
    (1)next[0]= -1 意义:任何串的第一个字符的模式值规定为-1。
    (2)next[j]= -1   意义:模式串T中下标为j的字符,如果与首字符相同,且j的前面的1—k个字符与开头的1—k个字符不等(或者相等但T[k]==T[j])(1≤k<j< span="">)。如:T=”abCabCad” 则 next[6]=-1,因T[3]=T[6]
    (3)next[j]=k    意义:模式串T中下标为j的字符,如果j的前面k个字符与开头的k个字符相等,且T[j] != T[k] (1≤k<j< span="">)。即T[0]T[1]T[2]。。。T[k-1]==T[j-k]T[j-k+1]T[j-k+2]…T[j-1]
    且T[j] != T[k].(1≤k<j< span="">);
    (4) next[j]=0   意义:除(1)(2)(3)的其他情况。
     
    意义
     next 函数值究竟是什么含义,前面说过一些,这里总结。
    设在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函数值next[n],
    1.       next[n]= -1 表示S[m]和T[0]间接比较过了,不相等,下一次比较 S[m+1] 和T[0]
    2.       next[n]=0 表示比较过程中产生了不相等,下一次比较 S[m] 和T[0]。
    3.       next[n]= k >0 但k<n, <="" span="">表示,S[m]的前k个字符与T中的开始k个字符已经间接比较相等了,下一次比较S[m]和T[k]相等吗?
    4.       其他值,不可能。
     
    Next()数组求解的实现:
    void getNext(const char* pattern,int next[])
    {
           next[0]=   -1;
           int k=-1,j=0;
           while(pattern[j] != '')
           {
                  if(k!= -1 && pattern[k]!= pattern[j] )
                         k=next[k];
                  ++j;++k;
                  if(pattern[k]== pattern[j])
                         next[j]=next[k];
                  else
                         next[j]=k;
           }
    }
     
    Next()数组求出后,就可以进行字符串匹配了
    int KMP(char *s,char* t)
    {
           if( !s||!t|| t[0]=='' || s[0]=='' )
                  return -1;//空指针或空串,返回-1。
           int len=0;
           const char * c=t;
           while(*c++!='')
           {
                  ++len;
           }
           int *next=new int[len+1];
           getNext(t,next);
    
           int index=0,i=0,j=0;
           while(s[i]!='' && t[j]!='' )
           {
                  if(s[i]== t[j])
                  {
                         ++i;
                         ++j;
                  }
                  else
                  {
                         index += j-next[j];
                         if(next[j]!=-1)
                                j=next[j];
                         else
                         {
                                j=0;
                                ++i;
                         }
                  }
           }
           delete []next;
           if(t[j]=='')
                  return index;
           else
                  return -1;
    }
    写到这,KMP算法介绍的也差不多了,关于KMP算法优化,待续。。。。


    
    
  • 相关阅读:
    数据结构:静态查找表
    数据结构:二叉查找树(C语言实现)
    自创open vp n windows步骤
    web application 访问控制
    postman trigger xdebug session in phpstorm
    sql查询学习和实践点滴积累
    如何写一个能在gulp build pipe中任意更改src内容的函数
    使用Virtual Audio Cable软件实现电脑混音支持电脑录音
    webpack学习笔记丁点积累
    centos 7.2 Apache+mysql+php step by step备忘
  • 原文地址:https://www.cnblogs.com/czx1/p/20141313707-cm.html
Copyright © 2020-2023  润新知