利用子集法构造DFA
一、实验目的
掌握将非确定有限自动机确定化的方法和过程。
二、实验要求、内容
1.输入一个NFA,输出一个接受同一正规集的DFA;
2.采用任意语言,实现该算法;
3编制测试程序;
4.调试程序。
三、实验设备
计算机、Windows 7操作系统、Eclipse Luna程序集成环境、JDK 12。
四、实验原理(或程序框图)及步骤
对给定的NFA状态,程序在利用子集构造法将其转换为对应的DFA状态时,首先需要获取NFA状态转换图中的对应信息,包括字母表、状态集以及初始状态。为方便程序处理,可将每个状态实例化为一个类State,其类图如图4-1所示,函数详细定义及功能见附录。状态转换图中,某状态经过字母表中某字符串可达某状态集,构成了当前状态、某个字符串和某个状态集三者的映射关系,则可对特定状态用字符串与状态集间的映射关系准确描述三者的关系,即构建键值对<字符串,可达状态集>(变量path)描述特定状态。此外,程序中还涉及某状态处理时的标记与否(变量flag)和状态名(变量name)。
五、程序源代码
计算DFA的while循环如下所示,此时已经完成了所有状态信息的输入、初始化并且计算出了DFA的首个状态加入transState列表中,此列表即为最终所求的DFA的状态集,其中每个状态的状态名均此状态包含的NFA状态集。tState被用于标记当前状态,是自定义的状态类State的实例,其中包含状态姓名、是否被标记以及此状态和所有字母上的转换关系,其类图见图4-1,详细定义见附录。flag为其是否被标记的布尔类型变量,transTable中包含所有找到的构造DFA的状态集合(原NFA的子集),在循环中通过path标记当前找到的可以构造DFA的状态。包含文件处理和输入输出的完整主程序以及类State的定义见附录。
while (!flag)
{
tState.markFlag(true);
List<String> state = new LinkedList<String>();
for (int i = 0; i < transTable.size(); i++)
{
state = transTable.get(i);
if (state.toString().equals(tState.name())) break;
}
// 找到当前状态的原始转换列表
String[] path = new String[state.size()];
k = 0;
for (String m : state) path[k++] = m;
// 取到当前状态
for (String s : sigma)
{
// 按字母表填转换表
if (s.equals("$")) break;
String[] move = new String[state.size()];
move = move(states, totalStates, path, s);
// 第一次move
// 如果这个状态得到这个字符串,执行e-closure运算
if (!move[0].equals("#"))
move = move(states, totalStates, move, "$");
stateList = new LinkedList<>();
for (String q : move) stateList.add(q);
tState.put(s, stateList);// 将得到的状态填入对应的状态
System.out.println(tState);
if (!transTable.contains(stateList) && !stateList.contains("#"))
{
transTable.add(stateList);//扩充状态转换列表
State sa = new State(stateList.toString(), sigma, totalSignals);
sa.put("$", "#");
transState.add(sa);
}
// 找下一个状态,改变对应flag的值用以控制循环
for (State s : transState)
{
if (!s.isFlag())
{
tState = s;flag = tState.isFlag();
break;
} else flag = true;
}
}
}
计算闭包的函数如下所示,相关描述见注释。
/**算法描述:(1)将T中所有状态压入栈stack; 将closure (T) 初始化为T;
* (2)若stack不空 将栈顶元素t弹出栈;
* (3)对每个从t到u有一条标记为 ε的边的状态u:
如果 u 不在ε-closure ( T ) do 将u 添加到closure ( T );
* (4)将u压入栈stack中 closure算法
* @param states 状态列表
* @param totalStates,所有状态数
* @param location,待转换状态在原始状态列表中的位置
* @param str,将要执行对该字符串的闭包运算
* @return 转换后的字符串集合 */
public static String[] closure(State[] states, int totalStates, int location, String str)
{
LinkedList<String> list = (LinkedList<String>) states[location].get(str);
LinkedList<String> current = new LinkedList<String>();
Stack<String> stack = new Stack<>();
if (list.contains("#"))
{
if (str.equals("$")) current.add(states[location].name());
}
else
{
stack.push(states[location].name());
for (String i : list) stack.push(i);
while