Java 使用ArrayList时如何处理深度递归?
所以今天早些时候我遇到了一个问题,现在是晚上,我所成功做的就是找出问题的根源 我有一堆节点组成一个图形。这些节点也可以有自己的节点子节点(想想肩->肘->手)。此图的一个可能场景是,其中一个节点可能连接了很多代的后代节点(如图所示) 我遇到的问题是,如果我在移动根节点时运行一个典型的递归函数,如updatePosition(),该函数将沿着其子节点行进行迭代,最终得到一个StackOverflower错误 我的问题是我不知道如何绕过这个限制。我知道我必须放弃这种递归方法,但是,怎么做呢?我非常感谢您的意见/建议,为我指明正确的方向 还要注意的是,这个问题发生在Android设备上,我假设这使得我的堆栈限制比典型桌面JVM上的堆栈限制要低Java 使用ArrayList时如何处理深度递归?,java,android,recursion,stack-overflow,Java,Android,Recursion,Stack Overflow,所以今天早些时候我遇到了一个问题,现在是晚上,我所成功做的就是找出问题的根源 我有一堆节点组成一个图形。这些节点也可以有自己的节点子节点(想想肩->肘->手)。此图的一个可能场景是,其中一个节点可能连接了很多代的后代节点(如图所示) 我遇到的问题是,如果我在移动根节点时运行一个典型的递归函数,如updatePosition(),该函数将沿着其子节点行进行迭代,最终得到一个StackOverflower错误 我的问题是我不知道如何绕过这个限制。我知道我必须放弃这种递归方法,但是,怎么做呢?我非常
编辑:根据使用手动创建堆栈的dangVarmit解决方案,以下是我的想法。我还没有能够测试这段代码,但它似乎可以工作 旧代码
void validatePosition()
{
if (_positionIsDirty == true)
updatePosition();
}
void updatePosition()
{
_positionIsDirty = false;
// etc...
for (int i = _childrenNodes.size() - 1; i >= 0; --i) // This recursive part caused the StackOverflowError
_childrenNodes.get(i).updatePosition();
}
void validatePosition()
{
if (_positionIsDirty == true)
{
// Create a Stack and add this Node to it.
Stack stack = new Stack();
stack.push(this);
while (stack.empty() == false)
{
// Pop top-most Node in Stack.
Node node = stack.pop();
// Update it and push its children onto the Stack.
node.updatePosition();
for (int i = node._childrenNodes.size() - 1; i >= 0; --i)
stack.push(node._childrenNodes[i]);
}
}
}
void updatePosition()
{
_positionIsDirty = false;
// etc...
}
新代码
void validatePosition()
{
if (_positionIsDirty == true)
updatePosition();
}
void updatePosition()
{
_positionIsDirty = false;
// etc...
for (int i = _childrenNodes.size() - 1; i >= 0; --i) // This recursive part caused the StackOverflowError
_childrenNodes.get(i).updatePosition();
}
void validatePosition()
{
if (_positionIsDirty == true)
{
// Create a Stack and add this Node to it.
Stack stack = new Stack();
stack.push(this);
while (stack.empty() == false)
{
// Pop top-most Node in Stack.
Node node = stack.pop();
// Update it and push its children onto the Stack.
node.updatePosition();
for (int i = node._childrenNodes.size() - 1; i >= 0; --i)
stack.push(node._childrenNodes[i]);
}
}
}
void updatePosition()
{
_positionIsDirty = false;
// etc...
}
创建节点的堆栈或数组列表。将根对象推到堆栈上,然后启动while循环(对于堆栈非空) 循环体在堆栈的顶部节点上运行。在您将递归到函数中的任何点上,您现在将新节点推送到堆栈上,然后使用continue在新的顶级节点上开始循环 当对某个节点执行递归函数时,它会将该节点从堆栈中弹出,并继续调用以开始循环
您的循环需要考虑一个事实,即它可能会在同一个节点上被多次调用,因此您需要对状态进行更多的管理。在递归函数中,您将返回到函数中相同位置的父调用方,该调用方具有相同的状态(局部变量等),因此您必须自己管理该状态。在左、右子节点中,您需要记住您检查并处理了左节点,这样您就可以跳过第二次检查并处理右节点(或者,如果您已经完成了两个节点,则弹出堆栈并继续)您可能希望在Wikipedia中查找“树遍历”,因为你要做的就是按预定顺序遍历一棵树。这篇文章有递归和非递归实现的例子。我认为@dangVarmint的答案基本上与文章的答案相同。是的,非常肯定。。你基本上是在用自己的堆栈替换系统堆栈,因为你可以分配比默认堆栈指针更多的内存。我还不能测试代码,但根据你的建议(如果我理解正确的话),如果我没有忽略任何东西的话,下面是我在一个quick.txt文件中提出的建议,我认为这可能会起作用(在开篇文章中更新)。