//将正规式转变成NFA
package hjzgg.formal_ceremony_to_dfa; import java.util.ArrayList; class Edge{
public int u, v;
public char key;
public Edge(int u, int v, char key) {
super();
this.u = u;
this.v = v;
this.key = key;
}
@Override
public String toString() {
return u + "->" + v + " " + key;
} @Override
public boolean equals(Object arg0) {
Edge tmp = (Edge)arg0;
return tmp.u==this.u && tmp.v==this.v && tmp.key==this.key;
}
@Override
public int hashCode() {
return u+v+key;
}
} class NFA{
public static final int MAX_NODE = ;
private boolean finalState[] = new boolean[MAX_NODE];//记录每一个节点是否为终态
private String formal_ceremony;//正规式字符串
private int cnt_node=;//记录节点的个数
private Map<Integer, Integer> endNode = new TreeMap<Integer, Integer>();//每一个开始节点对应的终端节点
private ArrayList<Edge> nodeAl = new ArrayList<Edge>();
private Vector<Pair>[] g = new Vector[MAX_NODE];//NFA图
private Set<Character> st = new TreeSet<Character>();//正规式中出现的字符的集合
public NFA(String formal_ceremony) {
super();
this.formal_ceremony = formal_ceremony;
} private void addEdge(int u, int v, char ch){
nodeAl.add(new Edge(u, v, ch));
if(g[u] == null)
g[u] = new Vector<Pair>();
g[u].add(new Pair(v, ch));
if(ch!='$')
st.add(ch);
} public boolean kernel_way(int fa, int ld, int rd, boolean isClosure){//fa表示区间的开始点,正规式的区间[ld, rd], isClosure表示这段区间查是否存在闭包
if(ld < || rd >= formal_ceremony.length()){
System.out.println("正规式不正确---发生数组越界!");
return false;
}
int pre_node = fa;
int inBracket = ;//判断'|'是否在括弧内
for(int i=ld; i<=rd; ++i){
if(formal_ceremony.charAt(i)=='(') ++inBracket;
else if(formal_ceremony.charAt(i)==')') --inBracket;
else if(formal_ceremony.charAt(i)=='|' && ==inBracket){
if(!kernel_way(fa, ld, i-, isClosure)) return false;
if(!kernel_way(fa, i+, rd, isClosure)) return false;
return true;
}
}
for(int i=ld; i<=rd; ++i){
if(formal_ceremony.charAt(i)=='('){//又是一个子区间
//寻找和 该 '('相匹配的')'
int cntLeftBracket = ;//统计遍历过程中'('出现的次数,遇到')'减去1
int posRightBracket = -;//记录相匹配的')'的位置
int posLeftBracket = i;
for(int j=i+; j<=rd; ++j){
if(formal_ceremony.charAt(j)=='(')
++cntLeftBracket;
else if(formal_ceremony.charAt(j)==')'){
if(cntLeftBracket == ){
posRightBracket = j;
break;
}
--cntLeftBracket;
}
}
if(posRightBracket == -){//出错
System.out.println("正规式出错----括弧不匹配!");
return false;
}
int nodeFather = ;//括弧内正则式的开始节点
if(posRightBracket+ <= rd && formal_ceremony.charAt(posRightBracket+)=='*'){
i = posRightBracket+;//过滤掉"()*"
addEdge(pre_node, ++cnt_node, '$');//表示这一条边为空
pre_node = cnt_node;
nodeFather = cnt_node;
addEdge(pre_node, ++cnt_node, '$');//表示这一条边为空
pre_node = cnt_node;
//处理()*括弧内的正规式
if(!kernel_way(nodeFather, posLeftBracket+, posRightBracket-, true)) return false;
} else {
nodeFather = pre_node;
if(!kernel_way(nodeFather, posLeftBracket+, posRightBracket-, false))//对于"(101)", 看成101
return false;
i = posRightBracket;
} } else {//单个字符
if(formal_ceremony.charAt(i)==')') continue;
if(i+ <= rd && formal_ceremony.charAt(i+)=='*'){
addEdge(pre_node, ++cnt_node, '$');//表示这一条边为空
pre_node = cnt_node;
addEdge(pre_node, pre_node, formal_ceremony.charAt(i));
if(i+==rd && isClosure)
addEdge(pre_node, fa, '$');//表示这一条边为空并且是连接到父亲节点
else{
if(endNode.containsKey(fa))
addEdge(pre_node, endNode.get(fa), '$');
else{
addEdge(pre_node, ++cnt_node, '$');//表示这一条边为空
if(i==rd) endNode.put(fa, cnt_node);//记录非闭包状态下 第一个节点对应的最后一个节点
}
}
pre_node = cnt_node;
++i;//过滤*
} else {
if(i==rd && isClosure){//是闭包的情况
addEdge(pre_node, fa, formal_ceremony.charAt(i));
} else{
if(endNode.containsKey(fa))
addEdge(pre_node, endNode.get(fa), formal_ceremony.charAt(i));
else{
addEdge(pre_node, ++cnt_node, formal_ceremony.charAt(i));
if(i==rd) endNode.put(fa, cnt_node);//记录非闭包状态下 第一个节点对应的最后一个节点
}
}
pre_node = cnt_node;
}
}
}
return true;
} private void checkFinalState(){//检查哪一个节点是终态
for(int i=; i<=cnt_node; ++i){
int cc = ;
if(g[i] == null){//表明是终态
finalState[i] = true;
continue;
}
for(int j=; j<g[i].size(); ++j)
if(g[i].elementAt(j).v != i)
++cc;
if(cc == )//表明是终态
finalState[i] = true;
}
} public boolean[] getFinalState(){
return finalState;
} public Vector<Pair>[] getNFAGraphics(){
if(kernel_way(, , formal_ceremony.length()-, false)){
// for(Edge e : nodeAl)//打印NFA
// System.out.println(e);
checkFinalState();
return g;
}
return null;
} public Set<Character> getCharacterSet(){
return st;
} public void outputNFA(){
if(kernel_way(, , formal_ceremony.length()-, false)){
checkFinalState();
for(Edge e : nodeAl)
System.out.println(e);
}
}
} /*
* 将正规式转换成NFA
* */
public class ToNFA { public static void main(String[] args){
String formal_ceremony = "0*(100*)*0*";
// String formal_ceremony = "1(1010*|1(010)*1)*0";
// String formal_ceremony = "1(0|1)*101";
// String formal_ceremony = "0*1*(010)0*1*";
// String formal_ceremony = "(0|1|2)*";
// String formal_ceremony = "0|1";
// String formal_ceremony = "0|1|2|3";
// String formal_ceremony = "(0|1|6)|(2|3)|(4|5)";
// String formal_ceremony = "(0|1)*|(2|3)*";
// String formal_ceremony = "((10)|(01)*|(0|1))";
NFA nfa = new NFA(formal_ceremony);
nfa.outputNFA();
}
}
//将NFA转变成确定化DFA
package hjzgg.formal_ceremony_to_dfa; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Vector; class Pair {
public int v;
public char ch;
public Pair(int v, char ch) {
super();
this.v = v;
this.ch = ch;
} } class MyHashSet extends HashSet<Integer>{//重写 set 集合的 hashcode()和equals()方法
private int state;
public void setState(int state){
this.state = state;
}
public int getState(){
return state;
}
@Override
public boolean equals(Object arg0) {
MyHashSet tmp = (MyHashSet)arg0;
if(tmp.size() != this.size()) return false;
Iterator<Integer> it = this.iterator();
while(it.hasNext()){
if(!tmp.contains(it.next())) return false;
}
return true;
} @Override
public int hashCode() {
int sum = ;
Iterator<Integer> it = this.iterator();
while(it.hasNext())
sum += (((java.lang.Integer)it.next()).intValue());
return sum;
}
} class DefinedNFA{
private int dfaNode = ;//defined DFA节点的个数
private boolean[] finalState = null;//表示NFA中哪一个节点是终态
private boolean[] newFinalState = new boolean[NFA.MAX_NODE] ;
private Vector<Pair>[] g = null;//NFA 图
private Set<Edge>edgeSet = new HashSet<Edge>(); //标记图中的边是否被访问过
private MyHashSet st = null; //集合,表示每一个子集状态
private Queue<MyHashSet> queue = new LinkedList<MyHashSet>();//存放要执行的子集状态
private Set<MyHashSet> sst = new HashSet<MyHashSet>();
private Set<Character> characterSet = null;//正规式中的字符的集合
private ArrayList<Edge> nodeAl = new ArrayList<Edge>();//NFA边的集合
public DefinedNFA(Vector<Pair>[] g, Set<Character> characterSet, boolean[] finalState) {
super();
this.g = g;
this.characterSet = characterSet;
this.finalState = finalState;
} public Set<Character> getCharacterSet(){
return characterSet;
}
public int getDfaNode(){
return dfaNode;
}
public boolean[] getNewFinalState(){
return newFinalState;
}
public ArrayList<Edge> getNodeAl(){
return nodeAl;
}
private void dfs(int u, char ch){
if(g[u]==null) return ;
int len = g[u].size();
for(int i=; i<len; ++i){
Pair pair = g[u].elementAt(i);
Edge edge = new Edge(u, pair.v, pair.ch);
if(!edgeSet.contains(edge) && pair.ch==ch){
edgeSet.add(edge);
st.add(pair.v);
dfs(pair.v, '$');
}
} } public void checkIsFinalState(Set<Integer> st, int state){
Iterator<Integer> it = st.iterator();
while(it.hasNext()){
int val = it.next();
if(finalState[val])
newFinalState[state] = true;
}
} private void initFirstSet(){
edgeSet.clear();
st = new MyHashSet();
st.add();
st.setState(++dfaNode);
dfs(, '$');
checkIsFinalState(st, dfaNode);
sst.add(st);
queue.add(st);
}
private void addEdge(int u, int v, char ch){
nodeAl.add(new Edge(u, v, ch));
} public void ToStateMatrix(){
initFirstSet();
while(!queue.isEmpty()){
MyHashSet myset = queue.poll();
for(Character ch : characterSet){
st = new MyHashSet();
for(Integer i : myset){
edgeSet.clear();
dfs(i, ch);
}
if(st.size()>){
if(!sst.contains(st)){
sst.add(st);
queue.add(st);
st.setState(++dfaNode);
checkIsFinalState(st, dfaNode);
} else {
Iterator<MyHashSet> it = sst.iterator();
while(it.hasNext()){
MyHashSet tmp = it.next();
if(tmp.equals(st)){
st = tmp;
break;
}
}
}
addEdge(myset.getState(), st.getState(), ch);
}
}
}
} public void outputDFA(){
ToStateMatrix();//有状态转换矩阵得到defined NFA
for(Edge e : nodeAl)
System.out.println(e);
} } public class ToDefinedDFA { public static void main(String[] args) {
// String formal_ceremony = "((10)|(01)*|(0|1))";
// String formal_ceremony = "(0|1|6)|(2|3)|(4|5)";
// String formal_ceremony = "1(0|1)*101";
String formal_ceremony = "0*(100*)*0*";
NFA nfa = new NFA(formal_ceremony);
DefinedNFA definedDFA = new DefinedNFA(nfa.getNFAGraphics(), nfa.getCharacterSet(), nfa.getFinalState());
definedDFA.outputDFA();
} }
//将确定化DFA最小化
package hjzgg.formal_ceremony_to_dfa; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; class MinimumDFA{
private boolean[] newFinalState = null;//由确定化DFA得到
private ArrayList<Edge> nodeAl = null;//由确定化DFA得到
private int dfaNode;//确定化DFA节点的个数
private Set<Character> characterSet = null;//正规式中的字符的集合
private ArrayList<Set<Integer>> setList = new ArrayList<Set<Integer>>();
public MinimumDFA(boolean[] newFinalState, ArrayList<Edge> nodeAl, int dfaNode, Set<Character> characterSet) {
super();
this.newFinalState = newFinalState;
this.nodeAl = nodeAl;
this.dfaNode = dfaNode;
this.characterSet = characterSet;
}
private void init(){//利用分割法将集合分成终态和非终态
Set<Integer> finalStateSet = new HashSet<Integer>();
Set<Integer> NofinalStateSet = new HashSet<Integer>();
for(int i=; i<=dfaNode; ++i)
if(newFinalState[i])//终态
finalStateSet.add(i);
else
NofinalStateSet.add(i);
setList.add(finalStateSet);
setList.add(NofinalStateSet);
} public void toMinimumDfa(){
init();
boolean flag = true;
ArrayList<Set<Integer>> tmpSetList = new ArrayList<Set<Integer>>();
while(flag){
flag = false;
hjzgg:
for(int k=; k<setList.size(); ++k){
Set<Integer> st = setList.get(k);
if(st.size()<=) continue;
for(Character ch : characterSet){
Map<Integer, Integer> mp = new HashMap<Integer, Integer>();
for(int i=; i<nodeAl.size(); ++i){//st集合(也就是map的val值)在 ch这个点对应的集合 {st}a = {...}
Edge edge = nodeAl.get(i);
if(edge.key == ch && st.contains(edge.u))
mp.put(edge.u, edge.v);
}

            for(Integer i : st)
              if(!mp.containsKey(i))//表明i节点对应的是一条空边
                mp.put(i, -1);

//将st集合拆分成两个不想交的集合
Set<Integer> firstSet = new HashSet<Integer>();
Set<Integer> secondSet = new HashSet<Integer>();
for(int j=; j<setList.size(); ++j){
firstSet.clear();
secondSet.clear();
Set<Integer> tmpSt = setList.get(k);
for(Entry<Integer, Integer> entry : mp.entrySet()){//返回此映射中包含的映射关系的 set 视图。返回的 set 中的每个元素都是一个 Map.Entry
if(tmpSt.contains(entry.getValue()))
firstSet.add(entry.getKey());
else secondSet.add(entry.getKey());
}
if(firstSet.size()!= && secondSet.size()!=){
flag = true;//如果发现可以拆分的集合,则继续最顶层的while循环
for(Integer i : tmpSt){//将firstSet 和 secondSet中都没有的元素添加到firstSet中
if(!firstSet.contains(i) && !secondSet.contains(i))
firstSet.add(i);
}
setList.remove(k);
setList.add(firstSet);
setList.add(secondSet);
break hjzgg;
}
}
}
}
}
// for(int k=0; k<setList.size(); ++k)//输出最终的集合划分
// System.out.println(setList.get(k));
// System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
for(int k=; k<setList.size(); ++k){
Set<Integer> st = setList.get(k);
if(st.size() > ){//看成是一个等价的状态,选择第一个元素当作代表
int first=;
for(Integer i : st){//取得第一个元素
first = i;
break;
}
ArrayList<Edge> tmpList = new ArrayList<Edge>();
for(int i=; i<nodeAl.size(); ++i){//遍历所有的边,找到不是first
Edge edge = nodeAl.get(i);
if(st.contains(edge.u) && edge.u!=first){
nodeAl.remove(i);
--i;
} else if(st.contains(edge.v) && edge.v!=first){
nodeAl.remove(i);
--i;
tmpList.add(new Edge(edge.u, first, edge.key));
}
}
nodeAl.addAll(tmpList);
}
}
} public void outputMinimumDFA(){
// for(int i=0; i<nodeAl.size(); ++i)//输出未确定化的DFA
// System.out.println(nodeAl.get(i));
toMinimumDfa();
for(int i=; i<nodeAl.size(); ++i)
System.out.println(nodeAl.get(i));
}
} public class ToMinimumDFA { public static void main(String[] args) {
// String formal_ceremony = "1(0|1)*101";
String formal_ceremony = "0*(100*)*0*";
NFA nfa = new NFA(formal_ceremony);
DefinedNFA definedDFA = new DefinedNFA(nfa.getNFAGraphics(), nfa.getCharacterSet(), nfa.getFinalState());
definedDFA.ToStateMatrix();
MinimumDFA minimumDFA = new MinimumDFA(definedDFA.getNewFinalState(), definedDFA.getNodeAl(), definedDFA.getDfaNode(), definedDFA.getCharacterSet());
minimumDFA.outputMinimumDFA();
} }

编译原理:正规式转变成DFA算法的更多相关文章

  1. 正规式->最小化DFA说明

      整体的步骤是三步: 一,先把正规式转换为NFA(非确定有穷自动机), 二,在把NFA通过"子集构造法"转化为DFA, 三,在把DFA通过"分割法"进行最小化 ...

  2. 正规式转化为DFA

    https://www.bilibili.com/video/BV1dj411f7AR?p=50 例题:

  3. 《编译原理》构造与正规式 (0|1)*01 等价的 DFA - 例题解析

    <编译原理>构造与正规式 (0|1)*01 等价的 DFA - 例题解析 解题步骤: NFA 状态转换图 子集法 DFA 的状态转换矩阵 DFA 的状态转图 解: 已给正规式:(0|1)* ...

  4. 编译原理课后习题答案令A,B和C是任意正规式,证明以下关系成立(A|B)*=(A*B*)*=(A*|B*)*

    题目: 令A.B和C是任意正规式,证明以下关系成立: A∣A=A (A*)*= A*         A*=ε∣A A*        (AB)*A=A(BA)*        (A∣B)*=(A*B ...

  5. 有穷自动机(NFA、DFA)&正规文法&正规式之间的相互转化构造方法

    在编译原理(第三版清华大学出版社出版)中第三章的词法分析中,3.4.3.5.3.6小节中分别讲解了 1.什么是NFA(不确定的有穷自动机)和DFA(确定的有穷自动机) 2.如何将  不确定的有穷自动机 ...

  6. 正规式与正规集,DFA与NFA

    词法分析器的设计 词法分析器的功能:输入源程序.输出单词符号 词法分析器的设计:给出程序设计语言的单词规范--单词表, 对照单词表设计识别该语言所有单词的状态转换图, 根据状态转换图编写词法分析程序 ...

  7. 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——3 计算4个函数

    整个引擎代码在github上,地址为:https://github.com/sun2043430/RegularExpression_Engine.git nullable, firstpos, la ...

  8. 编译原理-NFA构造DFA

    本题摘自北邮的编译原理与技术. 首先,根据此图构造状态转换表 表中第一列第一行表示从第一个符号B通过任意个空转换能到达的节点,Ia表示由此行的状态数组({B,5,1}可以看作0状态)经过一个a可以到达 ...

  9. 【编译原理】c++实现自下而上语法分析及中间代码(四元式)生成

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

随机推荐

  1. 用Navicat Premium 远程连接oracle数据库

    1.安装Navicat Premium软件(我的是11.0.7版本)(假设安装路径为D:\NavicatLite\Navicat Premium) 2.下载 instantclient-basic-n ...

  2. 读bootstrap2.3.2有感1

    起步: 下载编译好的bootstrap2文件,百度新版jquery.js,并复制html模版(hello world)放置在同一目录,然后看了下官网上的范例网站,心里还是很激动啊~ <!DOCT ...

  3. [转]Python数据挖掘

  4. Windows的bat脚本中for循环

    转载至 http://123304258.blog.163.com/blog/static/12354702012621103256608/   [删除目录下某种格式的文件 ] for /r  f:\ ...

  5. html多引号嵌套问题

    将html中的引号使用"代替 <a href="javascript:bootbox.alert('<img src="http://miaoimg.heym ...

  6. mongoDB研究笔记:复制集故障转移机制

    上面的介绍的数据同步(http://www.cnblogs.com/guoyuanwei/p/3293668.html)相当于传统数据库中的备份策略,mongoDB在此基础还有自动故障转移的功能.在复 ...

  7. 如何在ASP.NET 5上搭建基于TypeScript的Angular2项目

    一.前言 就在上月,公司的一个同事建议当前的前端全面改用AngularJs进行开发,而我们采用的就是ASP.NET 5项目,原本我的计划是采用TypeScript直接进行Angular2开发.所以借用 ...

  8. 第三波假期干货——webstrom工具栏图标

    在WS中使用工具栏上的快捷图标来配合工作可以有效提高效率,因为你不用去记住一些快捷键,只要点一下鼠标即可.不过在WS中有很多实用功能却是没有自带个性图标的,导致自定义工具栏后可能就是好几个一模一样的绿 ...

  9. redis使用心得

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com   redis是继memcached之后兴起的内存数据库,作者非常崇尚简洁高效,力求以最简单的方式最高效的解决问题 ...

  10. Android移动APP开发笔记——最新版Cordova 5.3.1(PhoneGap)搭建开发环境

    引言 简单介绍一下Cordova的来历,Cordova的前身叫PhoneGap,自被Adobe收购后交由Apache管理,并将其核心功能开源改名为Cordova.它能让你使用HTML5轻松调用本地AP ...