NFA->DFA->最简DFA

 /**
 *author  Young
 *
*2014-5-11
*
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class NFAtoDFA {

	static String map[][];
	static int endNum;
	//保存所有状态
	static ArrayList<Set<Integer>>list=new ArrayList<Set<Integer>>();
	//输入符号列
	static ArrayList<String>operatorList=new ArrayList<String>();

	//fromSetToSet中每个元素对应 list中从哪个状态下标到哪个状态下表经过的符号及对应下标
	static ArrayList<SetOperatorSet>fromSetToSet=new ArrayList<SetOperatorSet>();

	static Scanner sc=new Scanner(System.in);
	public static void main(String[] args) {

		System.out.println("输入终结符号(最大值)");
		//默认最大值是终结  0是开始
		endNum=sc.nextInt();
		map=new String[endNum+1][endNum+1];
		initMap();
		System.out.println("输入符号集(空格分隔,e代表可自动到达)");
		sc.nextLine();
		String line=sc.nextLine();

		for(String str:line.split(" +"))
		{
			operatorList.add(str);
		}
		System.out.println();
		int s,e;
		String operator;
		//-1表示输入结束
		while(sc.hasNext())
		{
			s=sc.nextInt();
			if(s==-1)
				break;
			operator=sc.next();
			e=sc.nextInt();
			map[s][e]=operator;

		}
		//把第一个状态加入list
		list.add(getSetStartWith(0));

		for(int i=0;i<list.size();i++)
		{
			Set<Integer> set=list.get(i);
			//======把符号作用于集合=======
			for(String ope:operatorList)
			{
				if(ope.equals("e"))
					continue;

				Iterator<Integer> iter=set.iterator();
				//set2 保存从某一集合(list中)经过某一符号达到的所有集合组成的集合
				Set<Integer> set2=new TreeSet<Integer>();
				//依次把该符号作用于该集合的每一个数字
				while(iter.hasNext())
				{
					//每次获取该集合中一个数字
					int fromNum=iter.next();
					//获取从该数字经过ope到达的数字  -1表示不达到
					int toNum=getIndexFromWithOperatorTo(fromNum,ope);
					if(toNum==-1)
						continue;
					//获取从toNum开始的可自动到达的集合,并加入set2
					set2.addAll(getSetStartWith(toNum));
				}

				//若list中存在该状态集合
				if(list.contains(set2))
				{
					//找到list中该状态集合下标
					int index=list.indexOf(set2);
					//结果列表中添加由list中第i个状态经ope达到list中第index个状态
					fromSetToSet.add(new SetOperatorSet(i, index, ope));
				}
				else
				{
					if(set2.size()!=0)
					{
						//若list中原本没有改状态,则把新状态加入list,并把list中第i个状态经ope达到list中最后一个状态
						list.add(set2);
						fromSetToSet.add(new SetOperatorSet(i, list.size()-1, ope));
					}
				}
			}
			//======把符号作用于集合结束=======
		}

		showResult();
		////////////===============NFA  化  DFA 结束 ======================///////////////

		///==================化简  DFA=======================/////

		new SimpleDFA( endNum, list, operatorList, fromSetToSet).start();

	}

	private static void initMap() {
		for(int i=0;i<endNum+1;i++)
			for(int j=0;j<endNum+1;j++)
				map[i][j]="";
	}

	private static void showResult() {

		for(int i=0;i<list.size();i++)
		{
			System.out.println(i+1+"  "+list.get(i));
		}
		Collections.sort(fromSetToSet);

		System.out.println("\n\n");
		for(SetOperatorSet li:fromSetToSet)
		{
			System.out.println(li.fromListIndex+1+"  "+li.operator+"   "+(li.toListIndex+1));
		}
		System.out.println("\n\n==========\n");

	}

	//获取map中从fromNum经过ope到达的数字   -1表示无法达到
	private static  int getIndexFromWithOperatorTo(int fromNum, String ope) {

		for(int i=0;i<endNum+1;i++)
		{
			if(map[fromNum][i].equals(ope))
				return i;
		}
		return -1;
	}

	//获取从s开始可自动达到的集合
	private static Set<Integer> getSetStartWith(int s) {
		Set<Integer> set=new TreeSet<Integer>();
		set.add(s);

		DFS(s,set);
		return set;
	}

	//搜索从s开始可自动达到的集合
	private static void DFS(int s,Set<Integer> set) {

		for(int i=0;i<=endNum;i++)
		{
			if(map[s][i].equals("e")&&!set.contains(i))
			{ 

				set.add(i);
				DFS(i,set);
			}
		}
	}

}

class SetOperatorSet implements Comparable<SetOperatorSet>{

	public  int fromListIndex;
	public  int toListIndex;
	public  String operator;
	public SetOperatorSet(int fromListIndex, int toListIndex, String operator) {

		this.fromListIndex = fromListIndex;
		this.toListIndex = toListIndex;
		this.operator = operator;
	}
	 @Override
	public boolean equals(Object obj) {
		 SetOperatorSet sos=(SetOperatorSet)obj;
		if(this.fromListIndex==sos.fromListIndex&&this.toListIndex==sos.toListIndex&&this.operator.equals(sos.operator))
			return true;
		return false;
	}
	@Override
	public int compareTo(SetOperatorSet o) {
	//	return  this.operator.compareTo(o.operator);
//		if(this.fromListIndex==o.fromListIndex&&this.toListIndex==o.toListIndex&&this.operator.equals(o.operator))
//			return 0;
		return this.fromListIndex-o.fromListIndex;
	}
	@Override
	public String toString() {

		return fromListIndex+ "  "+operator+"  "+toListIndex;
	}

}

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class SimpleDFA {

	 int endNum;
	//保存所有状态
	 ArrayList<Set<Integer>>list;

		//输入符号列
	 ArrayList<String>operatorList;

	//fromSetToSet中每个元素对应 list中从哪个状态下标到哪个状态下表经过的符号及对应下标
	 ArrayList<SetOperatorSet>fromSetToSet;

	 ArrayList<Set<Integer>>result=new ArrayList<Set<Integer>>();
	 ArrayList<Set<Integer>>tempList=new ArrayList<Set<Integer>>();
	public SimpleDFA(int endNum, ArrayList<Set<Integer>> list,ArrayList<String> operatorList,ArrayList<SetOperatorSet> fromSetToSet) {
		this.endNum = endNum;
		this.list = list;
		this.operatorList = operatorList;
		this.fromSetToSet = fromSetToSet;

	}

	public  void start() {

		 DividedSetByEndNum();

		 for(int i=0;i<tempList.size();i++)
		 {

			 Set<Integer>set=tempList.get(i);
			 int j;
			 for( j=0;j<operatorList.size();j++)
			{
				 if(operatorList.get(j).equals("e"))
					 continue;
				 if(needDivided(i,set,operatorList.get(j)))
				 {
					 break;
				 }
			}
			 if(j>=operatorList.size())
			 {
				 result.add(set);
			 }
		 }

		 showResult();

	}

	private void showResult() {
		 System.out.println("\n\n========最简化DFA===\n");
		 for(int i=0;i<result.size();i++)
		 {
			System.out.println( result.get(i));
		 }

		 for(int i=0;i<result.size();i++)
		 {
			 Set<Integer>set=result.get(i);
			 if(set.size()==1)
				 continue;
			 Iterator<Integer>itr=set.iterator();
			 int firstInSet=itr.next()-1;

			 while(itr.hasNext())
			 {
				 int next=itr.next()-1;

				 for(int j=0;j<fromSetToSet.size();j++)
				 {

					 SetOperatorSet sos=fromSetToSet.get(j);

					 if(sos.fromListIndex==next)
					 {
						 sos.fromListIndex=firstInSet;

					 }
					 if(sos.toListIndex==next)
					 {

						 sos.toListIndex=firstInSet;

					 }

				 }
			 }
		 }

//			System.out.println("\n替换完毕\n");
//			for(int j=0;j<fromSetToSet.size();j++)
//			{
//				SetOperatorSet li=fromSetToSet.get(j);
//				System.out.println(li.fromListIndex+"  "+li.operator+"   "+(li.toListIndex));
//			}

		ArrayList<SetOperatorSet>sosSet=new ArrayList<SetOperatorSet>();
		for(SetOperatorSet sos:fromSetToSet)
		{
		//	System.out.print(sos);
			if(!sosSet.contains(sos))
				sosSet.add(sos);

		}
		System.out.println("========最终结果=========");
		for(SetOperatorSet sos:sosSet)
		{
			System.out.println(sos.fromListIndex+1+"  "+sos.operator+"  "+(1+sos.toListIndex));
		}

	}

	private  boolean needDivided(int i,Set<Integer> set, String ope2) {

		Set<Integer>set2=new TreeSet<Integer>();
		Map<Integer,Set<Integer>>map=new HashMap<Integer,Set<Integer>>();
		Iterator<Integer>itr=set.iterator();

		while(itr.hasNext())
		{

			int fromStatue=itr.next();

			int toStatue=getFromByOperatorTo( fromStatue,  ope2);

			if(toStatue==-1)
				continue;
			int aimStatuIndex=getAimStatuIndexByReaultAndTempList(i,toStatue);

			if(set2.add(aimStatuIndex))
			{

				Set<Integer> set3=new TreeSet<Integer>();
				set3.add(fromStatue);
				map.put(aimStatuIndex, set3);
			}
			else
			{

				Set<Integer> set3=map.get(aimStatuIndex);
				set3.add(fromStatue);
			}

		}
		if(set2.size()<=1)
		{
			return false;
		}

		Iterator<Integer>iterator=set2.iterator();
		while(iterator.hasNext())
		{
			int index=iterator.next();
			Set<Integer> s=map.get(index);
			if(s.size()==1)
			{
				result.add(s);
			}
			else
			{
				tempList.add(s);
			}
		}
		return true;
	}
	private int getAimStatuIndexByReaultAndTempList(int i,int toStatue) {
		for(;i<tempList.size();i++)
		{
			Set<Integer>set=tempList.get(i);
			if(set.contains(toStatue))
				return i;
		}
		for(int j=0;j<result.size();j++)
		{
			Set<Integer>set=result.get(j);
			if(set.contains(toStatue))
				return -j-1;
		}
		return Integer.MAX_VALUE;
	}

	private void DividedSetByEndNum() {
		Set<Integer>endSet=new TreeSet<Integer>();
		Set<Integer>unEndSet=new TreeSet<Integer>();
		for(int i=0;i<list.size();i++)
		{
			Set<Integer>s=list.get(i);
			if(s.contains(endNum))
			{
				endSet.add(i+1);
			}
			else
				unEndSet.add(i+1);
		}

		tempList.add(unEndSet);
		tempList.add(endSet);
	}

	private  int getFromByOperatorTo(int sStatu, String ope) {
		for(int i=0;i<fromSetToSet.size();i++)
		{
			SetOperatorSet sos=fromSetToSet.get(i);
			if(sos.fromListIndex+1==sStatu&&sos.operator.equals(ope))
				return sos.toListIndex+1;
		}
		return -1;
	}

}

/*
测试样例
10
e  a   b
0 e 1
0  e  7
1  e  2
1 e 4
2 a 3
4 b 5
3 e 6
5 e 6
6 e 1
6 e 7
7 a 8
8 b 9
9 b 10
-1

==================
1  [0, 1, 2, 4, 7]
2  [1, 2, 3, 4, 6, 7, 8]
3  [1, 2, 4, 5, 6, 7]
4  [1, 2, 4, 5, 6, 7, 9]
5  [1, 2, 4, 5, 6, 7, 10]

1  a   2
1  b   3
2  a   2
2  b   4
3  a   2
3  b   3
4  a   2
4  b   5
5  a   2
5  b   3

==========

========最简化DFA===

[4]
[5]
[2]
[1, 3]

==========

========最终结果=========
1  a  2
1  b  1
2  a  2
2  b  4
4  a  2
4  b  5
5  a  2
5  b  1

==================
测试样例
13
e  a  b
0 e 1
0 e 3
1 b 2
2 e 1
2 e 3
3 a 4
4 b 5
5 e 6
6 e 13
6 e 7
6 e 9
7 b 8
8 e 12
9 a 10
10 b 11
11 e 12
12 e 13
12 e 6
-1

=====================
1  [0, 1, 3]
2  [4]
3  [1, 2, 3]
4  [5, 6, 7, 9, 13]
5  [10]
6  [6, 7, 8, 9, 12, 13]
7  [6, 7, 9, 11, 12, 13]

1  a   2
1  b   3
2  b   4
3  a   2
3  b   3
4  a   5
4  b   6
5  b   7
6  a   5
6  b   6
7  a   5
7  b   6

==========

========最简化DFA===

[4, 6, 7]
[1, 3]
[2, 5]

==========

========最终结果=========
1  a  2
1  b  1
2  b  4
4  a  2
4  b  4

*/

NFA->DFA->最简DFA,布布扣,bubuko.com

时间: 2025-01-17 04:28:04

NFA->DFA->最简DFA的相关文章

从正则表达式到 NFA 到 DFA 到最简 DFA (二)

从正则表达式到 NFA 到 DFA 到最简 DFA (二) NFA $ \rightarrow $ DFA (子集构造法) 这里我们用一个例子来解释. 如上图所示,这是上一篇文章中的正则表达式化成的 NFA,这里拿来接着用. 我们首先看开始状态 n0.n0 在接收了一个字符 a 之后可以转换到 n1,这个时候我们要看 n1 是否存在 $ \varepsilon $ 转移.若存在,则递归的将所有能 $ \varepsilon $ 转移的状态添加到一个集合里(包括 n1).然后再看我们所创造的这个集

从正则表达式到 NFA 到 DFA 到最简 DFA (三)(结束)

从正则表达式到 NFA 到 DFA 到最简 DFA (三) DFA $ \rightarrow $ 最简 DFA (Hopcroft 算法) 这是一个基于等价类的算法. split(S) foreach char c if c 能切分 S split S into T1, T2, ..., TK hopcroft() split all nodes into N, A(即非接收状态和接收状态) while (set is still changing) split(N/A) 这里的等价类,通俗来

DFA化简

首先是未化简DFA的转换表 NFA状态 DFA状态 a b {0,1,2,4,7} A B C {1,2,3,4,6,7,8} B B D {1,2,4,5,6,7} C B C {1,2,4,5,6,7,9} D B E {1,2,4,5,6,7,10} E B C 首先根据分为非接受状态组和接受状态组{A,B,C,D}和{E}. 通过输入a来分组,发现第一组无法区分,看输入b的情况,A,B,C都是转到第一组,只有D是转到第二组E,所以这里就可以分出来一组D,现在有3组,{A,B,C},{D}

第九次 DFA化简

1.将DFA最小化:教材P65 第9题 I {1,2,3,4,5} {6,7} {34}b->{6,7} {1,2}b->{2} {5}-> {6}b->{6} {7}b->{6} {6,7}不可区别 II {1,2},{3,4},{5} {6,7} {1}b->{2},{2}b->{2} {3}c->{3},{4}c->{3} {1,2}不可区别,{3,4}不可区别 不可区别 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→

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

在编译原理(第三版清华大学出版社出版)中第三章的词法分析中,3.4.3.5.3.6小节中分别讲解了 1.什么是NFA(不确定的有穷自动机)和DFA(确定的有穷自动机) 2.如何将  不确定的有穷自动机(NFA)  转化为  确定的有穷自动机(DFA); 3.如何化简DFA; 4.正规式和有穷自动机的等价性(根据给出的正规式构造有穷自动机); 5.正规文法和有穷自动机的等价性(根据给出的正规式构建有穷自动机): 个人在开始学习这一章节的时候,课上听得有些迷惑,并且看书也是感觉没有头绪,后来花了一些

NFA转换成DFA——汉字形式数字转换成整数数字

偶然间遇到了一个需求:汉字形式数字转换成整数数字.如果不处理意外情况,可以写的很简单(比如不会出现三三等),详情可以看这里.但是,想着可以写成一个FA的形式,于是乎,发现并不是想象中的那么简单..因为写成FA就发现,要处理非法形式的问题,还是有点麻烦的. 好不容易写成了FA,发现是个NFA,于是乎写了个NFA转换成DFA的代码,也支持了一套简单的FA的定义规则.代码如下: package ie; import java.util.ArrayList; import java.util.HashM

自己动手开发编译器(四)利用DFA转换表建立扫描器

上回我们介绍了两种有穷自动机模型——确定性有穷自动机DFA和非确定性有穷自动机,以及从正则表达式经过NFA最终转化为DFA的算法.有些同学表示还是难以理解NFA到底怎么转化为DFA.所以本篇开头时我想再多举一个例子,看看NFA转化为DFA之后到底是什么样.首先我们看下面的NFA,它是从一组词法分析所用的正则表达式转换而来的.这个NFA合并了IF.ID.NUM.error这四个单词的NFA.因此,它的四个接受状态分别代表遇到了四种不同的单词. 用上一篇学到的方法,我们需要求出一个DFA,它的每个状

正规式-&gt;最小化DFA说明

  整体的步骤是三步: 一,先把正规式转换为NFA(非确定有穷自动机), 二,在把NFA通过"子集构造法"转化为DFA, 三,在把DFA通过"分割法"进行最小化. 一步很简单,就是反复运用下图的规则,图1 这样就能转换到NFA了. 给出一个例题,来自Google book.本文主要根据这个例题来讲,图2 二.子集构造法. 同样的例题,把转换好的NFA确定化,图3 这个表是从NFA到DFA的时候必须要用到的.第一列第一行I的意思是从NFA的起始节点经过任意个ε所能到达

js 正则学习小记之NFA引擎

之前一直认为自己正则还不错,在看 次碳酸钴,Barret Lee 等大神都把正则玩的出神入化后发现我只是个战五渣.  求抱大腿,求大神调教. 之前大致有个印象,正则有很多种引擎,但我根本不知道有哪些引擎. 今天在读<精通正则表达式>才发现有Traditional NFA,POSIX NFA 和 DFA (具体自己百度下吧).可用了这么久的正则,还不知道 js 属于哪一种呢.在<精通正则表达式>里有个简单是方法检测属于哪一种. 用 /nfa|nfa not/ 去匹配 "nf