NFA与DFA工作的区别,dfa与nfa的基本概念及其区别

http://www.itjxue.com  2023-01-16 17:35  来源:未知  点击次数: 

dfa和nfa的区别

基本概念:

确定有限自动机(Deterministic Finite Automaton) 简称DFA。dfa是匹配速度,是确定的。

非确定有限自动机(Nondeterministic Finite Automaton) 简称NFA,nfa是匹配结果,是不确定的。

区别:

DFA比较快,但不提供Backtrack(回溯)功能,NFA比较慢,但提供了Backtrack功能。

NFA是基于表达式的(Regex-Directed),而DFA是基于文本的(Text-Directed)。

DFA引擎在任意时刻必定处于某个确定的状态,而NFA引擎可能处于一组状态之中的任何一个,所以,NFA引擎必须记录所有的可能路径(trace multiple possible routes through the NFA),NFA之所以能够提供Backtrack的功能,原因就在这里。 扩展资料 一个程序要转换成词法分析器,词法分析器的任务就是将字符流转换成词法记号流,转换的核心在于有穷自动机的表示方法,有穷自动机与状态转换图有点相似,但它不是图,而是一个识别器,它对每个输入的'字符做识别和判断,以确定其能到达的最终状态或状态集和路径,有穷自动机分为两类,即不确定的有穷自动机NFA和确定的有穷自动机DFA。

简述什么是DFA和NFA的区别求大神帮助

一个是匹配速度。DFA快一些 一个是匹配结果。DFA 是确定的。。而NFA 是不确定的

算法设计-帮帮忙

这个估计要用文件输入

否则太累了

--我们必须尽量优化程序才能达到题目的要求。显然n实在是太大了,所以我们不但不可能忍受O(n2)的复杂度,甚至连n前面的系数过大都会造成超时。为了尽量减小时间复杂度,我们只能依靠自动机的理论。

自动机理论

一个DFA(确定性有限自动机)是一个五元组∑, U, s, T, φ,其中∑是字符集U 是一个有限的状态集合, s 是 U 的一个元素表示初始状态, T 是 U的一个子集,表示终止状态and φ : U × ∑ → U 是转移函数。

开始时自动机在初始状态s,每步它读入一个字符c,然后根据state=φ(state,c)进行状态的转移。如果当字符串结束时它达到了终止状态,那么就说它接受了字符串。

NFA(非确定性自动机)与DFA的主要区别就是,NFA从一个状态按照一个字符转移到的状态可能有多个。因此NFA需要使用一个状态集合来表示当前可能处在的状态。

把自动机用图来表示的话,一般用结点表示状态,而结点之间有标有某个字符的有向边,表示可以从边的起点通过这个字符转移到边的终点。

此外NFA还可以包含标有ε的边,这种边表示不需要任何字符就可以直接进行状态的转移。

容易想到,如果我们建立了一个只接受符合正则表达式的自动机,就可以通过它来较快的判断哪些位置是可匹配的。

具体应用

比较常见的字符串匹配自动机大多都是DFA。但是由于有+,*,把正则表达式直接转变成DFA是非常困难的。因此我们只能先把它转化成NFA。

先看一下一般的转换规则:

如果正则表达式是一个字符,那么对应的NFA是:

p0-a-p1

如果正则表达式是A+B的形式,那么只要把它们的起始状态和终止状态合并就可以:

p0-a-p1

p0-b-p1

如果正则表达式是AB的形式,那么只要把A和B对应的自动机首尾相接:

p0-a-p1-b-p2

如果正则表达式是A*的形式,那么就需要按下面的图来进行处理:

p0-a-p0

p0-p1

通过上面的步骤可以得出:NFA的状态数不会超过正则表达式长度。

NFA中的状态转移

在NFA中进行状态转移比DFA要困难一些。我们可以定义两个函数,一个叫做epsilon-closure,用来计算一组NFA状态通过epsilon边能够到达的NFA状态集合。另外一个move用来在NFA上进行状态的转移。

设当前的状态集合是now,那么状态转移的过程就是:

new = {}

for every state s in now do

new = new ∪ {t | (s,t) = c}

new = epsilon_closure(new)

其中的(s,t)=c表示从s状态经过一个字符c可以转化到t状态。因为这个语句需要的集合总数也不会太多,所以可以通过预先计算出它们来加快速度。预处理后这个过程的复杂度是O(m2),而系数是比较小的。

但是由于在NFA中,我们必须把状态的集合作为一个真正的状态,每次状态转移都是对这个集合的处理。这样转移一次的复杂度是O(m2),这是不可忍受的(最大的数据需要大约2分钟才能出解)。

既然NFA速度过慢,我们自然想要把它转化为DFA。因为DFA中的状态转移是O(1)的。可是并没有一个多项式复杂度的方法可以把NFA转换成DFA。一般介绍的NFA转换到DFA的方法都是通过类似BFS的方法来把NFA中所有可能出现的状态集合对应成DFA的一个状态。

这种转换在本题中显然是不可行的,因为NFA的结点数最多是500,而转化成的DFA则可能有多达2500个状态,即使实际有许多状态不能达到,也是无论如何不可以忍受的。

看来把NFA转换成DFA是行不通的。但是我们还是从NFA转DFA的过程中受到了一些启发:NFA之所以速度慢,是因为我们在进行状态转移的时候可能进行许多重复操作:比如从{1,2}沿一个字符1转移后是{2,3},以后我们还可能遇到相同的情况,而这时我们还会用O(m2)的时间去进行状态转移。这是一种很严重的浪费。因此我们每进行一次状态转移,就把这个状态转移的情况放到hash表中,以后使用的时候就可以查找了。这相当于只把我们需要的一部分子集转移成DFA,虽然一般情况下并不能降低时间复杂度,但是在实际应用中确实很有效。(特别是对于没有*和括号的自动机,这样做可以保证线形的时间复杂度)

算法回顾和细节

我们重新来看一下算法的框架:

根据正则表达式建立NFA

now = start

while not eof do begin

read(c);

if 曾经进行过now,c的转移 then 利用以前的结果

else 进行状态转移并记录结果

if 终止状态 in now then 输出当前位置

end

建立NFA有各种方法,由于NFA并不会很大,所以我们可以使用递归的方法来实现。为了尽量减小系数,我们使用位压缩的方式来实现集合,并采用较为简化的hash函数(比如把一个集合位压缩后的一系列整数加起来取对220的余数),并在输入和输出的时候通过缓冲区来加快速度。这样就基本可以达到题目的时间要求。

但是注意到字符串可能有10M,而产生的NFA的状态集合最多也可能有10M个,而每个集合都需要100到200字节的存储空间,大大超出了允许的空间范围。因此我们需要对hash表的规模加以严格限制。如果规模过大就不得不放弃存储状态的想法,牺牲一定的时间来换取空间。

dfa与nfa有何区别

一个是匹配速度。DFA快一些

一个是匹配结果。DFA 是确定的。。而NFA 是不确定的

(责任编辑:IT教学网)

更多

推荐Discuz!建站文章