KMP算法理解

来源:互联网 发布:巴西柔术知乎 编辑:程序博客网 时间:2024/04/29 18:54

学习笔记:
考研的时候了解过一点,当时找了各种资料,理解的也是头昏脑涨,仅仅记住了next数组的心算过程。写个笔记有助于自己加深理解。如有朋友感兴趣可去:http://blog.csdn.net/v_july_v/article/details/7041827
这篇是我现在看到解释的最透彻的一篇。


首先理解KMP算法的抽象思想

一般的字符串比较思维:

首先将文本串和模式串的第一位相互比较:

不相等,模式串向后移一位:

直到遇到与模式串第一位相等的位置:

再比较模式串的第二位:

如果有不相等的时候:

将模式串右移一位,再从头开始:

可是根据模式串的特点可以右移四位,从模式串的第2位(从0开始)与当前文本串比较

于是这个四 和2是怎么确定的呢?

先死板地接受这样一种概念:

暂时叫做匹配数组:表示在一个串中,当前下标i对应的值为前i-1个串中前缀和后缀能匹配的最大长度:

eg:

什么是前缀?
比如单词word:前缀有 w、wo、wor;后缀:d、rd、ord。

匹配数组计算过程:

回到匹配时:

设文本串s的比较下标为i,模式串p的比较下标为j , 匹配数组为next。当前i = 10, j = 6,现在s[i] != p[j],将j = next[j] = 2,有:

人性化的想象一下,比较到s[i]和p[j]时,前j个字符必然相等的。

直接比较p[2]和s[10]

求next数组

利用递归思想,假设已经求了next[0~j],且已知next [j] = k,要求next[j+1]。分为两种情况:

(1)next[k] == next[j] =>next[j+1] = next[j]+1; 表示最大前缀 最大后缀一直匹配着

(2)next[k] != next[j],一切要重新洗牌,找出前0~j个字符的最大前缀后缀。

不妨想像模式串p为文本串s’,p[0~k]为模式串p’

代码如下:

求next数组:

void GetNext(char* p,int next[])  {      int pLen = strlen(p);      next[0] = -1;      int k = -1;      int j = 0;      while (j < pLen - 1)      {          //找不到就一直回溯        while(k != -1 && p[j] != p[k]) k = next[k];        next[++j] = ++k;     }  }  

kmp扫描:

int KmpSearch(char* s, char* p)  {      int k = 0;      int j = 0;      int sLen = strlen(s);      int pLen = strlen(p);      while (j < sLen && k < pLen)      {            while (k != -1 && s[k] != p[j])  k = next[k];        k++;          j++;     }      if (j == pLen)          return i - j;      else          return -1;  }  
0 0
原创粉丝点击