字符串匹配定义:文本是一个长度为n的数组T[1…n], 模式是以个长度m<=n的数组P[1…m]
P和T的元素都是有限字母表∑中的字符
1.字符串朴素匹配
也就是蛮力匹配,每次移动一个步长,然后匹配,时间复杂度O((n-m+1)m)
2.Rabin-Karp算法
Rabin-Karp算法的思想是将模式串P表达为一个值,这样每次进行串匹配的时候,只需要比较这个值就可以了,而不需要对m个字符串进行m次比较。
核心思想是用 一个值 来代替 整个字符串 来参与比较
比如以十进制为例,文本串为'1234567',模式串为'234'(其值为234),当搜索指针指向第一个字符'1'时,计算出串'123'的值为123,直接与模式串的值234进行比较,不匹配,那么就表明此时模式串匹配失败,将搜索指针移向下一个字符。
如何用 值 来代表 字符串?
想象一下将字符串转换为数值的情形
计算串"123"的值:1*100+2*10+3*1 = 123
串"6789"的值:6*1000+7*100+8*10+9*1 = 6789
十进制字母表只有0-9,因此选取基数10可以完成的表述整个串
对于Ascii字母表,则可以选取基256。
因此,将一个串表述成一个值是可行的,其时间复杂度为O(m),其中m为串的长度。
对于文本串T[1…n],可以在O(m)的时间复杂度计算出前m个字符T[1…m]的值。
而T[2…m+1],T[3…m+2],...T[n-m+1…n]的值,可以在O(n-m)的时间计算出来(动态规划)。
新的问题:值太大,溢出?
通过一个值来表述一个串以后,如果串比较长,那么这个表述串的这个值自然会比较大,而且,可能会溢出。很自然的解决办法是对这个值取模,将它限制到一个固定的范围内。
那么问题又来了,模运算是多对一映射,比如,55和66对11取模后都是0,但是它们的值并不相等。
因此,取模运算会导致一个新的问题,就是伪命中。也就是,模运算匹配,但串本身并不匹配。
可以显式的检查T[i…m+i]与P[1…m]是否相等。
假设计算的值对q取模,倘若q够大,那么T[i…m+i]的值与P[1…m]的值发生伪命中的几率就会比较低,那么额外的测试时间就足够低了。
这样看来,对字符串求值,通过值来进行串的匹配,更像一个启发式的思想,对文本串进行一次过滤,然后在进行逐字匹配。
由于每次在判定模式串是否匹配时,只需要进行一次比较,因此匹配过程中的期望时间复杂度为O(n-m+1),这个时间没有加上对模式串求值的时间O(m)。最坏是时间复杂度也为O((n-m+1)m),也就是每一次唯一产生的值都与串的值取模相等,但实际情况下比蛮力匹配要快许多。
3.FA
针对模式串,构造一个有穷自动机,那么,有穷自动机接收的语言就是该模式串匹配的句子。
对于每个模式串,都存在一个字符串匹配自动机,必须在预处理阶段,根据模式构造出相应的自动机后,才能利用它来搜索字符串。构造自动机的核心是构造其状态转移函数。
这种方法功能比较强大,因为它可以搜索以正则式表达的模式串。而其他算法则不能。
4.KMP
先看一个例子。文本串T为bababaabcccb,模式P为ababaca
。
如图所示。此时,红色的5个字符ababa已经匹配,
从字符c开始不匹配。这时候开始移动模式P。到底该移动几个字符呢?朴素的字符串匹配移动一位,然后重新开始比较。但是根本模式本身的信息,移动s'=s+1是无效的,s'=s+2才有可能导致一个成功的匹配。因为模式P的前5个字符里,ababa的前面三个字符aba同时也是ababa的后缀。也就是说,P的最长前缀同时也是P5的的一个真后缀。这些信息是可以被预先计算的,用前缀函数π来表示。在位移s处有q个字符成功匹配,那下一个可能有效的位移为s'=s+(q-π[q]).
首先假定文本串从第s个位置开始与模式匹配,共匹配q个字符,匹配第q+1个字符时失败,即满足:P[1…q]=T[s+1…s+q],那么,我们的目标就是,寻找一个位移s',使得移动1,2,..s'-1都是不可能导致与模式P匹配成功,只有移动s',才有可能使得与模式P匹配成功。那该怎么寻找这个位移呢?关键就在这个模式本身了。
如果P[1…q]已经匹配成功,在q+1处匹配失败,倘若已知P[1…k]=P[q-k+1…q](k<q)且k是满足如上等式条件的最大的k,那么,直接移动q-k个位置就可以使得前面的k个字符相匹配。
这个k就包含了模式串本身的信息。它预先被计算,被定义为前缀函数。定义如下:
模式P的前缀函数是函数π(0,1,2,...,m-1}→{0,1,2,..,m-1}并满足
π[q]=max{k:k<q且Pk是Pq的后缀,即P[1…k]=P[q-k+1…q]},
π[q]是Pq的真后缀P的最长前缀的长度。
下面是前缀函数的一个计算例子。
计算前缀函数本身就是一个模式串“自我匹配”的过程。KMP的核心也在于通过前缀函数来减少不必要的比较而加快字符串的匹配速度。前缀函数里面包含了模式串的部分匹配信息,也就是当把模式串的前面部分字符移动一段位移后在模式中重复出现,那么这个部分匹配信息就可以用在串匹配中。
也可以看这个,写的还比较详细:
http://jpkc.nwu.edu.cn/datastr/study_online/newsite/pluspage/kmp.htm
5.BM
BM算法有几个要点
1.从右向左进行比较,也就是比较次序为P[m],P[m-1]...
2.当某趟比较中出现不匹配的字符时,BM采用两条启发式规则计算模式串移动的距离,即bad character
shift rule坏字符和good suffix shift rule好后缀规则。
坏字符与好后缀的定义
Index: 0 1 2 3 4 5 6 7 8 9 10 11
Text: k s e a b c d e f a b c a
Pattern: d e c a b c
从右往左进行匹配,第一个mismatch的字符c就是坏字符,后面已经成功匹配的字串abc就是好后缀。
如果字符没有在模式串中
1) 坏字符规则
P中的某个字符与T中的某个字符不相同时使用坏字符规则右移模式串P,P右移的距离可以通过delta1函数
计算出来。delta1函数的定义如下:
delta1(x) = 如果字符x在P中未出现,则为 m(模式长度); 否则 m-k, j是最大的整数使得P[k]=字符x,
用数学表达式则为:m - max{k|P[k] = x, 1 <= k <= m};
解释一下,如果字符x在模式P中没有出现,那么从字符x开始的m个文本显然不可能与P匹配成功,直接全部跳
过该区域即可。如果x在模式P中出现,则以该字符进行对齐。
2) 好后缀规则
P中的某一子串P[j-s+1..m-s]与已比较部分P[j+1..m]相同,可让P右移s位。
delta2的定义如下:
delta2(j)= {s|P[j+1..m]=P[j-s+1..m-s])&&(P[j]≠P[j-s])(j>s)}
(这部分还看得晕乎晕乎的,下次在来完善)
贴个BM例子
移动的时候,取两者较大值作为位移值移动。
BM算法在字母表很大,模式串很长时尤其适用,能够显著提高匹配速度。
实际应用中,BM算法比同样具有O(m+n)时间复杂度的KMP算法效率高出3-5倍。具体来说,BM算法的预处理阶段的时间空间复杂性是O(m+n),查找阶段的时间复杂性是O(mn),最好情况下的性能是O(n/m)。
参考:
前面几个算法主要参考《算法导论》
BM算法参考
http://www.cs.utexas.edu/users/moore/best-ideas/string-searching/index.html
http://www-igm.univ-mlv.fr/~lecroq/string/node14.html
分享到:
相关推荐
带通配符的字符串匹配算法则是这个领域的延伸,它允许在模式字符串中包含特殊字符,如星号(*)或问号(?),以表示任意字符或单个任意字符。这种算法使得搜索更加灵活,可以适应更复杂的查询需求。 **通配符的含义** -...
在C语言中,实现字符串匹配算法通常涉及到对字符数组的操作和逻辑控制结构。本篇文章将详细探讨四种常见的字符串匹配算法:平凡算法(SimpleSM)、KMP算法(KMPSM)、BM算法(bmSM)以及RK算法(rkSM),并分析它们...
**KMP字符串匹配算法详解** KMP(Knuth-Morris-Pratt)字符串匹配算法是由D.E. Knuth、V.J. Morris和J.H. Pratt三位学者于1977年提出的,它是一种高效的字符串搜索算法,主要用于在一个主串(text)中查找是否存在...
### 字符串匹配算法之Horspool算法:深入解析与应用 #### 引言 在计算机科学领域,字符串匹配是一项核心任务,广泛应用于文本编辑、数据检索、模式识别等多个场景。传统的简单匹配算法如逐一比较法往往在面对大...
在这个主题中,我们将探讨三种经典的字符串匹配算法:穷举法、KMP(Knuth-Morris-Pratt)算法和BM(Boyer-Moore)算法。 1. **穷举法**:也称为朴素匹配算法,是最直观的字符串匹配方法。它通过比较主串中的每个...
### 改进的多模式字符串匹配算法 #### 摘要与背景介绍 本文提出了一种改进的多模式字符串匹配算法,旨在优化经典的AC(Aho-Corasick)多模式字符串匹配算法,并融合了BMH(Boyer-Moore-Horspool)算法的优势。这一...
这里我们将深入探讨几种常见的字符串匹配算法,包括Brute Force算法、KMP算法、Horspool算法以及Boyer-Moore算法。 1. **Brute Force算法**:这是最直观的字符串匹配方法,也被称为简单匹配。它将模式串与匹配串...
《多模式字符串匹配算法——AC_BM算法的深度解析与实现》 字符串匹配算法是计算机科学中的一个重要领域,尤其在文本处理、搜索引擎、数据挖掘等领域有着广泛应用。其中,AC_BM算法,即Aho-Corasick算法结合Boyer-...
### 字符串匹配算法小集解析 #### 一、引言 本文档提供了一系列共35种不同的字符串匹配算法,这些算法在英文环境下被广泛讨论和应用。通过对这些算法进行详细的解析,我们可以更好地理解每种算法的特点、应用场景...
### 入侵检测技术中一种改进的字符串匹配算法的研究 #### 概述 随着网络环境的日益复杂化,网络攻击事件频繁发生,如何有效监测和响应这些潜在威胁成为了网络安全领域的重要课题。入侵检测系统(IDS)作为网络安全...
**字符串匹配算法-BM算法的实现代码** 在计算机科学领域,字符串匹配算法是寻找一个字符串(称为模式)在另一个较大的字符串(称为文本)中的过程。BM(Boyer-Moore)算法是一种高效的字符串搜索算法,由Robert S. ...
一般而言文本就是要编辑的文档,而模式字符串往往由用户来指定,高效的字符串匹配 算法可以提高程序的响应性能,当然字符串匹配算法的应用远远不止于此,例如在生物计算科学中查找特定的DNA序列,也是字符串匹配算法...
首先对三种基本字符串匹配算法进行了详细分析和说明,再编程实现。创新拓展研究了Boyer-Moore算法,进行了分析和编程实现。让四种算法对数据量极大的文本,进行子串的查询处理,并分析算法运行时间效率,并对所有...
KMP算法,全称为Knuth-Morris-Pratt算法,是一种高效的字符串匹配算法,由Donald Knuth、James H. Morris和 Vaughan Pratt三位学者在1970年代提出。该算法在处理字符串匹配问题时,避免了不必要的回溯,极大地提高了...
本文将介绍一种名为KMP的字符串匹配算法。KMP算法(Knuth-Morris-Pratt算法)是一种高效的字符串匹配算法,由Donald Knuth、Vaughan Pratt和James H. Morris共同发明。KMP算法通过使用一个称为“部分匹配表”或...
### 字符串匹配算法之BNDM:结合位并行与后缀自动机的高效灵活匹配 在计算机科学领域,字符串匹配算法是处理文本搜索、数据挖掘和生物信息学等应用中的关键工具。《字符串匹配算法之BNDM》一文深入探讨了一种创新的...
本文将介绍一种名为KMP的字符串匹配算法。KMP算法(Knuth-Morris-Pratt算法)是一种高效的字符串匹配算法,由Donald Knuth、Vaughan Pratt和James H. Morris共同发明。KMP算法通过使用一个称为“部分匹配表”或...
### 一种改进的字符串匹配算法:KMP算法详解 #### KMP算法简介 KMP算法是一种高效的字符串匹配算法,由D.E.Knuth、V.R.Pratt和J.H.Morris三位计算机科学家共同发现,因此得名为Knuth-Morris-Pratt算法(简称KMP...
### 字符串匹配算法概述 在计算机科学领域中,字符串匹配是一种常见的操作,它涉及到在一个较大的文本串(T)中查找一个较短的模式串(P)。本章节将重点介绍字符串匹配的基本概念以及两种重要的算法——简单字符串...