【算法解析】
● 众所周知,KMP算法中模式串T的next数组,是KMP算法的核心。
next数组的核心作用是“当模式串T的第j位与主串S的第pos位失配时(即 T[j]≠S[pos] 时),让模式串T的第next[j]位与主串S的第pos位再进行比较”。这相当于让模式串T往右移动了 j-next[j] 位后,再进行比较。
● 正是由于next数组的引入,使得KMP算法的效率大大优于BF算法。但是,next数组在某些情况下仍存在缺陷。
例如,针对模式串"aaaab",其相应的next数组值为“-1 0 1 2 3”。则据next数组的作用易知,当 T[3]=a 与主串 S[pos] 失配时,则会使用 T[next[3]]=T[2]=a 与主串 S[pos] 再进行匹配,显然还会失配。这是因为,T[0]~T[2]与T[3]都相等,当T[3]与S[pos]失配时,T[0]~T[2]与S[pos]必然也失配。显然T[0]~T[2]与S[pos]的比较没有意义,一定会匹配失败。针对本模式串"aaaab"而言,将会有 T[3]=a≠S[pos],T[next[3]]=T[2]=a≠S[pos],T[next[2]]=T[1]=a≠S[pos],T[next[1]]=T[0]=a≠S[pos] 等四次比较。
● nextval数组的引入,正是为了减少这种无意义的比对,而对next数组进行的优化。
【手动求nextval数组的步骤】
● 手动求nextval数组(模式串下标从1开始)
若在KMP算法设计中,将模式串下标从1开始计数,那么求nextval数组的算法步骤为:
(1)求出next数组的值(定义next[1]=0,next[2]=1);
(2)定义nextval[1]=0。然后,比较模式串的第j个(j>1)字符是否与第next[j]个字符相等。若相等,则模式串第j个字符的nextval值等于第next[j]个字符的nextval值。若不等,则模式串第j个字符的nextval值等于其next数组值。
即,若T[j]=T[next[j]],则nextval[j]=nextval[next[j]]。否则,nextval[j]=next[j]。


● 手动求nextval数组(模式串下标从0开始)
若在KMP算法设计中,将模式串下标从0开始计数,那么求nextval数组的算法步骤为:
(1)求出next数组的值(定义next[0]=-1,next[1]=0);
(2)定义nextval[0]=-1。然后,比较模式串的第j个(j>0)字符是否与第next[j]个字符相等。若相等,则模式串第j个字符的nextval值等于第next[j]个字符的nextval值。若不等,则模式串第j个字符的nextval值等于其next数组值。
即,若T[j]=T[next[j]],则nextval[j]=nextval[next[j]]。否则,nextval[j]=next[j]。
【求nextval数组的算法代码】
- #include
- using namespace std;
-
- const int maxn=100;
- int ne[maxn],nev[maxn];
-
- void getNext(string s) {
- int len=s.length();
- int i=0,j=-1;
- ne[0]=-1;
- while(i
- if(j==-1||s[i]==s[j]) {
- i++;
- j++;
- ne[i]=j;
- } else j=ne[j];
- }
- }
-
- void getNextval(string s) {
- int len=s.length();
- int i=0,j=-1;
- nev[0]=-1;
- while(i
- if(j==-1||s[i]==s[j]) {
- i++;
- j++;
- nev[i]=j;
- if(s[i]!=s[j]) nev[i]=j;
- else nev[i]=nev[j];
- } else j=nev[j];
- }
- }
-
- int main() {
- string T;
- getline(cin,T);
-
- getNext(T);
- for(int i=0; i
length(); i++) { - cout<
" "; - }
-
- cout<
-
- getNextval(T);
- for(int i=0; i
length(); i++) { - cout<
" "; - }
-
- return 0;
- }
-
-
- /*
- input:
- abcaabbabcab
- output:
- -1 0 0 0 1 1 2 0 1 2 3 4
- -1 0 0 -1 1 0 2 -1 0 0 -1 4
- */
【编程技巧】
● 由于字符串的下标从0开始,因此采用李春葆《数据结构》中的方式定义nextval[0]=-1,nextval[1]=0是很自然的事情。之后,利用语句 cout< ● 若想输出以“0 1”开头的nextval数组值,只需修改语句cout<cout< 便可。其他代码保持不变。
【参考文献】
https://blog.csdn.net/qq_43456605/article/details/119954614
https://blog.csdn.net/qq_35963993/article/details/106236665
-
相关阅读:
pytorch 学习第三天 交叉熵
Jquery 老项目引入vue,elementui
Linux:线程池
互联网历史
软件工程毕业设计课题(80)微信小程序毕业设计PHP电影视频播放小程序系统设计与实现
【SpringBoot】必须掌握的45个注解
CV相关 - 文献地址地址、数据集地址
linux下常用命令
怎么把加密的PDF解密?安利几个办公小技巧
贴纸拼词 —— 记忆化搜索 / 状压DP
-
原文地址:https://blog.csdn.net/hnjzsyjyj/article/details/127105603