保留版权,转载需注明出处(http://blog.csdn.net/panjunbiao)。

非确定有限状态自动机(Nondeterministic Finite Automata,NFA)由以下元素组成:

  1. 一个有限的状态集合S
  2. 一个输入符号集合Sigma,并且架设空字符epsilon不属于Sigma
  3. 一个状态迁移函数,对于所给的每一个状态和每一个属于Sigma或{epsilon}的符号,输出迁移状态的集合。
  4. 一个S中的状态s0作为开始状态(初始状态)
  5. S的一个子集F,作为接受状态(结束状态)
例如,我们给定:
  1. S={s0, s1, s2, s3, s4}
  2. Sigma={a, b}
  3. 状态迁移函数T,且T(s0, a} = {s1}, T(s1, a) = {s2}, T(s2, b) = {s3}, T(s3, b) = {s4}
  4. s0为开始状态
  5. {s4}为接受状态
这样我们就得到一个很简单的NFA,它可以用图来表示,如下图图1:


NFA是一个识别器,例如图1所示的NFA,我们从状态s0开始,按顺序输入aabb,在输入第一个符号a之后,状态将从s0迁移到s1,输入第二个符号a之后,状态迁移到s2,输入第三个符号b之后,状态迁移到s3,输入第四个符号b之后,状态迁移到s4,而s4是接收状态,也就是说对我们刚才输入的aabb字符串说yes,表明本NFA识别了所输入的字符串。
所谓非确定,是指在某个状态输入同一个符号,状态可以迁移到不同的下一个状态,例如图2,在s0处输入字符a,状态既可以迁移为s1,也可以迁移为s3,准确的说是状态迁移到了{s1,s3},因此图2所示的NFA能够接受的字符串包括aa和ab。
另外,NFA的特点还在于空符号也能进行状态迁移,例如图3的s0,不需要任何输入字符就可以迁移到s1,因此图3的NFA可以识别的语言为*a*b,即0到任意多个a,接着0到任意多个b。

NFA可以识别的语言与正则表达式所表达的语言是等价的,参考
http://en.wikipedia.org/wiki/Nondeterministic_finite_automaton
那么,NFA如何实现呢?我们先来看看NFA状态节点的一种实现:
/*
This file is one of the component a Context-free Grammar Parser Generator,
which accept a piece of text as the input, and generates a parser
for the inputted context-free grammar.
Copyright (C) 2013, Junbiao Pan (Email: panjunbiao@gmail.com) This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ package automata; import java.util.*; public class NFAState implements Comparable<NFAState> {
private static int COUNT = 0; //状态标识,每个NFA状态节点都有唯一的数值标识
private int id; public int getId() { return this.id; } //在创建NFA状态对象的时候,通过静态变量生成唯一标识
public NFAState() {
this.id = COUNT ++;
} //迁移函数,由于迁移函数需要两个输入:当前状态和输入符号,因此在一个状态对象内部,
//迁移函数都是针对本对象的,只需要输入符号就可以了,这里通过Map接口实现迁移函数
protected Map<Integer, Set<NFAState>> transition = new HashMap<Integer, Set<NFAState>>();
public Map<Integer, Set<NFAState>> getTransition() { return this.transition; } //空字符迁移函数,即从当前节点经过空字符输入所能够到达的下一个状态节点
protected Set<NFAState> epsilonTransition = new HashSet<NFAState>();
public Set<NFAState> getEpsilonTransition() { return this.epsilonTransition; } //向迁移函数添加一个映射,不给定下一个状态节点
public NFAState addTransit(int input) {
return addTransit(input, new NFAState());
} //向迁移函数添加一个映射,给定下一个状态节点
public NFAState addTransit(int input, NFAState next) {
Set<NFAState> states = this.transition.get(input);
if (states == null) {
states = new HashSet<NFAState>();
this.transition.put(input, states);
}
states.add(next);
return next;
} //向迁移函数添加一个映射,不给定下一个状态节点
public NFAState addTransit(char input) {
return addTransit(input, new NFAState());
} //向迁移函数添加一个映射,给定下一个状态节点
//假定我们的上下文无关文法是大小写不敏感的,当输入字符是char类型并且是字母时,
//生成大写字母和小写字母两个映射
public NFAState addTransit(char input, NFAState next) {
if (Character.isLetter(input)) {
this.addTransit((int) (Character.toUpperCase(input)), next);
this.addTransit((int)(Character.toLowerCase(input)), next);
return next;
}
this.addTransit((int)input, next);
return next;
} //添加一个空字符的映射
public NFAState addTransit(NFAState next) {
this.epsilonTransition.add(next);
return next;
} //返回迁移函数
public Set<NFAState> getTransition(int input) {
return this.transition.get(input);
} }

再来看看NFA的实现:

/*
This file is one of the component a Context-free Grammar Parser Generator,
which accept a piece of text as the input, and generates a parser
for the inputted context-free grammar.
Copyright (C) 2013, Junbiao Pan (Email: panjunbiao@gmail.com) This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ package automata; import java.util.*; import abnf.CharVal;
import abnf.NumVal;
import abnf.AbnfParser;
import abnf.RangedNumVal;
import abnf.Repeat;
import abnf.Repetition;
import abnf.Rule;
import abnf.RuleName; public class NFA {
//开始状态startState
private NFAState startState = null;
public NFAState getStartState() { return startState; } //接收状态acceptingStates
private Set<NFAState> acceptingStates = new HashSet<NFAState>();
public Set<NFAState> getAcceptingStates() { return acceptingStates; }
public boolean accept(NFAState state) {
return this.acceptingStates.contains(state);
}
public void addAcceptingState(NFAState state) {
this.acceptingStates.add(state);
} public NFA() {
this(new NFAState(), new NFAState());
} public NFA(NFAState startState) {
this(startState, new NFAState());
} public NFA(NFAState startState, NFAState acceptingState) {
this.startState = startState;
this.addAcceptingState(acceptingState);
} //在上面的NFAState类实现中,新的状态节点是在添加迁移映射的过程中生成的,
//这个过程中NFA并没有介入,因此NFA类不能直接得到状态集S的成员
//而是需要从状态startState开始,不断迭代找出所有的状态节点
protected void getStateSet(NFAState current, Set<NFAState> states) {
if (states.contains(current)) return;
states.add(current); Iterator<NFAState> it; it = current.getNextStates().iterator();
while (it.hasNext()) {
this.getStateSet(it.next(), states);
} it = current.getEpsilonTransition().iterator();
while (it.hasNext()) {
this.getStateSet(it.next(), states);
} } public Set<NFAState> getStateSet() {
Set<NFAState> states = new HashSet<NFAState>();
this.getStateSet(this.getStartState(), states);
return states;
} }

这样,我们可以从NFA类中获得一个NFA的开始状态startState和接受状态集合acceptingStates,在每一个状态节点NFAState中可以获得状态迁移函数,因此NFA所定义的各个元素都实现了。


非确定有限状态自动机的构建(一)——NFA的定义和实现的更多相关文章

  1. 非确定有限状态自动机的构建(二)——将CharVal转换为NFA

    保留版权,转载注明出处:潘军彪的个人博客(http://blog.csdn.net/panjunbiao/article/details/9378933) 将上下文无关文法读入内存之后,可以将它转换成 ...

  2. K:有限状态自动机

      有限状态自动机是一种特殊的状态机.它表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.有限状态自动机分为两种,一种是 确定有限状态自动机(DFA) ,一种是 非确定有限状态自动机(NF ...

  3. <轻量算法>根据核密度估计检测波峰算法 ---基于有限状态自动机和递归实现

    原创博客,转载请联系博主! 希望我思考问题的思路,也可以给大家一些启发或者反思! 问题背景: 现在我们的手上有一组没有明确规律,但是分布有明显聚簇现象的样本点,如下图所示: 图中数据集是显然是个3维的 ...

  4. Trie 前缀树或字典树 确定有限状态自动机

    https://zh.wikipedia.org/wiki/Trie 应用 trie树常用于搜索提示.如当输入一个网址,可以自动搜索出可能的选择.当没有完全匹配的搜索结果,可以返回前缀最相似的可能.[ ...

  5. 简聊DFA(确定性有限状态自动机)

    状态机理论最初的发展在数字电路设计领域.而在软件设计领域,状态机设计的理论俨然已经自成一体. 状态机是软件编程中的一个重要概念,比这个概念更重要的是对它的灵活应用.在一个思路清晰而且高效的程序中,必然 ...

  6. 用C语言实现有限状态自动机FSM

    摘要:状态机模式是一种行为模式,在<设计模式>这本书中对其有详细的描述,通过多态实现不同状态的调转行为的确是一种很好的方法,只可惜在嵌入式环境下,有时只能写纯C代码,并且还需要考虑代码的重 ...

  7. DFA确定有限状态自动机

    DFA 在计算理论中,确定有限状态自动机或确定有限自动机(英语:deterministic finite automaton, DFA)是一个能实现状态转移的自动机.对于一个给定的属于该自动机的状态和 ...

  8. 【Codeforces 506E】Mr.Kitayuta’s Gift&&【BZOJ 4214】黄昏下的礼物 dp转有限状态自动机+矩阵乘法优化

    神题……胡乱讲述一下思维过程……首先,读懂题.然后,转化问题为构造一个长度为|T|+n的字符串,使其内含有T这个子序列.之后,想到一个简单的dp.由于是回文串,我们就增量构造半个回文串,设f(i,j, ...

  9. 51NOD 1292 1277(KMP算法,字符串中的有限状态自动机)

    在前两天的CCPC网络赛中...被一发KMP题卡了住了...遂决定,哪里跌倒就在哪里爬起来...把个KMP恶补一发,连带着把AC自动机什么的也整上. 首先,介绍设定:KMP算法计划解决的基本问题是,两 ...

随机推荐

  1. php 用户访问菜单页面,必须登录,判断用户是否登录

    <pre name="code" class="python"># 本节课大纲: 一.空模块和空操作 1.空操作 function _empty($ ...

  2. 宣布正式发布 Biz Talk Services、Azure Active Directory 和 Traffic Manager, 同时发布 Azure Active Directory 高级版预览

    除经济优势之外,云计算还在可转化为竞争优势的应用程序开发方面提供了更大的灵活性.我们很高兴看到每天创建的新 Windows Azure 订阅超过 1000 个,更令人兴奋的是,有一半客户使用价值更高的 ...

  3. 用C语言写一个程序,得出当前系统的整形数字长(16位,32位,64位)等,不能使用sizeof()

    #include <iostream>#include <cmath>using namespace std; int main(){ int num = -1; unsign ...

  4. 首届全球RTB(实时竞价)广告DSP算法大赛

    首届全球RTB(实时竞价)广告DSP算法大赛 竞赛指南     RTB (Real Time Bidding, 实时竞价) 是近年来计算广告领域最激动人心的进展之一. 它增加了展示广告的透明度与效率, ...

  5. Oracle Licensing

    Oracle根据什么来计算License的? Unlimited License Agreements Unlimited License Agreements通常简称ULA,表示在一个固定期限内(2 ...

  6. iOS 开发 Message Digest Algorithm 5(MD5加密)

    MD5的全称是Message Digest Algorithm 5(消息摘要算法第五版),是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.在90年代初由MIT Laboratory ...

  7. 递推,大数存储E - Order Count

    Description If we connect 3 numbers with "<" and "=", there are 13 cases: 1) ...

  8. Week7(10月21日)

    Part I:提问  =========================== 1.请为下图编写视图代码,视图中表单提交后,交给当前控制器和动作处理. 2.如何实现点击列标题排序功能? 3.分页时采用了 ...

  9. 有什么很好的软件是用 Qt 编写的?

    作者:尘中远链接:http://www.zhihu.com/question/19630324/answer/19365369来源:知乎 一些出名的例子如下:(wiki搬运) 3DSlicer, a ...

  10. Scriptcase在线试用开发环境

    现在,你可以通过浏览器在线试用的方式,体验Scriptcase的高效快速开发方式. 只需要有上网环境就可以使用: 兼容几乎所有的浏览器(IE.Firefox.Chrome.Opera……): 客户端无 ...