0


最详BF算法和KMP算法

BF算法和KMP算法可以说是串中重要的算法,也是数据结构必学算法,我以前是不太理解KMP算法的,但是现在说来可以写出程序 理解思想了 也能懂了next数组,若有错误清在评论区指出,一起探讨。


一、BF算法

1.理解阶段

算法中最紧要的是理解一个算法的思想,就像是人一样,没有思想与行尸走肉无异,算法是一样的。BF算法的时间复杂度最理想为O(n) ------n为子串的长度

最不理想为O(n*m) ------------------m为主串长度

BF算法又称为简单模式匹配算法 其思想简单 容易理解 但是效率较低(需要回溯)

第一次进行模式匹配 匹配到第3个字符 匹配错误。

进行第2次模式匹配,本次匹配会把子串回溯到起点 主串会回溯到上次进行匹配的起点的下一个位置 可以看到到子串的第2个字符匹配失败 重新回溯

第3次进行模式匹配 同上回溯方法 到第5个字符匹配失败 重新回溯

第4次进行模式匹配 匹配成功

2.代码阶段

如果说理解重要,但是只处于理解阶段对于一个程序员是远远不够的,还要有代码能力。

**先给出BF算法部分代码 **

我定义返回型为int型 返回第一次出现的位置

  1. int creatBF(char *a,char *b)
  2. {
  3. //a主串 b子串
  4. int i=0,j=0,x=0;
  5. while(i<strlen(a)&&j<strlen(b)) //子串主串都没有到达最后 到达最后说明匹配不成功
  6. {
  7. if(a[i]==b[j])
  8. {
  9. i++;
  10. j++;
  11. }
  12. else
  13. {
  14. i=x+1; //x存储上一次开始的起点
  15. j=0; //回溯
  16. x=i; //记录本次开始的起点
  17. }
  18. }
  19. //跳出循环 则到达a的长度或到达b的长度
  20. //到达a 则说明匹配成功
  21. //到达b 则说明 匹配不成功
  22. if(j==strlen(b))
  23. {
  24. return x;
  25. }
  26. return 0;
  27. }

测试结果如下:

二、KMP算法

1.理解阶段

KMP算法是BF算法的升级版 相对来说是 理解难度上升 但是效率得到了提高

KMP算法相对与BF算法 是主串不需要回溯 子串是回溯到特定的位置 可以有效减少比较次数

较少运行时间 提高效率

子串回溯 主要看next数组 ,我的理解是next数组是next数组的值-1表示最长前缀的下标

当子串主串发生失配时 主串不发生回溯,子串会回溯到最长相等前后缀数值的位置

而记录最长相等前后缀的就时next数组 next[j]=k 表示子串中前j-1个字符的最长相等前后缀长度为k-1

下面给出获得next数组的代码

1.next数组的获得代码

  1. void GetNext(char *a,int next [])
  2. {
  3. //a主串 b子串
  4. int j=0; //便利子串
  5. int k=-1; //k时子串中每个字符的next值
  6. next[0]=-1;
  7. while(j<strlen(a))
  8. {
  9. if(k==-1||a[j]==a[k])
  10. {
  11. j++;
  12. k++;
  13. next[j]=k;
  14. }
  15. else
  16. k=next[k];
  17. }
  18. }

测试结果如图:

2.KMP算法代码如下:

KMP算法的核心在于求next数组 剩下的就是进行比较

  1. int creatKMP(char *a,char *b,int next[])
  2. {
  3. //a 主串 b子串
  4. int i=0,j=0;
  5. while(i<strlen(a)&&j<strlen(b))
  6. {
  7. if(j==-1||a[i]==b[j])
  8. {
  9. i++;
  10. j++;
  11. }
  12. else
  13. j=next[j];
  14. }
  15. if(j>=strlen(b))
  16. {
  17. return (i-strlen(b));//i表示 查找结束在主串中的位置减去子串长度 为首位置
  18. }
  19. else
  20. return -1;
  21. }

测试结果如图:

下面我会给出完整的程序,包括BF和KMP算法 如下:

  1. # include <stdio.h>
  2. #include <string.h>
  3. void GetNext(char *a,int next [])
  4. {
  5. //a主串 b子串
  6. int j=0; //便利子串
  7. int k=-1; //k时子串中每个字符的next值
  8. next[0]=-1;
  9. while(j<strlen(a))
  10. {
  11. if(k==-1||a[j]==a[k]) //表示判断加入后缀 j后是否与会 使最长前后缀增加 a[k] 表示最长前缀的后一个
  12. {
  13. j++;
  14. k++;
  15. next[j]=k;
  16. }
  17. else
  18. k=next[k];
  19. }
  20. }
  21. int creatKMP(char *a,char *b,int next[])
  22. {
  23. //a 主串 b子串
  24. int i=0,j=0;
  25. while(i<strlen(a)&&j<strlen(b))
  26. {
  27. if(j==-1||a[i]==b[j])
  28. {
  29. i++;
  30. j++;
  31. }
  32. else
  33. j=next[j];
  34. }
  35. if(j>=strlen(b))
  36. {
  37. return (i-strlen(b));//i表示 查找结束在主串中的位置减去子串长度 为首位置
  38. }
  39. else
  40. return -1;
  41. }
  42. int creatBF(char *a,char *b)
  43. {
  44. //a主串 b子串
  45. int i=0,j=0,x=0;
  46. while(i<strlen(a)&&j<strlen(b)) //子串主串都没有到达最后 到达最后说明匹配不成功
  47. {
  48. if(a[i]==b[j])
  49. {
  50. i++;
  51. j++;
  52. }
  53. else
  54. {
  55. i=x+1; //x存储上一次开始的起点
  56. j=0; //回溯
  57. x=i; //记录本次开始的起点
  58. }
  59. }
  60. //跳出循环 则到达a的长度或到达b的长度
  61. //到达a 则说明匹配成功
  62. //到达b 则说明 匹配不成功
  63. if(j==strlen(b))
  64. {
  65. return x;
  66. }
  67. return 0;
  68. }
  69. int main()
  70. {
  71. char a[13];
  72. char b[5];
  73. scanf("%s%s",a,b);
  74. int t=creatBF(a,b);
  75. printf("%d\n",t);
  76. int next[5];
  77. GetNext(b,next);
  78. //for(int i=0;i<5;i++)
  79. //{
  80. // printf("%d ",next[i]);
  81. //}
  82. int y=creatKMP(a,b,next);
  83. printf("%d",y);
  84. }

三.BF算法与KMP算法的区别与优缺点

BF算法是子串主串都需要进行回溯比较浪费时间,效率比较低。

KMP算法是主串不需要回溯,子串只需要根据next数组进行回溯到特定位置


本文转载自: https://blog.csdn.net/m0_61469860/article/details/125113203
版权归原作者 &volume 所有, 如有侵权,请联系我们删除。

“最详BF算法和KMP算法”的评论:

还没有评论