计算机基础数据结构讲解第十二篇-字符串模式匹配KMP算法第二讲
现在继续讲解KMP算法的有关知识,以及KMP算法的代码和改进,改进用nextval[]数组。
一:next公式讲解
由公式可知next[1]=0,也就是模式串第一个字符(j=1),与主串第i个字符发生失配时,规定next[1]=0,将模式串右移一位,然后模式串第一个字符和主串的下一个位置(i+1)进行比较。
设next[j]=k,那此时next[j+1]等于多少呢?可能有两种情况:
1.Pk=Pj
若Pk=Pj,则说明有最大公共前后缀,此时next[j+1]=k+1,即next[j+1]=next[j]+1。
2.Pk≠Pj
若Pk≠Pj,则说明找到的最大公共前后缀不符合,这时可以把求next函数值的问题视为一个模式匹配的问题,如果不匹配,需要找到长度更短的相等前后缀,依次类推则一直向后寻找,寻找更小的k为k',则next[j+1]=k'+1。也可能不存在任何k'满足上诉条件,即不存在长度更短的相等前缀后缀,令next[j+1]=1。
关于知道next[j]的值,计算next[j+1]的值这里已经介绍了,下面就来介绍求next值的程序。
二:求next程序
算法如下:
void get_next(String T,int next[]){
int i=1;j=0;
next[1] = 0;
while(i<T.length){
if(j==0!!T.ch[i]=T.ch[j]){
++i;++j;
next[i] = j; //Pi=Pj
}
else
j=next[j]; //否则令j=next[j],循环继续
}
}
用手工的方法计算的时候,比较困难,所以还是用之前的方法求next数组。而KMP算法就比较简单了,根据之前得到的过程代码如下:
int Index_KMP(String S,String T,int next[]){
int i = 1;j = 1;
while(i<=S.length&&j<=T.length){
if(j==0||S.ch[i]=S.ch[j]){
++i;++j //没有公共前后缀或子串第一个字符比较,直接比较i+1位
}
else
j=next[j]; //模式串向右移动
}
if(j>T.length)
return i = T.length; //匹配成功
else
return 0;
}
由上面的推断可知,KMP算法的时间复杂度是O(n+m),但在一般情况下,普通模式匹配的实际执行时间近似为O(n+m),因此至今仍被采用。KMP算法仅在主串与子串有很多部分匹配,即最长公共前后缀时才显得比普通算法快得多,其主要优点是主串不回溯。
三:KMP算法的进一步优化
前面定义的next数组在某些情况下尚有缺陷,还可以进一步优化。当Pj≠Sj,下次匹配应该是P(next[j])跟Sj比较,如果Pj=P(next[j]),那么相当于拿一个和Pj相等的字符跟Sj比较,这必将导致继续失配,这样的比较毫无意义。
那么如何进行处理呢?就可以继续递归,将next[j]修正为next[next[j]],直至两者不相等为止,更新后的数组命名为nextval。计算next数组修正值的算法如下,匹配算法不变,只需要修改一部分。代码如下:
void get_nextval(String T,int nextval[]){
int i=1;j=0;
nextval[1] = 0;
while(i<T.length){
if(j==0!!T.ch[i]=T.ch[j]){
++i;++j;
if(T.ch[i]!=T.ch[j])
nextval[i] = j
else
nextval[i] = nextval[j];
}
else
j=next[j];
}
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 2025成都.NET开发者Connect圆满结束