算法 kmp算法

客官°小女子只卖身不卖艺 2022-05-26 04:40 341阅读 0赞

kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同。

下面具体说下这两种算法的区别:

主串:BABCDABABCDABCED

从串:ABCDABCED

BF算法:

第一步:








































B A B C D A B A B C D A B C E D
A                              

从主串的第一个字符位置开始与从串第一个字符位置进行匹配,匹配失败

第二步:








































B A B C D A B A B C D A B C E D
  A B C D A B C                

从主串的第二个字符位置开始与从串第一个字符位置进行匹配,匹配失败

第三步:








































B A B C D A B A B C D A B C E D
    A                          

从主串的第三个字符位置开始与从串第一个字符位置进行匹配,匹配失败

………..

第七步:








































B A B C D A B A B C D A B C E D
            A                  

从主串的第七个字符位置开始于从串第一个字符位置进行匹配,匹配失败

第八步:








































B A B C D A B A B C D A B C E D
              A B C D A B C E D

匹配成功,这个就是BF算法,每次匹配失败后要从主串的下一个字符位置与从串的第一个字符接着进行匹配。

kmp算法:

第一步:








































B A B C D A B A B C D A B C E D
A                              

主串与从串的第一个字符不匹配

第二步:








































B A B C D A B A B C D A B C E D

A B C D A B C







这两步和bf一样

第三步:








































B A B C D A B A B C D A B C E D





A B C







这里就和bf不一样了,其原因就是从串中字符有相同的一部分(AB),这里先知道区别,待会我会说它的实现过程

第四步:








































B A B C D A B A B C D A B C E D
              A B C D A B C E D

如果看不懂的话,下面会讲清楚,然后根据程序找下标就可以知道原因了。

kmp算法分两部分:①next数组(kmp算法的核心)

②字符串的匹配

在讲解next数组时,顺便把前缀和后缀的知识也说了。

比如上面的从串:ABCDABCED(前缀是从第一个字符数,但后缀不是倒着数,它也是顺着数,看下面的写法吧)

第一个字符前,它没有串,所以没有前缀和后缀,则它也没有最长长度,我把它的长度初始化为0。

第二个字符前,它的串是A,前缀和后缀是不能包含串本身,所以它没有前缀和后缀,长度为0。

第三个字符前,它的串是AB,前缀是A,后缀是B,不匹配,长度为0。

第四个字符前,它的串是ABC,第一种,前缀是A,后缀是C,不匹配,长度为0,

第二种,前缀是AB,后缀是BC,不匹配,长度为0,

所以最长长度为0。

第五个字符前,它的串是ABCD,第一种,前缀是A,后缀是D,不匹配,长度为0,

第二种,前缀是AB,后缀是CD,不匹配,长度为0,

第三种,前缀是ABC,后缀是BCD,不匹配,长度为0,

所以最长长度为0。

第六个字符前,它的串是ABCDA,第一种,前缀是A,后缀是A,匹配,长度为1,

第二种,前缀是AB,后缀是DA,不匹配,长度为0,

第三种,前缀是ABC,后缀是CDA,不匹配,长度为0,

第四种,前缀是ABCD,后缀是BCDA,不匹配,长度为0,

所以最长长度为1。

第七个字符前,它的串是ABCDAB,第一种,前缀是A,后缀是B,不匹配,长度为0,

第二种,前缀是AB,后缀是AB,匹配,长度为2,

第三种,前缀是ABC,后缀是DAB,不匹配,长度为0,

第四种,前缀是ABCD,后缀是CDAB,不匹配,长度为0,

第五种,前缀是ABCDA,后缀是BCDAB, 不匹配,长度为0,

所以最长长度为2。

第八个字符前,它的串是ABCDABC,第一种,前缀是A,后缀是C,不匹配,长度为0,

第二种,前缀是AB,后缀是BC,不匹配,长度为0,

第三种,前缀是ABC,后缀是ABC,匹配,长度为3,

第四种,前缀是ABCD,后缀是DABC,不匹配,长度为0,

第五种,前缀是ABCDA,后缀是CDABC,不匹配,长度为0,

第六种,前缀是ABCDAB,后缀是BCDABC,不匹配,长度为0,

所以最长长度为3。

第九个字符前,它的串是ABCDABCE,第一种,前缀是A,后缀是E,不匹配,长度为0,

第二种,前缀是AB,后缀是CE,不匹配,长度为0,

第三种,前缀是ABC,后缀是BCE,不匹配,长度为0,

第四种,前缀是ABCD,后缀是ABCE,不匹配,长度为0,

第五种,前缀是ABCDA,后缀是DABCE,不匹配,长度为0,

第六种,前缀是ABCDAB,后缀是CDABCE,不匹配,长度为0,

第七种,前缀是ABCDABC,后缀是BCDABCE,不匹配,长度为0,

所以最长长度为0。

然后根据我们求出来的最长长度,就能绘制出next表了,








































下标 1 2 3 4 5 6 7 8 9
从串 A B C D A B C E D
next 0 0 0 0 0 1 2 3 0

可能别人的next和kmp和我写的不一样,不过我就是这么理解的,如果哪里错了,大家可以提出来

当然这个next数组也可以改进的,大家想一想,上面在比较bf与kmp算法是,kmp的第三步是不是多余了,为什么呢,因为第二步的ABCDABC中的第二个C与主串中的A不匹配,第三步还是ABC,这里面的C肯定也与A不匹配,所以也就有了next数组的改进,怎么改进呢,很简单,只要相等时候,让它等于前面那个一样字符的next数组下标就可以了,看表格








































下标 1 2 3 4 5 6 7 8 9
从串 A B C D A B C E D
next 0 0 0 0 0 0 0 3 0

第二个B与第一个B的next值一样为0,第二个C与第一个C的next值一样为0。

这就是next数组及其改进后的next数组。

next数组程序:

  1. void Get_next(int *next, string s2)
  2. {
  3. int i = 1;
  4. int j = 0;
  5. next[i] = 0;
  6. while(i <= s2.length())
  7. {
  8. if(j == 0 || s2[i - 1] == s2[j - 1])
  9. {
  10. i++;
  11. j++;
  12. if(s2[i - 1] == s2[j - 1])
  13. next[i] = next[j];
  14. else
  15. next[i] = j - 1;
  16. }
  17. else
  18. j = next[j];
  19. }
  20. }

如果你理解了next数组的求值方法,根据bf算法的思路应该可以写出kmp字符匹配函数,

下面是kmp算法的总体程序:

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. //求next数组下标
  5. void Get_next(int *next, string s2)
  6. {
  7. int i = 1;
  8. int j = 0;
  9. next[i] = 0;
  10. while(i <= s2.length())
  11. {
  12. if(j == 0 || s2[i - 1] == s2[j - 1])
  13. {
  14. i++;
  15. j++;
  16. if(s2[i - 1] == s2[j - 1])
  17. next[i] = next[j];
  18. else
  19. next[i] = j - 1;
  20. }
  21. else
  22. j = next[j];
  23. }
  24. // for(int k = 1; k < 10; k++)
  25. // cout << next[k] << endl;
  26. }
  27. //匹配部分
  28. int kmp(string s1, string s2, int pos)
  29. {
  30. int next[100];
  31. Get_next(next, s2);
  32. int i = 0;
  33. int j = 0;
  34. while(i < s1.length() && j < s2.length())
  35. {
  36. if(j == 0 || s1[i] == s2[j])
  37. {
  38. i++;
  39. j++;
  40. }
  41. else
  42. {
  43. j = next[j + 1];
  44. }
  45. }
  46. if(j >= s2.length())
  47. return i - s2.length();
  48. return -1;
  49. }
  50. int main()
  51. {
  52. string s1= "babcdababcdabced";
  53. string s2 = "abcdabced";
  54. int pos;
  55. cin >> pos;
  56. cout << kmp(s1, s2 ,pos) << endl;
  57. return 0;
  58. }

本程序只是个人的想法和思路,若有错误还请大家提出,若有不明白的地方,请在下面评论,谢谢大家啦!

对了,我的算法应该存在问题,希望多多指出。

发表评论

表情:
评论列表 (有 0 条评论,341人围观)

还没有评论,来说两句吧...

相关阅读

    相关 KMP算法

    1.原始的字符串匹配方法 算法基本思想:从主串S的第pos个字符起和模式的第一个字符比较之,若相等,则继续逐个比较后续字符;否则从主串的下一个字符起再重新和模式的字符比较

    相关 KMP算法

    kmp算法又称“看毛片”算法,是一个效率非常高的字符串匹配算法。不过由于其难以理解,所以在很长的一段时间内一直没有搞懂。虽然网上有很多资料,但是鲜见好的博客能简单明了地将其讲清

    相关 KMP算法

    1. KMP算法 1.1 定义     Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串P 的出现

    相关 KMP算法

    核心:1.当遇到不可匹配的字符的时候,我们希望找到一些规律,可以将搜索串往后多滑动几位    2.构建《部分匹配表》 下面链接是阮大神的见解,写的非常棒!    [字符串

    相关 Kmp算法

    举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? ![bg2013050101.jpg][]

    相关 KMP算法

    KMP算法的思想是 主串S 和模式串W,判断W是否匹配S 如果主串S在i位置与W串在j位置出现不匹配的情况的时候,利用已经得到的匹配把W串尽量右移动一段距离。 用伪代码写

    相关 KMP算法

    一 KMP算法介绍 1 KMP是一个解决模式串在文本串是否出现过,如果出现过,求算出现的位置的经典算法。 2 Knuth-Morris-Pratt 字符串查找算法,简称