我已经构建了一个NFA,并且我正在运行此方法来评估计算机以查看表达式是否有效。这适用于小正则表达式,但是当我的正则表达式的大小因此我的NFA的大小变得太大时,此搜索会向我抛出堆栈溢出。我相当肯定它是因为我已经实现了BFS,使用了递归,而且我可能没有很好地处理我的基本情况。
此方法采用表达式和节点(从NFA的起始节点开始)。首先,它检查表达式的长度是否为零,如果我在接受节点中(节点上的布尔值),则返回true。 如果表达式长度为零但当前节点不是接受节点,则返回false。
如果这些都没有评估,那么我得到一个列表,列出当前节点可以使用" e" (epsilon)过渡,并评估它们。
如果没有" e"节点,然后我从输入表达式中删除第一个字符,创建表达式的缩短子字符串(删除表达式的前面),然后查找该节点可以使用删除的字符和缩减表达式到达的节点列表。
如果这些都没有击中,那么我返回false
基本正则表达式是(a | b)* a 并且评估表达式的示例将是aaaa 在每次通过时减少,aaaa> aaa> aa> a-> a。
private boolean evaluate(autoNode node, String expression)
{
if(expression.length()==0 && node.getAccept())
{
return true;
}
else if(expression.length()==0 && !node.getAccept())
{
return false;
}
String evalExp = expression.charAt(0)+""; //The first character in the expression
String redExp = expression.substring(1, expression.length());
//for each epsilon transition, evaluate it
if(node.getTransSet().contains("e"))
{
//if this node has an "e" transition then...
ArrayList<autoNode> EpsilonTransMap = node.getPathMap("e");
//The above ArrayList is a list of all the nodes that this node can reach
//using the "e" / epsilon transition
for(autoNode nodes : EpsilonTransMap)
{
if(evaluate(nodes, expression))
{
return true;
}
}
}
//for each transition on that key evaluate it
if(node.getTransSet().contains(evalExp))
{
//if this node has a transition from the front of the expression then...
ArrayList<autoNode> TransitionKeyMap = node.getPathMap(evalExp);
//The above ArrayList is a list of all the nodes that this node can reach
//on a transition equal to the "key" removed from the front of the expression String
for(autoNode nodes : TransitionKeyMap)
{
if(evaluate(nodes, redExp))
{
return true;
}
}
}
return false;
}
我意识到我可能通过使用bfs搜索而不是dfs来解决我自己的问题。我想知道是否有人可以帮助我解决这个问题并避免因为一次有太多事情而导致堆栈溢出。因为虽然(a | b)* a可以评估得很好......
((AA)+ |(BB)+ |(CC)+)(BA)的(CA)
创建一个相当大的NFA,导致堆栈溢出时只评估: &#34;&#34;
任何不会导致我完全废弃该方法的事情都会很棒并且值得赞赏。
答案 0 :(得分:0)
嗯,你在这里实际上没有DFS 或一个BFS,但这并不重要。我想你也不能用正则表达式来表达字母&#34; e&#34;在他们中间。
重要的是,当您达到epsilon转换周期时,您将获得堆栈溢出。例如:
评估(n1,&#34; aa&#34;)找到从n1到n2的epsilon过渡,并递归:
评估(n2,&#34; aa&#34;),它发现从n2到n1的epsilon过渡并递归:
评估(n1,&#34; aa&#34;)..等等,递归直到堆栈溢出。
有很多方法可以解决这个问题......但即使你修复它,这对于评估NFA来说仍然是一个非常糟糕的算法 - 它可以在状态数量上花费指数时间!
编辑 - 所以,这是以伪代码进行NFA评估的正确方法:
boolean evaluate(Node nfa, String str)
{
Set<Node> fromStates = new Set();
fromStates.add(nfa);
closeEpsilons(fromStates);
for (char chr in str)
{
if (fromStates.size()==0)
return false;
//find all the states we can get to from
//fromStates via chr
Set<Node> toStates = new Set();
for (Node fromState in fromStates)
{
//OP's code would say .getPathMap(chr) here
for(Node toState in fromState.getTransitionTargets(chr))
{
if (!toStates.contains(toState))
toStates.add(toState);
}
}
closeEpsilons(toStates);
//process the rest of the string with the state set we just found
fromStates = toStates;
}
//string is done. see if anything accepts
for(Node state in fromStates)
{
if (state.accepts())
{
return true;
}
}
return false;
}
//expand a state set with all states is reaches via epsilons
void closeEpsilons(Set<Node> states)
{
Queue<Node> processQueue = new Queue();
processQueue.addAll(states);
while(!processQueue.isEmpty())
{
Node fromState = processQueue.removeFirst();
//OP's code would say "getPathMap("e") here
for(Node toState in fromState.getEpsilonTargets())
{
if (!states.contains(toState))
{
//found a new state
states.add(toState);
//we'll have to search it for epsilons
processQueue.add(toState);
}
}
}
}