【问题标题】:How to avoid stack overflow in deep tree recursion如何避免深度树递归中的堆栈溢出
【发布时间】:2011-08-15 22:20:47
【问题描述】:

我已经阅读了很多类似的文章,如果这已经得到回答,我很抱歉,但我仍然卡住了。

我正在编写一个函数来填充一棵树,每个节点都有四个分支,它们将存储对“八块拼图”状态的可能操作,即http://www.8puzzle.com/images/8_puzzle_start_state_a.png

由于手头问题的严重递归性质,我认为问题是堆栈溢出。

尾递归似乎是解决方案,但我不确定它是否相关/可能或如何在这种情况下实现它。代码如下:

void Tree::insert(string &initialState, const string &goalState, tree_node *&inNode){
cout<<"insert called"<<endl;
depth++;
cout<<depth<<endl;
string modState;
int zeroPos=0;

if(initialState==goalState){
    cout<<"*    *   *   GOAL    *   *   *"<<endl;
    getchar();
    exit(0);
}   

if(inNode==NULL){//is this the first node?

    inNode = new tree_node(initialState);       
    root=inNode;
    inNode->parent=NULL;
    insert(initialState, goalState, inNode);
}else{
    inNode->state = initialState;

    for(zeroPos=0;zeroPos<initialState.size();zeroPos++){//where is the empty tile?
        if(initialState[zeroPos]=='0'){
            break;
        }
    }
    //left
    if(zeroPos!=0 && zeroPos!=3 && zeroPos!=6){//can the empty tile move left?

        modState=initialState;
        modState[zeroPos]=modState[zeroPos-1];
        modState[zeroPos-1]='0';

        if(isOriginal(modState, inNode) ){//does this state already exist?

            cout <<"left  " << modState[0]<<modState[1]<<modState[2]<<endl;
            cout <<"left  " << modState[3]<<modState[4]<<modState[5]<<endl;
            cout <<"left  " << modState[6]<<modState[7]<<modState[8]<<endl;

            inNode->l = new tree_node(modState);    
            inNode->l->parent= inNode;
            if(inNode->l != NULL){
                insert(modState, goalState, inNode->l);
            }
        }
    }

    }
 }
}

【问题讨论】:

  • 我没有检查过你的代码,但是如果你的算法工作正常,如果你在 8-puzzle 上遇到堆栈溢出,我会很惊讶。
  • 也许所有状态的树不是最好的实现?
  • 我可能应该提到我打算运行各种搜索算法,找到到达目标状态的步骤,并记录它们在各个方面(时间、内存使用等)的效率。
  • @RemnantXO 为什么要在运行搜索算法之前创建状态树?
  • 嗯。是否有替代方法来运行它们?如果不将它们排列成某种结构,我想不出如何搜索这些状态。也许我只是非常愚蠢并且错过了显而易见的事情?

标签: c++ recursion tree stack-overflow


【解决方案1】:

这是一个非常通用的答案,但是您是否尝试过通过堆分配队列或堆栈之类的方式显式管理您的堆栈?基本上不使用实际的函数调用,只需从您自己的堆栈/队列中推送和拉取东西。它们涵盖了非递归图遍历算法here(深度优先和广度优先搜索)。

【讨论】:

    【解决方案2】:

    优化您的代码,即只保留您需要的那些节点。例如只保留叶节点(我的意思是那些你还没有展开的节点)。 是的,您可以在构建树的同时搜索树,编写一个函数来测量当前状态和目标状态之间的距离,这称为启发式。还有一个更好的算法可以解决8puzzle,叫做A*,建议你google一下。

    【讨论】:

    • 不是动态分配的节点存储在堆上吗?我将实现 A*,但我正在比较一系列搜索功能。
    • 是的,但是您可以删除已经展开的节点,即当您添加所有子节点时,删除节点本身。
    猜你喜欢
    • 1970-01-01
    • 2013-06-28
    • 1970-01-01
    • 2010-10-26
    • 2019-12-01
    • 1970-01-01
    • 2015-11-22
    • 2010-11-30
    • 2019-12-21
    相关资源
    最近更新 更多