Java 如何使用此评估(BFS)避免堆栈溢出
我已经构建了一个NFA,我正在运行这个方法来评估机器,看看表达式是否有效。这适用于小型正则表达式,但当正则表达式的大小以及NFA的大小变得太大时,此搜索会向我抛出堆栈溢出。我相当肯定这是因为我已经实现了BFS,正在使用递归,并且可能没有很好地处理我的基本情况 此方法接受一个表达式和一个以NFA的开始节点开始的节点。首先,它检查表达式的长度是否为零,如果我在接受节点中,则检查节点上的布尔值,然后返回true。 如果表达式长度为零,但当前节点不是接受节点,则返回false 如果这两个都不计算,那么我将获得当前节点可以使用eε转换到达的所有节点的列表,并对它们进行计算 如果没有e节点,那么我将从输入表达式中删除第一个字符,制作表达式的缩短子字符串,删除表达式的前面,然后查找该节点可以使用删除的字符和缩减表达式访问的节点列表 如果这两个都未命中,则返回false 基本正则表达式是A | b*A 计算表达式的一个例子是aaaa 每次传球都会减少,aaaa->aaa->aa->a->a->Java 如何使用此评估(BFS)避免堆栈溢出,java,regex,Java,Regex,我已经构建了一个NFA,我正在运行这个方法来评估机器,看看表达式是否有效。这适用于小型正则表达式,但当正则表达式的大小以及NFA的大小变得太大时,此搜索会向我抛出堆栈溢出。我相当肯定这是因为我已经实现了BFS,正在使用递归,并且可能没有很好地处理我的基本情况 此方法接受一个表达式和一个以NFA的开始节点开始的节点。首先,它检查表达式的长度是否为零,如果我在接受节点中,则检查节点上的布尔值,然后返回true。 如果表达式长度为零,但当前节点不是接受节点,则返回false 如果这两个都不计算,那么我
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+baca
创建相当大的NFA,这会在计算时导致堆栈溢出:
a
任何不会导致我完全放弃该方法的东西都将是非常好的,我们将不胜感激。好吧,这里实际上没有DFS或BFS,但这并不重要。我猜不能使用带有字母e的正则表达式也不重要 重要的是,每当达到ε转换周期时,就会出现堆栈溢出。例如: 评估1,aa发现从n1到n2的ε转换,并递归: evaluaten2,aa,发现从n2到n1的ε转换并递归: 评估1,aa。。以此类推,直到堆栈溢出为止 有很多方法可以解决这个问题。。。但即使你修复了它,这仍然是一个非常糟糕的算法来评估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);
}
}
}
}
也许,您可以尝试将NFA转换为DFA,以减少回溯。我能够实现这一点,在花了这么多时间编写bum方法之后,很高兴看到一种更干净的方法。我显然还有很多东西要学,这让我很紧张,yeesh。这解决了堆栈溢出问题,这很有帮助,我仍然有一些问题需要评估,但我认为这是我的NFA建设,所以我需要仔细看看,但这是非常有帮助的,特别是在花费我的头撞墙之后。再次感谢!我有一个开源项目,用于NFA构建和DFA构建,如果您想了解一些实际的代码: