问候:
我的JSP Web应用程序中有父事务的比喻。我将事务ID存储在数据库中,并且要求显示父项的所有子项,然后显示父项子项的后续子项。实际上,这个父母及其子女的名单将永远不会超过4或5级,但我需要考虑到它可以比这更多层次。
我试过这样做会递归如下:
private static void processChildrenTransactions(
AllTremorTransactionsVO parentBean,
ArrayList<AllTremorTransactionsVO> childCandidatesList )
{
ArrayList<AllTremorTransactionsVO> childList =
new ArrayList<AllTremorTransactionsVO>();
for (AllTremorTransactionsVO childTransactions : childCandidatesList)
{
if (childTransactions.getParentGuid() != null)
{
if (childTransactions.getParentGuid().equals(parentBean.getTransactionGuid()))
{
childList.add(childTransactions);
}
}
}
for (AllTremorTransactionsVO allTremorTransactionsVO : childList)
{
processChildrenTransactions(allTremorTransactionsVO, childList);
}
return;
}
这不起作用,在循环运行时生成堆栈溢出。关于如何做到这一点的任何想法?
答案 0 :(得分:8)
如果方法的参数不能立即解决,则存在深度递归(存在使堆栈爆炸的风险)的方法。即被调用方法的最终结果取决于方法本身的结果。伪:
Result process(Parent parent) {
Result result = new Result();
for (Child child : parent.getChildren()) {
result.update(process(child));
}
return result;
}
这会导致代码等待update()
,直到结果已知,因此它会保留在堆栈中。它会随着每个方法调用而累积。
您可以优化它以使用tail recursion而不是使用可变结果对象作为参数:
void process(Parent parent, Result result) {
for (Child child : parent.getChildren()) {
result.update(child);
process(child, result);
}
}
这样,update()
可以立即执行,因为参数可以立即解决。只要在调用process()
之后没有返回值或任何其他逻辑发生,运行时就可以通过从堆栈中删除调用来优化它。另请参阅前面提到的有关尾递归的wiki文章和this website。
但是..你发布的代码似乎已经是尾递归的。所以问题出在其他地方。在研究了你的代码后,你似乎每次都在迭代相同的孩子。即这只是无限循环的手段。可能if
检查是伪造的和/或孩子们在自己的父子树中有反向引用。
答案 1 :(得分:2)
我猜你有一个无限循环...
childList
拥有相同的父级allTremorTransactionsVO
是childList
childList
并选择之前的第一个allTremorTransactionsVO
我通常会像这样构建这样的递归代码:
public List allChildren( Transaction trans )
{
List allChildren = new List();
for( Transaction childTrans : trans.getChildren() )
{
allChildren.addAll( allChildren( childTrans ));
}
return allChildren;
}
答案 2 :(得分:1)
我最近遇到了同样的问题(使用了太多的堆栈)并使用了迭代算法。该示例使用Javascript,但可以很容易地进行调整:
var nodeStack = new Array();
nodeStack.push(root);
while(nodeStack.length > 0) {
var currentNode = nodeStack.pop();
var data = currentNode.data;
var children = currentNode.children;
/* do stuff with data */
if(children.length > 0) {
jQuery.each(children, function(index, value) {
nodeStack.push(value);
});
}
答案 3 :(得分:0)
如果发生堆栈溢出,则递归运行得太深。您必须将算法重写为迭代(即使用for / while / foreach循环)构造。
答案 4 :(得分:0)
我能够按如下方式解决我的StackOverflow条件:
private static void processChildrenTransactions(AllTremorTransactionsVO parentBean, ArrayList<AllTremorTransactionsVO> childCandidatesList ) {
ArrayList<AllTremorTransactionsVO> childList = new ArrayList<AllTremorTransactionsVO>();
ArrayList<AllTremorTransactionsVO> childListTwo = new ArrayList<AllTremorTransactionsVO>();
for (AllTremorTransactionsVO childTransactions : childCandidatesList) {
childListTwo.add(childTransactions);
if (childTransactions.getParentGuid() != null) {
//gets a list of every trans with a child
if (childTransactions.getParentGuid().equalsIgnoreCase(parentBean.getTransactionGuid())){
childList.add(childTransactions);
childListTwo.remove(childTransactions);
}
}
}
parentBean.setChildTransactions(childList);
for (AllTremorTransactionsVO allTremorTransactionsVO : childList) {
processChildrenTransactions(allTremorTransactionsVO, childListTwo);
//processChildrenTransactions(allTremorTransactionsVO, childList);
}
return;
}
我现在拥有所有的孩子,但我正在努力将他们正确地分组。它们需要像这样列出:
父 --Child /父 - - 儿童 亲 --Child / Parnet ----父/子 ------儿童
等等。