KMP算法的详细理解

很早就想写关于这个算法的具体分析,可是一直很懒的去思考这个问题。现在快要杭电的计算机复试了,复试内容我选择的是数据结构。让我又重新燃起了要对KMP算法的分析。它是我第一个碰见的比较难的关于字符串的算法。所以很有兴趣想好好的了解一下,也让我能对他更好的了解。

讲KMP算法的时候,通常都会提及BF算法.

 

BF算法相对简单点,具体的做法是"对主串和子串进行一个一个的字符的比较,当碰到相同的字符的时候,则分别指向下一个字符,然后在进行比较。如果在比较过程中发现两个字符不同则进行回退。讲子串的退回到第一个字符,而主串退回到第一个进行比较字符的下一个字符".对于主串的回退是很浪费时间的。而KMP(3个作者)想到了对子串进行部分信息的记录也换的更加高效的算法---也就是KMP算法。

 

对于KMP算法,其实我认为首先要弄清楚的是next数组里面到底是存放了什么信息?

next数组里面存放的是,比如next[i]是指当子串的第i位与主串中相应的一个字符(比如是k)不匹配的时候,那么子串的指针应该指向next[i]中存放的(比如说j)数的位置与主串的k位的字符进行比较。

     有next数组以后在匹配过程中可以避免2中情况

  • 避免主串的回退
  • 每一次回退子串不是从头开始,而是让子串尽量的往右移动 

其实KMP的算法难就难在next的难理解和难计算.关于next的计算根据严蔚明的<<数据结构>>上所讲,我觉得其实挺清楚了。我也讲讲看。

(假设我们称主串为S,子串为P)

  1. 当子串的i字符与主串的j字符不匹配的时候,

我们假设这个时候子串应该移动到k这个字符,也就是说子串中的k位字符要与主串中的j位进行比较。那么可以推出一些信息

  • P(1...k-1)=S(j-k+1...j-1)----因为我们假设的是子串的第k位字符进行比较
  • 第二信息是P(i-k+1....i-1)=S(j-k+1...j-1)---因为这是题目本身就有的,当子串i与主串的j不匹配的时候
  • 从上面的两个信息就可以知道P(1...k-1)=P(i-k+1....i-1)

     2.根据上面的推论,我们可以这么认为next[i] = k;解释可以认为是当i与主串不匹配的时候,让子串移到第k位与主串进行比较。所以一次类推我们可以在得出当主串与k字符不匹配时,那么主串的j字符就与子串的next[k]字符进行比较,一直类推到第一字符。所以我们通常假设第一个字符的next[0] = -1

 

     3关于next数组的具体计算

 

     这个过程很像数学中的归纳法一样。假设next[h] = k 从这一步我们可以知道P(1...k-1)=P(h-k+1....h-1),那么推测一下next[h+1]是多少?

 

  1. 情况1 当P[k] = P[h]时,那么next[h+1] = k+1
  2. 情况二 当 P[k] != P[h],那么现在的情况其实你会觉得和主串与子串不匹配的时候很相像。那个事情的情况是S[j]!=P[i],然后我们做的就是让S[j]与P[next[i]]进行比较,所以这个事情我们也可以让P[k]来代替上面主串比较过程中的P[i]的位置.所以这时候我们要进行的就是让P[h]与P[next[k]]进行比较。比较的结果也是两种。

 

 

 

关于next数组的具体实现

void GetNext(int *next,const string &thiz,const int &num) { int k = -1; next[0] = -1; int i = 1; while(i < num) { if(k == -1 || thiz[i - 1] == thiz[k]) { next[i++] = ++k; } else { k = next[k]; } } }  

 

 


你可能感兴趣的:(数据结构,算法,String)