热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

顺序表示的串——串的模式匹配1——基本内容

串的模式匹配也称为子串的定位操作,即查找子串在主串中出现的位置。它是经常用到的一个算法,也是数据结构中的一个难点之一。串的模式匹配算法常见的有两种:Brute-Force朴素模式匹

串的模式匹配也称为子串的定位操作,即查找子串在主串中出现的位置。它是经常用到的一个算法,也是数据结构中的一个难点之一。串的模式匹配算法常见的有两种:Brute-Force朴素模式匹配算法和KMP算法。
【Brute-Force算法】
子串的定位操作串通常称为模式匹配,是各种串处理系统中最重要的操作之一。设有主串S和子串T,如果在主串S中找到一个与子串T相等的串,则返回T的第一个字符在串S中的位置。其中,主串S又称为目标串,子串T又称为模式串。
Brute-Force算法的思想是:从主串S=“s0s1s2…sn-1”的第pos个字符开始与模式串T=“t0t1t2…tm-1”的第一个字符进行比较,如果相等则继续逐个比较后续字符;否则从主串的下一个字符开始重新与模式串T的第一个字符进行比较,依此类推。如果在主串S中存在与模式串T相等的连续字符序列,则匹配成功,函数返回模式串T中第一个字符在主串S中的位置;否则返回-1表示匹配失败。
假设主串S=”ababcabcacbab”模式串T=”abcac”,S的长度n=13,T的长度m=5。用变量i表示主串S当前正在比较字符的下标,变量j表示子串T中当前正在比较字符的下标。模式匹配的过程如图

《顺序表示的串——串的模式匹配1——基本内容》

【BMP算法】

KMP算法是由D.E.Knuth、J.H.Morris、V.R.Pratt共同提出的,因此被称为KMP算法(Knuth-Morris-Pratt算法)。KMP算法在Brute-Force算法的基础上有较大的改进,可在O(n+m)时间数量级上完成串的模式匹配,主要是消除了主串指针的回退,使算法效率有了很大的程度的提高。
根据Brute-Force算法,遇到不相等的字符,将子串后移一位,再从头逐个比较。这样做虽然可行,但是效果很差,因为你要将主串和子串的指针都退回到原来的位置,将已经比较过的字符重新比较一遍。
KMP算法思想是:在每一趟匹配过程中出现字符不等时,不需要回退主串的指针,而是利用已经得到前面“部分匹配”的结果,将模式串向右滑动若干个字符后,继续与主串中的当前字符进行比较。
假设主串S=”ababcabcacbab”模式串T=”abcac”。KMP算法匹配过程如图

《顺序表示的串——串的模式匹配1——基本内容》

 

从图中可以看出,KMP算法的匹配次数从原来的6趟减少为3趟。而对于Brute-Force算法,在第3趟匹配过程中,当i=6,j=4时,主串中的字符与模式串中的字符不相等,又从i=3,j=0开始比较。经过仔细观察,其实在i=3,j=0,i=4,j=0,i=5,j=0这三次比较过程都是没有必要的。因为从第3趟的部分匹配课得出:S2=T0=’a’,S3=T1=’b’,S4=T2=’c’,S5=T3=’a’,S6≠T4,因为S3=T1且T0≠T1,所以S3≠T0,所以没有必要从i=3、j=0开始比较。又因为S4=T2,且T0≠T2,故S4≠T0,所以S4与T0也没有必要从i=4、j=0开始比较。又因为S5=T3且T0=T4,故S5=T0,所以也没有必要将S5与T0进行比较。

《顺序表示的串——串的模式匹配1——基本内容》
也就是说,根据第3趟的部分匹配也可以得出结论:Brute-Force算法算法的第4、5趟是没有必要的,第6趟也没有必要将主串的第6个字符与模式串的第1个字符比较。

《顺序表示的串——串的模式匹配1——基本内容》

因此,只需要将模式串向右滑动3个字节,从i=6,j=1开始比较。同理,在第1 趟匹配的过程中,当出现字符不相等时,只需将模式串向右滑动2个字符,从i=2、j=0开始比较即可。在整个KMP算法中,主串中的i指针没有回退。
下面来讨论一般情况。设主串S=“s0s1s2…sn-1”模式串T=“t0t1t2…tm-1”。在模式匹配过程中,若出现字符不匹配的情况,即当si≠tj(0≤i

“si-j si-j+1 … si-1″=”tj-k tj-k+1 … tj-1″(1)

即说明至少在字符si之前有一部分字符是相等的。

若子串(即模式串)中存在收尾重叠的真子串,即:

“t0 t1 … tk-1” = “tj-k tj-k+1 … tk-1″(2)

根据(1)(2)可以得出:

“si-k si-k+1 … si-1” = “t0 t1 …tk-1”

如图

《顺序表示的串——串的模式匹配1——基本内容》

因此,在匹配的过程中,主串中的第i个字符与模式串的第j个字符不等时,仅需将子串向右滑动,使si与tk对齐,接着进行后续的比较,此时,模式串中的子串”t0 t1 … tk-1″ 必与主串中的子串”si-k si-k+1 … si-1″ 相等。

如图

《顺序表示的串——串的模式匹配1——基本内容》

【求next函数值】

下面就来确定模式串需要滑动的具体位置。令next[j]=k,则next[j]表示当模式串中的第j个字符与主串中对应的字符不相等时,需要重新与主串比较的模式串字符位置,也就是需要将模式串滑动到第几个字符与主串比较。

求模式串中的next函数定义如下图:

《顺序表示的串——串的模式匹配1——基本内容》

其中,第1种情况,next[j]的函数是为了方便算法设计而定义的;
第2种情况,如果子串(模式串)中存在首尾重叠的真子串,则next[j]的值就是k,即模式串的最长子串的长度;
第3种情况,如果模式串中不存在重叠的子串,则从子串的第一个字符开始比较。

由此可以得到模式串“abcac”的next函数值

如图

《顺序表示的串——串的模式匹配1——基本内容》

KMP算法的模式匹配过程:如果模式串T中存在真子串”t0 t1 … tk-1″ = “tj-k tj-k+1 … tj-1″,当模式串T的tj与主串的si不相等,按照next[j]=k将模式串向右滑动,从主串中的si与模式串的tk开始比较。如果si=tk,则继续比较下一字符。如果si≠tk,则按照next[next[j]]将模式串继续向右滑动,将主串中的si与模式串中的next[next[j]]字符进行比较。如仍然不相等,则按照以上方法,将模式串继续向右滑动,直到next[j]=-1为止。这时,模式串不再向右滑动,从si+1开始与t0进行比较。

利用next函数值的一个模式匹配例子

如图

《顺序表示的串——串的模式匹配1——基本内容》

KMP模式匹配算法是建立在模式串的next函数值已知的基础上的。下面讨论如何求模式串的next函数值。

从上面的分析可以看出,模式串的next函数值的取值与主串无关,仅与模式串相关。根据模式串next函数定义,next函数可以由地推的方法得到。

设next[j]=k,表示在模式串T中存在以下关系:

“t0 t1 … tk-1” = “tj-k tj-k+1 … tj-1”

其中,0k满足以上等式。计算next[j+1]的值需要考虑以下两种情况:

(1)若tj=tk,则表示在模式串T中满足以下关系:
“t0 t1 … tk” = “tj-k tj-k+1 … tj”
并且不可能存在k’>k满足以上等式。因此有
next[j+1]=k+1,即next[j+1]=next[j]+1

(2)若tj≠tk,则表示模式串T中满足以下关系:

“t0 t1 … tk” ≠ “tj-k tj-k+1 … tj”

此时,已经有”t0 t1 … tk-1″ = “tj-k tj-k+1 … tj-1″,但是tj≠tk,把模式串T向右滑动到k’=next[k](0

因此得到

next[j+1]=k’+1 即next[j+1]=next[k’]+1

如果tj≠tk’ ,则将模式串继续向右移动到next[k’]个字符与tj比较。如果仍不相等,则将模式串继续向右滑动到下标为next[next[k’]]字符与tj进行比较。依此类推,直到tj和模式串中某个字符相等或者不存在任何k’满足”t0 t1 … tk’ ” = “tj-k tj-k+1 … tj”,则有

next[j+1]=0

上述讨论的是根据next函数的定义如何得到next函数值的方法。例如,模式串为T=”abcdabcdabe”的next函数值

如图
 

《顺序表示的串——串的模式匹配1——基本内容》

例如,在已经得到的前3个字符next函数值的基础上,如果求next[3]。因为next[2]=1,且t2=t0,则next[3]=next[2]+1=2。接着求next[4],因为t2=t0,但“t2t3”≠“t0t1”,所以需要将t3与下标为next[1]=0的字符即t0进行比较,因为t0≠t3,所以next[4]=1。


推荐阅读
  • 本文汇集了作者在准备研究生入学考试过程中的心得体会,包括备考策略、复习重点及应对考试的心理调适技巧,旨在为即将参加考研的学生提供实用建议。 ... [详细]
  • 使用R语言进行Foodmart数据的关联规则分析与可视化
    本文探讨了如何利用R语言中的arules和arulesViz包对Foodmart数据集进行关联规则的挖掘与可视化。文章首先介绍了数据集的基本情况,然后逐步展示了如何进行数据预处理、规则挖掘及结果的图形化呈现。 ... [详细]
  • 本文介绍了如何通过 ADB 命令行工具启动和停止 Android 应用。通过简单的命令,您可以轻松地控制设备上的应用运行状态。 ... [详细]
  • 本文介绍了如何使用jQuery获取浏览器窗口的可视区域高度、文档的整体高度以及宽度等关键尺寸信息,包括边界、填充和边距在内的完整尺寸。 ... [详细]
  • SPFA算法详解与应用
    当图中包含负权边时,传统的最短路径算法如Dijkstra不再适用,而Bellman-Ford算法虽然能解决问题,但其时间复杂度过高。SPFA算法作为一种改进的Bellman-Ford算法,能够在多数情况下提供更高效的解决方案。本文将详细介绍SPFA算法的原理、实现步骤及其应用场景。 ... [详细]
  • 本文详细介绍了Socket在Linux内核中的实现机制,包括基本的Socket结构、协议操作集以及不同协议下的具体实现。通过这些内容,读者可以更好地理解Socket的工作原理。 ... [详细]
  • 探索CNN的可视化技术
    神经网络的可视化在理论学习与实践应用中扮演着至关重要的角色。本文深入探讨了三种有效的CNN(卷积神经网络)可视化方法,旨在帮助读者更好地理解和优化模型。 ... [详细]
  • 我整理了HMOV四大5G旗舰的参数,可依然没能拯救我的选择困难症
    伊瓢茕茕发自凹非寺量子位报道|公众号QbitAI报道了那么多发布会,依然无法选出要换的第一部5G手机。这不,随着华为P40系列发布,目前国 ... [详细]
  • 最优化算法与matlab应用3:最速下降法
    最优化算法与matlab应用3:最速下降法最速下降法是一种沿着N维目标函数的负梯度方向搜索最小值的方法。(1)算法原理函数的负梯度表示如下:搜索步长可调整ak,通常记为(第k次迭代 ... [详细]
  • Java高级工程师学习路径及面试准备指南
    本文基于一位朋友的PDF面试经验整理,涵盖了Java高级工程师所需掌握的核心知识点,包括数据结构与算法、计算机网络、数据库、操作系统等多个方面,并提供了详细的参考资料和学习建议。 ... [详细]
  • 本文探讨了在 Python 2.7 环境下,如何有效地对大量数据(如几百 KB 的字符串)进行加密和压缩,并确保能够准确无误地解密回原始数据。 ... [详细]
  • ACM经典书籍推荐
    本文介绍了几本在算法和计算机科学领域具有重要影响力的书籍,包括由Donald E. Knuth编著的《计算机程序设计艺术》第一卷,以及潘氏兄弟的数论经典教材等。这些书籍不仅是学习相关领域的宝贵资源,也是专业人士不可或缺的参考书。 ... [详细]
  • Linux内核中的内存反碎片技术解析
    本文深入探讨了Linux内核中实现的内存反碎片技术,包括其历史发展、关键概念如虚拟可移动区域以及具体的内存碎片整理策略。旨在为开发者提供全面的技术理解。 ... [详细]
  • 通过两幅详细的思维导图,全面解析Spring框架中应用的设计模式及其核心编程理念。 ... [详细]
  • 本文详细探讨了 Android Service 组件中 onStartCommand 方法的四种不同返回值及其应用场景。Service 可以在后台执行长时间的操作,无需提供用户界面,支持通过启动和绑定两种方式创建。 ... [详细]
author-avatar
blg1202702934392
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有