KMP模式匹配

来源:互联网 发布:天之痕活物数据修改 编辑:程序博客网 时间:2024/05/29 09:26

KMP算法

  一种由Knuth(D.E.Knuth)、Morris(J.H.Morris)和Pratt(V.R.Pratt)三人设计的线性时间字符串匹配算法。这个算法不用计算变迁函数δ,匹配时间为Θ(n),只用到辅助函数π[1,m],它是在Θ(m)时间内,根据模式预先计算出来的。数组π使得我们可以按需要,“现场”有效的计算(在平摊意义上来说)变迁函数δ。粗略地说,对任意状态q=0,1,…,m和任意字符a∈Σ,π[q]的值包含了与a无关但在计算δ(q,a)时需要的信息。由于数组π只有m个元素,而δ有Θ(m∣Σ∣)个值,所以通过预先计算π而不是δ,使得时间减少了一个Σ因子。[1]
  KMP算法是通过分析子串,预先计算每个位置发生不匹配的时候,所需GOTO的下一个比较位置,整理出来一个next数组,然后在上面的算法中使用。

编辑本段KMP算法的讲解

  当我们分析一个子串时,例如:abcabcddes. 需要分析一下,每个字符x前面最多有多少个连续的字符和字符串从初始位置开始的字符匹配。然后+1就行了(别忘了,我们的字符串都是从索引1开始的)当然,不要相同位置自己匹配,默认第一个字符的匹配数是0。

编辑本段定义

  设字符串为 x1x2x3...xn,其中x1,x2,x3,... xi,... xn均是字符,设ai为字符xi对应的整数。则a=m,当且仅当满足如下条件:字符串x1x2...xm equals 字符串x(i-m+1)...xi-1 xi 并且x1x2...xm x(m+1) unequals x(i-m) x(i-m+1)...xi-1 xi。

编辑本段举例

  abcabcddes
  0111234111
  |----------------------默认是0
  --| | |-----------------不能自己在相同位置进行字符匹配,所以这里认为没有匹配字符串,所以0+1 =1,继续从1开始匹配
  ------| | |-----------前面的字符和开始位置的字符相同,所以是2,3,4
  -----------| | | |-------不匹配只能取1。
  希望能明白的是,如果开始字符是 Ch1的话,那么我们就是要在串中第2个Ch1后面的位置开始自己和自己匹配,计算最大的吻合度。
  程序写出来就是:
  void GetNext(char* T,int *next)
  {
  int k=1,j=0;
  next[1]=0;
  while(k〈 T[0]){
  if (j ==0 || T[k] == T[j])
  {
  ++k;
  ++j;
  next[k] = j;
  }
  else j= next[j];
  }
  }
  但是这个不是最优的,因为他没有考虑aaaaaaaaaaaaaaaaaaab的情况,这样前面会出现大量的1,这样的算法复杂度已经和最初的朴素算法没有区别了。所以稍微改动一下:
  void GetNextEx(char *T,int *next)
  {
  int k=1,j=0; next[1] = 0;
  while(k < T[0])
  {
  if (j == 0 || T[k] == T[j])
  {
  ++k; ++j;
  if (T[k] == T[j])
  next[k] = next[j];
  else
  next[k] = j;
  }
  else j = next[j];
  }
  }
  现在我们已经可以得到这个next字符串的值了,接下来就是KMP算法的本体了:
  相当简单:
  int KMP(char* S,char* T,int pos)
  {
  int k=pos,j=1;
  while (k<strlen(S)){
  if (S[k] == T[j]){ ++k; ++j; }
  else j = next[j];
  }
  if (j>T[0]) return k-T[0];
  else return 0;
  }
  和朴素算法相比,只是修改一句话而已,但是算法复杂度从O(m*n) 变成了:O(m)
原创粉丝点击