当前位置: 首页 > news >正文

数据结构——KMP算法

KMP算法

BF算法因主串指针频繁回溯,在最坏情况下效率较低。KMP算法通过预处理模式串,利用其前缀后缀的重叠特性,避免主串指针回溯,大幅提升匹配效率,是字符串模式匹配的经典优化算法。

1. KMP算法的核心思想

KMP算法的核心是消除主串指针的回溯。当模式串与主串某位置匹配失败时,不是将主串指针回退到“上一次起始位置的下一个”,而是通过分析模式串的“前缀-后缀重叠信息”,直接将模式串指针跳转到合适的位置,继续与主串当前位置的字符比较。

这里的“前缀-后缀重叠”指:模式串中某子串的“前缀”(从第一个字符开始的子串)和“后缀”(以最后一个字符结尾的子串)存在相等的部分。例如,模式串“abab”中,子串“aba”的前缀“a”和后缀“a”相等,长度为1;子串“ab”的前缀“a”和后缀“b”不相等,长度为0。这种重叠信息可用于匹配失败时的指针跳转,避免主串指针重复比较。

2. next数组的定义与计算

为了实现指针的智能跳转,KMP算法引入next数组:对于模式串的第jjj个字符(从0开始),next[j]next[j]next[j]表示“模式串前jjj个字符组成的子串的最长相等前缀后缀长度”。

(1)next数组的定义示例
以模式串T=T =T=“ababc”为例,计算每个位置的next[j]next[j]next[j],结果如下表:

模式串字符位置 jjj0(‘a’)1(‘b’)2(‘a’)3(‘b’)4(‘c’)
next[j]next[j]next[j]00120
  • j=0j=0j=0:子串只有一个字符,无前后缀,next[0]=0next[0]=0next[0]=0
  • j=1j=1j=1:子串“ab”,前缀“a”和后缀“b”不相等,next[1]=0next[1]=0next[1]=0
  • j=2j=2j=2:子串“aba”,前缀“a”和后缀“a”相等,长度1,next[2]=1next[2]=1next[2]=1
  • j=3j=3j=3:子串“abab”,前缀“ab”和后缀“ab”相等,长度2,next[3]=2next[3]=2next[3]=2
  • j=4j=4j=4:子串“ababc”,无相等的前缀后缀,next[4]=0next[4]=0next[4]=0

(2)next数组的计算方法
计算nextnextnext数组可通过动态规划实现,核心逻辑是“利用已计算的nextnextnext值推导当前next[j]next[j]next[j]”:

  • 初始化next[0]=0next[0] = 0next[0]=0,定义指针i=0i=0i=0(前缀指针)、j=1j=1j=1(后缀指针);
  • T[i]==T[j]T[i] == T[j]T[i]==T[j]:说明前缀后缀可延长,next[j]=i+1next[j] = i+1next[j]=i+1i++i++i++j++j++j++
  • T[i]!=T[j]T[i] != T[j]T[i]!=T[j]:若i>0i > 0i>0,则i=next[i−1]i = next[i-1]i=next[i1](回退到前一个位置的最长前缀后缀长度);否则next[j]=0next[j] = 0next[j]=0j++j++j++

以下是计算nextnextnext数组的C语言代码(嵌入KMP算法中):

// 计算模式串t的next数组
void getNext(char t[], int next[], int m) {int i = 0, j = 1;next[0] = 0;while (j < m) {if (t[i] == t[j]) {next[j] = i + 1;i++;j++;} else {if (i > 0) i = next[i - 1];else {next[j] = 0;j++;}}}
}
3. KMP算法的匹配过程

KMP的匹配过程基于nextnextnext数组,主串指针iii始终不回溯,模式串指针jjj根据next[j]next[j]next[j]跳转,步骤如下:

  • 初始化i=0i=0i=0(主串指针)、j=0j=0j=0(模式串指针);
  • 比较S[i]S[i]S[i]T[j]T[j]T[j]
    • 若相等:i++i++i++j++j++j++,继续比较下一个字符;
    • 若不相等:若j>0j > 0j>0,则j=next[j−1]j = next[j-1]j=next[j1](根据next数组跳转);否则i++i++i++(主串指针后移,模式串从头开始);
  • 重复上述步骤,直到j==mj == mj==m(匹配成功,返回i−mi - mim)或i==ni == ni==n(匹配失败,返回-1)。

以“主串S=S =S=‘ababcabcacbab’,模式串T=T =T=‘abcac’(nextnextnext数组为[0,0,1,0,2])”为例:

  • 初始i=0,j=0i=0, j=0i=0,j=0S[0]=′a′==T[0]=′a′S[0]='a' == T[0]='a'S[0]=a==T[0]=ai=1,j=1i=1, j=1i=1,j=1
  • S[1]=′b′==T[1]=′b′S[1]='b' == T[1]='b'S[1]=b==T[1]=bi=2,j=2i=2, j=2i=2,j=2
  • S[2]=′a′!=T[2]=′c′S[2]='a' != T[2]='c'S[2]=a!=T[2]=cj=next[1]=0j = next[1] = 0j=next[1]=0
  • S[2]=′a′==T[0]=′a′S[2]='a' == T[0]='a'S[2]=a==T[0]=ai=3,j=1i=3, j=1i=3,j=1
  • S[3]=′b′==T[1]=′b′S[3]='b' == T[1]='b'S[3]=b==T[1]=bi=4,j=2i=4, j=2i=4,j=2
  • S[4]=′c′==T[2]=′c′S[4]='c' == T[2]='c'S[4]=c==T[2]=ci=5,j=3i=5, j=3i=5,j=3
  • S[5]=′a′!=T[3]=′a′S[5]='a' != T[3]='a'S[5]=a!=T[3]=a? 纠正,模式串“abcac”的第3个字符是‘a’,S[5]=′a′==T[3]=′a′S[5]='a' == T[3]='a'S[5]=a==T[3]=ai=6,j=4i=6, j=4i=6,j=4
  • S[6]=′c′==T[4]=′c′S[6]='c' == T[4]='c'S[6]=c==T[4]=cj=5==m=5j=5 == m=5j=5==m=5,匹配成功,返回i−m=6−5=1i - m = 6 - 5 = 1im=65=1(实际起始位置需根据示例调整,核心是跳转逻辑)。
4. KMP算法的代码实现

以下是KMP算法的完整C语言实现,包含nextnextnext数组计算和匹配过程:

// KMP算法:s为主串,t为模式串,n为主串长度,m为模式串长度
int KMP(char s[], char t[], int n, int m) {int next[m];getNext(t, next, m); // 计算next数组int i = 0, j = 0;while (i < n && j < m) {if (s[i] == t[j]) { // 字符相等,继续i++;j++;} else {if (j > 0) j = next[j - 1]; // 模式串指针跳转else i++; // 主串指针后移}}return j == m ? i - m : -1; // 匹配成功返回起始位置,否则返回-1
}// 计算next数组(辅助函数)
void getNext(char t[], int next[], int m) {int i = 0, j = 1;next[0] = 0;while (j < m) {if (t[i] == t[j]) {next[j] = i + 1;i++;j++;} else {if (i > 0) i = next[i - 1];else {next[j] = 0;j++;}}}
}
5. KMP算法的性能分析

KMP算法的时间复杂度由两部分组成:计算nextnextnext数组的时间O(m)O(m)O(m)mmm为模式串长度),以及匹配过程的时间O(n)O(n)O(n)nnn为主串长度)。因此,整体时间复杂度为O(n+m)O(n + m)O(n+m),远优于BF算法的最坏情况O(n×m)O(n \times m)O(n×m)

例如,当主串长度n=106n=10^6n=106,模式串长度m=103m=10^3m=103时,KMP算法只需约106+10310^6 + 10^3106+103次操作,而BF算法最坏可能需要10910^9109次操作,效率差距显著。

综上,KMP算法通过预处理模式串得到nextnextnext数组,消除了主串指针的回溯,实现了线性时间复杂度的字符串模式匹配。其核心是对“前缀-后缀重叠信息”的利用,这一思想不仅解决了字符串匹配问题,也为其他领域的算法优化提供了启发。理解KMP的nextnextnext数组计算和匹配逻辑,是掌握高级字符串处理技术的关键。

http://www.dtcms.com/a/525486.html

相关文章:

  • 湖北微网站建设报价我的手机网站
  • Spring集成WebSocket
  • MinerU系列最新迭代版本上线,专为高精度、高效率的文档解析任务设计;清华、字节联合推出HuMo,实现三模态协同生成人物视频
  • 什么是企业营销型网站seo公司优化排名
  • 洛阳有做网站开发的吗wordpress重构
  • 呼和浩特网站建设电话西安网页设计培训
  • uniapp开发小程序,实现开通会员卡页面
  • 微信小程序开发案例 | 简易登录小程序
  • uniapp开发小程序,Canvas实现海报生成邀请码,邀请好友功能
  • 江苏省建设斤网站宁波seo关键词
  • 第 03 天:Linux 文件夹结构与文件类型
  • 网站页面安全监测建设方案成为软件工程师的条件
  • cesium点、线、面、模型
  • 风电项目管理软件:陆上风电、海上风电、山地风电、戈壁风电、风电吊装、风电EPC、风电安装与施工等建设工程的信息与数字化管理
  • 深圳公司建立网站电子商务网站应该如何建设
  • 建设厅网站实名制系统如何解聘租个网站服务器多少钱
  • 天硕工业级固态硬盘:以主动抗浪涌技术定义高可靠国产存储标杆
  • Linux文件系统挂载与卸载完全指南
  • 测试:uk8s创建监控和告警同步飞书等渠道
  • 欧美做暖网站哈尔滨网站建设效果好
  • 南开大学 网站开发技术 刘冲关于行业网站建设意见
  • React学习笔记(一)
  • Linux综合练习
  • 与网站开发相关的书籍国家免费职业培训平台
  • 机器人外呼人机耦合还有哪些潜在成本误区
  • 详细讲解条件变量
  • 筑牢风控生命线:金仓数据库替代MongoDB,重构证券融资融券业务的数据基石
  • 网站的时间对齐应该怎么做ftp跟网络连接Wordpress
  • 阿里云国际站GPU:怎么通过控制台自助排查功能诊断GPU?
  • 做商贸网站安徽省住房建设部官方网站