nfa转dfa的过程(维护一个队列用于存储待扩展的状态集 q,一个向量存储所有的状态集 temp_state)
queue< vector<int> >q;
vector< vector<int> >temp_state;
过程如下:
(1)把初始状态集加入到temp_state中。
这里起初用
temp_state[0].pushback(element)
的方法,不过这样做是存在问题的。
最后,先把初始的状态整合到一个整数向量中,再把向量添加到temp_state。
(2)把初始状态集入队
(3)队首元素出队(要删除),对于队首元素,首先检查它接受符号a可以到达的新的状态集,然后检查接收
符号b可以到达的状态集。
(4)若新的状态集与原来的状态集没有重复的,就把新的状态集添加到temp_state和q中。同时更新一下dfa的
状态转换表,这里要注意,即使不把新的状态集添加到temp_state和q中,也要更新状态转换表。同时要注意对新的状态集为
空时的处理。
(5)检查q是否为空,如果是,结束,否则跳向(3)。
(6)输出得到的dfa状态转换表。
细节问题:
在求news(新的状态集)时,首先计算通过符号a可以到达的集合,在求出这个中间news后,要去除多余的元素(状态太多在运行时间上回变长)。
sort(news.begin(),news.end()); //排序
news.erase(unique(news.begin(), news.end()), news.end()); //unique把重复的元素放到队列的最后面
排序算法用 algorithm中的。
之后,再基于news,查看它通过空转换可以到达的状态。
for(int i=0;i<news.size();i++){ //继续检查通过 #(空符号)可以到达的转态
//注意news.size()是动态扩展的
for(int k=0;k<state.size();k++){
if(table[news.at(i)][state.at(k)]=='#') //to write
{
for(int ii=0;ii<news.size();ii++){ //这里如果不检查是否有重复,会无限循环
if(news.at(ii)==state.at(k))
break;
else if((ii==news.size()-1)&&news.at(ii)!=state.at(k))
news.push_back(state.at(k));
}
}
}
}
不同于接受一个非空符号时的处理,这里一定要在得到一个新的状态时就与原来的状态作比较,不一样时才加入新的状态,
否则会无限循环。
还有一点要注意的是,向temp_state和q中插入的状态集必须是统一排好序的,不然在新的状态集与原来的状态集比较时
会出现问题,比如 (1,2,4)和(2,1,4),这两个状态是等价的,但是我们用 vector<int> 存储,它们在向量中的顺序不一样,
如果用 == 号来判断,会返回为不相等,因此这里入队和插入temp_state的状态集都是排过的。
sort(news.begin(),news.end());
遇到的问题
(1)得到的dfa有重复的状态
在新得到的状态集与原有的状态集比较时,应该先排序,尽管我们认为它们里面状态的顺序不一致时
状态集任然是相等的,但计算机并不会这样考虑,它只会机械地先比较大小,再把元素一个一个作比较,
我们在编程时,一定要拥有计算机式的思维。
(2)会得到空状态
在写程序时,没有考虑到可能该状态集接受一个符号时,并不能到达任何一个状态,虽然这样整个
状态转换图仍然是正确的,但是已经与实际上dfa不符合了。
(3)得出的状态集中有多余的状态
存储新得到的状态集的向量news,在运行一遍后,未清除,上次得到的状态累积到下一次状态,出现这种问题
的原因:没有事先规划好细节,今后在解决较多变量的问题时,应该先规划好算法细节,并详细列出各个变量的作用,
作参考。