• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2020-10-13 08:22 Aet 隐藏边栏 |   抢沙发  5 
文章评分 1 次,平均分 5.0

定义

假设文本是一个长度为n的数组 T[1...n],而模式是一个长度为m的数组P[1...m],其中m<=n。进一步假设P和T的元素都是来自一个有限字母集合M的字符。如M={0,1}或者M={a,b,c,...z}
字符数组P和T通常称为字符串。

原理

有限自动机

定义有限自动机 AM 是一个5元组(Q,q_0,A,M,delt),其中:

  • Q:为状态的有限集合
  • q_0属于Q:为初始状态
  • AQ的子集:表示一个特殊的接受状态集合
  • M:是有限的输入字母表
  • delt:为 Q*M--> Q 的函数,称为有限自动机的转移函数

有限自动机开始于状态 q_0,每次读入输入字符串的一个字符。如果有限自动机在状态q时读入了字符a,则它从状态q变成了状态 delt(q,a),进行了一次转移。每当当前状态q属于A时,则说明状态机接受了迄今为止所读入的字符串。

有限自动机引入了一个函数 phai,称为终态函数。定义 M* 表示所有的有限长度的字符串的集合,该字符串是由所有字母表M中的字符组成。
长度为0的空字符串记为e,e属于M*. phai 是从 M*Q的函数,满足: pai(w)是有限自动机扫描字符串w后的终止状态。

其中 w 属于 M*。因此当且仅当 phai(w)属于A时,有限自动机接受字符串 w。我们可以用转移函数定义 phai:

  • phai(e)=q_0
  • phai(wa)=delt(phai(w),a), w属于M*,a属于M

字符串匹配自动机

对于一个给定的模式P,我们可以在预处理阶段构造出一个字符串匹配自动机,根据模式构造出的自动机后,再利用它来搜寻文本字符串。

首先定义一个辅助函数 sigma,称之为P的后缀函数。函数 sigma是一个 M*{0,1,....m}上的映射:

  • sigma(x)=max{k:P_k是x的后缀},即sigma(x)x的后缀中,P的最长前缀的长度。

因为空字符串P0=e是每一个字符串的后缀,因此sigma(e)=0。对于一个长度为m的模式Psigma(x)=m当且仅当Px的后缀。

给定模式P[1...m],其相应的字符串匹配自动机定义如下:

  • 状态集合Q{0,1,...m}。开始状态q_00状态,并且只有状态m是唯一被接受的状态
  • 对任意状态q和字符a,转移函数 delt定义为: delt(q,a)=sigma(Pq a)

考虑最近一次扫描T的字符。为了使得T的一个子串(以T[i]结尾的子串)能够和P的某些前缀Pj匹配,则前缀Pj必须是Ti的一个后缀。
假设q=phai(Ti),则读完Ti之后,自动机处于状态q。转移函数delt使用状态数q表示P的前缀和Ti后缀的最长匹配长度。也就是说,
在状态q时, PqTi的后缀,且q=sigma(Ti)

步骤

预处理算法(构造delt函数)

  • 遍历Pq0m (因为q=0时,P_0=空字符串):
    • 对每个字符a属于有限字母集合a,寻找Pk是 (Pq a) 后缀的最大的k,则 delt(q,a)=k
  • 返回 delt

匹配算法

  • 遍历Ti1n
    • 计算 q=delt(q,T[i])。如果 q==m,则偏移 i-m是有效偏移点,将 i-m 加入结果std::vector

性能

有限自动机字符串匹配算法的预处理时间为O(m^3 |M|),其中M 为有限字母集合的大小
匹配时间为O(n)

实现

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0 最后编辑于:2021-11-20
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享