保留版权,转载需注明出处(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. wiki oi 3116 高精度练习之加法

    题目描述 Description 给出两个正整数A和B,计算A+B的值.保证A和B的位数不超过500位. 输入描述 Input Description 读入两个用空格隔开的正整数 输出描述 Outpu ...

  2. 解析LayoutSubviews

    layoutSubviews作用 layoutSubviews是对subviews重新布局.比如,我们想更新子视图的位置的时候,可以通过调用layoutSubviews方法,既可以实现对子视图重新布局 ...

  3. C#_会员管理系统:开发五(用户注册)

    创建一个新的用户注册窗体(VIPRegistration.cs): 用户注册窗体(VIPRegistration.cs)详细代码如下: using System; using System.Colle ...

  4. BZOJ 3236: [Ahoi2013]作业( 莫队 + BIT )

    莫队..用两个树状数组计算.时间复杂度应该是O(N1.5logN). 估计我是写残了...跑得很慢... ----------------------------------------------- ...

  5. ZOJ 3879 Capture the Flag 15年浙江省赛K题

    每年省赛必有的一道模拟题,描述都是非常的长,题目都是蛮好写的... sigh... 比赛的时候没有写出这道题目 :( 题意:首先输入4个数,n,q,p,c代表有n个队伍,q个服务器,每支队伍的初始分数 ...

  6. 如何用vs查看结构体布局

    今天遇到一个问题: 假设在每个系统的structA 结构不同,我们在windbg看了以后直接拿来用,自己定义成结构体,如何来验证这个结构体内存布局是否和windbg一致. 当然笨办法是自己一个个成员数 ...

  7. ASP.NET MVC 5 学习教程:添加模型

    原文 ASP.NET MVC 5 学习教程:添加模型 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 通过控 ...

  8. Python 2.7 学习笔记 列表的使用

    同其它编程语言一样,python也提供了丰富的数据结构,以方便数据的处理.本文介绍两种最基本的数据集合,列表和元组的使用. 一.列表使用介绍 可以理解为一个有序的序列.其使用方式举例如下: list= ...

  9. MySQL中关于日期、时间的数据类型和函数

    一.日期相关的数据类型 1.datetime 占用8字节,既显示了日期,又显示了时间.其表示的日期范围为“1000-01-01 00:00:00”到“9999-12-31 23:59:59” 2.da ...

  10. UVALive 3989 Ladies&#39; Choice

    经典的稳定婚姻匹配问题 UVALive - 3989 Ladies' Choice Time Limit: 6000MS Memory Limit: Unknown 64bit IO Format:  ...