C ++ Stack Overflow异常,可能是由于递归造成的

时间:2018-02-13 20:16:20

标签: c++ recursion stack-overflow

我有一些正常工作的代码。但是,有时我的程序必须因错误而关闭。我试图调试此错误,但在执行此操作时遇到了一些问题。

当我在调试中运行时,我在启动程序后很快就会出现堆栈溢出错误,这比我在发布时出错时要快得多。

我缩小了调试时抛出错误的点,就是在第3570次调用此递归函数时。

void setRankAbove(vector<nodeStructure> &allNodes, int index, int rankToSet) {
    if (rankToSet>=allNodes[index].rank) {
        allNodes[index].rank = rankToSet;
        if (allNodes[index].root != index) {
            setRankAbove(allNodes, allNodes[index].parent, rankToSet + 1,debug);
        }           
    }
}

有关程序崩溃原因以及为什么它只会在调试中崩溃的任何想法?

无论如何,回到最初的问题,我已经缩小了失败的地方。

vector<vector<double>> backwardsAggregation(int inputRows, int inputCols, vector<vector<double>> &localCostsStepOne, vector<nodeStructure> &nodeMST,float sigma,bool debug) {
    // create 2D array of local costs step 2
    vector<double> localOneDim(inputCols);
    vector<vector<double>> localCostsRootToLeaf(inputRows, localOneDim);

    // factors defined in paper
    double nodeFactor = (1 - exp(-1 / (sigma*sigma)));
    double parentFactor = exp((double)(-0.5) / (sigma*sigma));
    cout << "Step 3.2.1" << endl;
    try{
        aggregateStepTwo(nodeMST, nodeMST[0].root, localCostsStepOne, localCostsRootToLeaf, parentFactor, nodeFactor, debug, 0);
    }
    catch (const std::exception & ex) {
        cout<< "exception"<< endl;
        cout << ex.what() << endl;
    }

    cout << "Step 3.2.2" << endl;
    return localCostsRootToLeaf;
}

在一定数量的调用后调用aggregateStepTwo时失败。它可能会递归地称它为1,000,000次。这是另一个堆栈溢出吗?

如果是这样,我如何摆脱堆栈溢出?

由于 罗布

1 个答案:

答案 0 :(得分:1)

你有尾递归。通过迭代算法替换这种递归通常非常简单。这是一种天真的方法,只是将递归重写为无限循环,在递归停止的相同位置中断。

void setRankAbove(vector<nodeStructure> &allNodes, int index, int rankToSet) {
  while (1) {
    if (rankToSet < allNodes[index].rank) {
      break;
    }
    allNodes[index].rank = rankToSet;
    if (allNodes[index].root == index) {
      break;
    }
    index = allNodes[index].parent;
    rankToSet++;
  }
}

这应该有用。

现在,如果您不喜欢break,可以从以下观察中获得更“优雅”的解决方案(值得商榷):

  1. 在第一次迭代中,分配仅取决于index
  2. 的值
  3. 每次后续迭代都取决于index的根以及涉及index的父级和rank+1的关系。
  4. 所以第一个看起来像一个特例。其他人依赖于涉及indexindex父母的相同表达。因此,如果我们将第一个案例排除在循环之外,我们将得到以下算法:

    void setRankAbove(vector<nodeStructure> &allNodes, int index, int rankToSet) {
      if (rankToSet < allNodes[index].rank) {
        return;
      }
    
      allNodes[index].rank = rankToSet++;
      int parent = allNodes[index].parent;
    
      while (allNodes[index].root != index && rankToSet >= allNodes[parent].rank) {
        index = parent;
        allNodes[index].rank = rankToSet++;
        parent = allNodes[index].parent;
      }
    }
    

    我真的很惊讶编译器没有自动将这种递归转换为循环。你是不是在编译优化标志,还是我对编译器的期望过高?