KMP算法;学习严蔚敏;大概理解;

本文深入讲解KMP字符串匹配算法的工作原理及其实现过程。通过分析next和nextval数组的构造方法,帮助读者理解如何避免主串指针的回溯,提高搜索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. #include<iostream>
  2. #include<vector>
  3. #include<string>
  4. usingnamespacestd;
  5. strings;//主串
  6. stringt;//模式串
  7. vector<int>next;//next函数值
  8. vector<int>nextval;//next修正函数值
  9. voidget_next()
  10. {
  11. inti=1;
  12. intj=0;
  13. next[1]=0;
  14. while(i<(int)t.size()-1)
  15. {
  16. if(j==0||t[i]==t[j])//i指针不回溯
  17. {
  18. ++i;
  19. ++j;
  20. next[i]=j;
  21. }
  22. else//如果不相等,则j根据已求next回溯,或者找到t[i]==t[j]且j不能再大,则next[++i]=next[++j],或者j==0,则没有能匹配相等的,则++i,++j
  23. {
  24. j=next[j];
  25. }
  26. }
  27. }
  28. voidget_nextval()
  29. {
  30. inti=1;
  31. intj=0;
  32. nextval[1]=0;
  33. while(i<(int)t.size()-1)
  34. {
  35. if(j==0||t[i]==t[j])
  36. {
  37. ++i;
  38. ++j;
  39. if(t[i]!=t[j])
  40. {
  41. nextval[i]=j;
  42. }
  43. else
  44. {
  45. nextval[i]=nextval[j];
  46. }
  47. }
  48. else
  49. {
  50. j=nextval[j];
  51. }
  52. }
  53. }
  54. intindex_kmp(intpos)
  55. {
  56. inti=pos;
  57. intj=1;
  58. while(i<=(int)s.size()-1&&j<=(int)t.size()-1)
  59. {
  60. if(j==0||s[i]==t[j])
  61. {
  62. ++i;
  63. ++j;
  64. }
  65. else
  66. {
  67. j=nextval[j];
  68. }
  69. }
  70. if(j>(int)t.size()-1)
  71. {
  72. returni-((int)t.size()-1);
  73. }
  74. else
  75. {
  76. return0;
  77. }
  78. }
  79. intmain()
  80. {
  81. stringtemp;
  82. s.push_back('#');
  83. t.push_back('#');
  84. cout<<"输入主串:";
  85. getline(cin,temp);
  86. s+=temp;
  87. cout<<"输入模式串:";
  88. getline(cin,temp);
  89. t+=temp;
  90. next.assign(t.size()+1,0);
  91. nextval.assign(t.size()+1,0);
  92. //以上为输入部分
  93. get_nextval();
  94. cout<<index_kmp(1)<<endl;
  95. }
#include <iostream> #include <vector> #include <string> using namespace std; string s;//主串 string t;//模式串 vector<int> next;//next函数值 vector<int> nextval;//next修正函数值 void get_next() { int i=1; int j=0; next[1]=0; while(i<(int)t.size()-1) { if(j==0||t[i]==t[j])//i指针不回溯 { ++i; ++j; next[i]=j; } else//如果不相等,则j根据已求next回溯,或者找到t[i]==t[j]且j不能再大,则next[++i]=next[++j],或者j==0,则没有能匹配相等的,则++i,++j { j=next[j]; } } } void get_nextval() { int i=1; int j=0; nextval[1]=0; while(i<(int)t.size()-1) { if(j==0||t[i]==t[j]) { ++i; ++j; if(t[i]!=t[j]) { nextval[i]=j; } else { nextval[i]=nextval[j]; } } else { j=nextval[j]; } } } int index_kmp(int pos) { int i=pos; int j=1; while(i<=(int)s.size()-1&&j<=(int)t.size()-1) { if(j==0||s[i]==t[j]) { ++i; ++j; } else { j=nextval[j]; } } if(j>(int)t.size()-1) { return i-((int)t.size()-1); } else { return 0; } } int main() { string temp; s.push_back('#'); t.push_back('#'); cout<<"输入主串:"; getline(cin,temp); s+=temp; cout<<"输入模式串:"; getline(cin,temp); t+=temp; next.assign(t.size()+1,0); nextval.assign(t.size()+1,0); //以上为输入部分 get_nextval(); cout<<index_kmp(1)<<endl; }

以下i表示主串位置,j表示模式串位置,s为主串,t为模式串.

KMP算法的牛逼之处就是免去i的回溯, 否则普通的扫描扫着扫着不相等,i又回溯到之前的起始位置的下一个位置,j也回溯到1,又开始匹配.

而KMP则是i一直向前走,一旦遇到不匹配的字符,j回溯到一个可以用来比较的位置,而j之前的t部分串与s串i之前的部分是最大匹配的,然后检测s[i],t[j]是否相等,相等则i可以+1,j+1,继续检测,此时i能够后移的原因是,i之前的部分串已最长的匹配t串,这种理解只可意会,不可言传....

next的作用: 当扫描过程中,如果s[i]!=t[j],那么j=next[j],然后比较s[i]与t[j],此时.....s[i-1]与......t[j-1]是最长匹配的,如果s[i]==t[j],那么++i,++j,继续扫描下一位,如果不相等,那么继续j=next[j],再找一个次长的匹配,比较s[i]与s[j],如果一直到j==0都没有匹配i位的字符,那么说明整个模式串与s[i]以及之前的一段都没有匹配,则++i,++j, 即继续从j=1,i=i+1比较。

next怎么求的:这个非常飘渺, next只与模式串有关,因为在s与t匹配过程中一旦遇到一个字符不匹配,那么就应该尝试用已经匹配的那一段t与已经匹配的s的部分去匹配,然后比较t的部分匹配的下一个位置与s[i]是否相等. 所以求next就相当于t与t进行匹配的过程, 与KMP算法非常类似的,首先令i=1,j=0,next[1]=0,表示如果t[1]与主串的字符不匹配,那么应该去和t[0]比较且t[0]之前部分匹配,但是t[0]没有字符,所以if j==0, ++i,++j, 这一位t[i]已经没法匹配了。 如果t[i]与t[j],则++i,++j,并且++i,++j之前的i,j之前的段属于匹配的,所以++i,++j以后的next[i]=j,即如果s[某一位]与t[i]不相等,那么就可以根据next[i]找到j,用s[某一位]与t[j]比较看是否相等.

nextval怎么求:这个是next的升级版,思想是建立在next之上的,但是并不是说要先求next才能求nextval, nextval只是在next的思想上进一步优化了。 如果求next的过程中,t[i]==t[j],那么本来可以直接写 next[++i]=++j; 但是这时候有一些问题,如果t[++i]与主串s[某位]不相等的时候,我们用next[++i],结果t[next[++i]]与t[++i]又相等,虽然i之前的t串与s串某一位之前完全匹配,但是这样的比较是没有意义的,因为既然匹配过程中已不相等,根据next滑动t串后的比较位与t之前的比较位一样,肯定也不匹配,所以这时候我们就非常需要nextval发挥作用了。 所以如果求next的过程中,t[++i]==t[++j],那么我们应该让j回溯到nextval[j]以找到一个不相等的位匹配,这样就最终求得了nextval的所有情况.

的确是只可意会不可言传,权当自己的思路笔记了。。。。。。。。。。不指望别人能读懂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值