KMP算法的特征向量

假设子串P有m个字符,子串P的特征向量N有m个非负整数,与每个字符一一对应。

也就是说每个字符都有属于自己,用来描述所在位置特征的专属数字。

那么,问题来了,这个数字的意义是什么?换句话说这个数字的作用是什么?用来描述什么?

嗯哼!敲黑板,注意听哦。

假设位置是i,N[i]是5,则5代表,从p的前五个字符顺序组成的字符串与从 i 位置开始,向左数5个字符,这5个字符从左向右组成的字符串相同。而且,没有比5大的

(⊙o⊙)…,呃,有点迷。就是    p[0]p[1]p[2]p[3]p[4] == p[i-4]p[i-3]p[i-2]p[i-1]p[i] 这个意思。。。

好了,来下一个定义吧,首先讲几个概念

//前缀子串:  模板P开头的t个字符,称为P的前缀子串,即 q[0]q[1]q[3]…q[t-1]
//i位置的左子串: 模板P的第i位置左边(包括i位置),也取出t个字符,即q[i-t+1]...q[i-2]q[i-1]q[i]
找出最长的(t最大的)能够与前缀子串匹配的i位置左子串(简称第i位的最长前缀串),t就是要求的特征数ni。

然后p中的每一个字符都有这样的一个数字,这些数字组成了p的特征向量N。

那么,重点来了,如何计算一个子串P的特征向量呢?

这里采用了递归算法,假设i-1位置的特征向量已知,借此来算i的特征向量。

递归,当i==0时,n[0]=0

i > 0 (假定知道n[i-1]==k)

如果p[i]==p[k],则n[i]==k+1;(不会比k+1大,否则n[i-1]>k)

如果p[i]!=p[k],且k!=0;则令k=n[k-1],一直循环,直到不满足。

如果p[i]!=p[k],k==0;则n[i]==0;

如果p[i]==p[k],则n[i]==k+1;

解释:这里主要是一直循环比较难理解。

当i处比较失败后,我们会缩短(如果增长的话n[i-1]>k)最长前缀子串和i-1位置的左子串继续比较,但缩短也是有规律的,我们要把这两者缩小,最长前缀子串

是从右边删减,i-1位置处的左子串是从左边删减,其余两端不变,同时要保证缩小后的两个串依然相等,我们注意到,当前最长前缀子串依然等于i-1位置的左子串

于是问题就转化成把当前最长前缀子串看成子串,找出其最右端字符的特征向量n[k-1].,确定新的当前最长前缀子串,以此类推。需要指出的是k的意义,k代表当前最长

前缀子串的再右边一位,所以这时我们依然比较p[i]与p[k],但是这时k值发生了变化,k=n[k-1].

具体的算法是

int *Next(String P)
{
  int m = P.strlen();    
  //m为模板P的长度
  assert( m > 0 );    
  //若m=0,退出
  int *N = new  int [m]; 
  // 动态存储区开辟整数数组
  assert( N != 0);   
  //若开辟存储区域失败,退出
  N[0] = 0; 

  for ( int i =1 ; i < m ;  i++ )   //分析P的每个位置i
  {
    //第(i-1)位置的最长前缀串长度     
    int k = N[i-1]; 
    //以下while语句递推决定合适的前缀位置k
    while( k > 0 && P[i] != P[k] )   k = N[k-1];
    //根据P[i]比较第k位置前缀字符,决定N[i]
    if(P[i] == P[k])  

       N[i] = k+1;
    else   N[i] = 0 ;
   }
   return N; 
}

 

posted @ 2017-04-25 21:14  visionshao  阅读(1375)  评论(0编辑  收藏  举报