当前位置:   article > 正文

详解kmp算法

kmp算法

了解kmp算法之前先要知道为什么要有kmp算法

1.朴素模式匹配

        1.1基本思想:

从主串test 和模式串pattern 的第一个字符开始,将两字符串的字符一一比对,如果出现某个字符不匹配,主串回溯到第二个字符,子串回溯到第一个字符再进行一一比对。如果出现某个字符不匹配,主串回溯到第三个字符,子串回溯到第一个字符再进行一一比对…循环一直到子串字符全部匹配成功。

        1.2例如:

第一次:不匹配

第二次:主串从第2个字符,模式串从头开始,直到b与c不匹配

 第三次:主串从第3个位置开始,模式串从头开始,a与c不匹配 

第四次:主串从第4个位置开始,模式串从头开始,匹配成功

 朴素模式匹配的缺点:

当主串与模式串能部分匹配时, 主串的扫描指针i经常回溯,导致时间开销增加。

2.kmp算法

         2.1基本思想

当字串与模式串不匹配的时候,主指针不需要再次回溯,只需要调整模式串的位置

例如:

当扫描到 a , f 不匹配时,如果是朴素模式匹配那么 i指针会退到第二个位置,j指针会退到开头位置

 像这个样子:

而如果是kmp算法,会调整 j 的位置,而不使 i 指针回退

 

 实现这个功能那就必需要一个next数组

        2.2next数组

kmp算法最主要的就是next数组

next数组作用

  • next[i]的值表示下标为i的字符前的字符串最长相等前后缀的长度

  • 表示该处字符不匹配时应该回溯到的字符的下标

        2.3next数组的实现

(1)初始化 i ,j,next[0]。i 指针指向前缀的最大长度,j 指针指向后缀的最大长度

(2)当i,j指针指的元素不相等时

(3)当i,j指针指的元素相等时

(4)next数组赋值或调整 j 指针的位置

        2.4代码实现

这里初始化为next[0]=-1,j=0,k=-1,之后得到 next[i] 数组就是对应的值

如果初始化为next[1]=0,j=1,k=0,则需要初始数组空一格位置

  1. void GetNext(char* p, int next[])
  2. {
  3. int pLen = strlen(p);
  4. next[0] = -1;
  5. int k = -1; //k指向前缀
  6. int j = 0; //j指向后缀
  7. while (j < pLen - 1)
  8. {
  9. //p[k]表示前缀,p[j]表示后缀
  10. if (k == -1 || p[j] == p[k])
  11. {
  12. ++k;
  13. ++j;
  14. next[j] = k;
  15. }
  16. else
  17. {
  18. k = next[k]; //回退因为如果此时最大前后缀不满足,则继续看前一个元素的最大前后缀值
  19. }
  20. }
  21. }

        

        2.5next 数组举例

逻辑上可以理解为i,j分别指向两个相同的串,从而代表前缀和后缀。实际只是在一个串操作

 

 

 

 此时i,j指的元素不相同,需要缩小最大前后缀的长度:j=next[j]

 

 

 

 

当i<length-1时退出循环,每次字符的前面匹配的字符的最大前后缀均以求出 

     

           2.6操作中j=next[j]解释

 

 

         2.7kmp算法代码实现

  1. int KmpSearch(char* s, char* p,int next[])
  2. {
  3. int i = 0;
  4. int j = 0;
  5. int sLen = strlen(s);
  6. int pLen = strlen(p);
  7. while (i < sLen && j < pLen)
  8. {
  9. //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
  10. if (j == -1 || s[i] == p[j])
  11. {
  12. i++;
  13. j++;
  14. }
  15. else
  16. {
  17. //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
  18. //next[j]即为j所对应的next值
  19. j = next[j];
  20. }
  21. }
  22. if (j == pLen)
  23. return i - j;
  24. else
  25. return -1;
  26. }

测试:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/662077
推荐阅读
相关标签
  

闽ICP备14008679号