【问题标题】:Recursive function building a vector, what will be returned?递归函数构建一个向量,会返回什么?
【发布时间】:2014-05-22 03:42:45
【问题描述】:

所以我试图递归地构建一个向量,当我看到这个时,我开始认为我做错了。以下代码是否会在每次迭代结果中返回一个向量,或者我只是在每次迭代中创建新向量,而实际上不会在每个递归调用上构建。如果我错了,我该如何递归地构建向量...在此先感谢您的建设性帮助!

std::vector<ParameterClass> recursiveParser :: parseParamList()
{
  std::vector<ParameterClass> paramVector;

  if (lexicator->getCurrentToken()->getTokenType() == STRING) {

    paramVector.push_back(ParameterClass(*lexicator->getCurrentToken()));
    lexicator->advance();
    parseParamList();

  } else if (lexicator->getCurrentToken()->getTokenType() == ID) {

    paramVector.push_back(ParameterClass(*lexicator->getCurrentToken()));
    lexicator->advance();
    parseParamList();

  } else {

  // so as to not fail in Expression, i need to check to see that there is a
  // left paren indicating that there should be an expression

    if (lexicator->getCurrentToken()->getTokenType() == LEFT_PAREN) {
      paramVector.push_back(ParameterClass(parseExpression()));
      lexicator->advance();
      parseParamList();
    }
  }
  return paramVector;
}

【问题讨论】:

  • 问题是什么?
  • 为什么不将第一个和第二个条件合二为一呢?看起来多余

标签: c++ recursion vector construction


【解决方案1】:

如果您想递归地构建一个列表(向量等),请使用以下模式:

private:
    void InternalBuild(std::vector<OutputData> & vec)
    {
        // Add data to vec
        // Possibly call recursively InternalBuild(vec);
    }

public:
    std::vector<OutputData> RecursiveBuild()
    {
        std::vector<OutputData> vec;
        InternalBuild(vec);
        return vec;
    }

值得注意的是,您似乎在这里误用了递归。递归旨在用于数据结构,这些数据结构本质上是递归的(树、图等)。在这种情况下,您递归地处理线性数据 - 为什么不简单地编写如下内容:

while (!lexer.endOfExpression())
{
    // Process token

    lexer.Advance();
}

在你的情况下,如果你得到足够长的表达式,你最终会出现堆栈溢出异常,因为你的程序将耗尽堆栈内存。如果你线性实现这个算法就不会发生这种情况。

【讨论】:

  • 感谢您的意见!你对这个问题的线性度是正确的,但是我有程序的其他部分本质上是递归的,我只是对我的类进行了相同的建模。
  • 我用你解释的方法重新编写了我的递归调用,这很有意义,而且效果很好!
  • @M_J 很高兴我能帮上忙 :)
  • 通过递归调用传递向量引用是否有任何性能损失?
  • @KevinLeeGarner 如果你通过引用传递std::vector(就像我一样),在内部它等于传递一个指针(4 个字节),所以这既不是内存也不是时间成本。
【解决方案2】:

试试这个,它附加递归调用的结果

    std::vector<ParameterClass> recursiveParser :: parseParamList()
 {
std::vector<ParameterClass> paramVector;
if(lexicator->getCurrentToken()->getTokenType() == STRING)
{
    paramVector.push_back(ParameterClass(*lexicator->getCurrentToken()));
    lexicator->advance();
    std::vector<ParameterClass> result = parseParamList();
    std::copy(result.begin(), result.end(), std::back_inserter(paramVector));
}
else
    if(lexicator->getCurrentToken()->getTokenType() == ID)
    {
        paramVector.push_back(ParameterClass(*lexicator->getCurrentToken()));
        lexicator->advance();
        std::vector<ParameterClass> result = parseParamList();
        std::copy(result.begin(), result.end(), std::back_inserter(paramVector));
    }else
    {
        // so as to not fail in Expression, i need to check to see that there is a left paren indicating that there should be an expression
        if(lexicator->getCurrentToken()->getTokenType() == LEFT_PAREN)
        {
            paramVector.push_back(ParameterClass(parseExpression()));
            lexicator->advance();
            std::vector<ParameterClass> result = parseParamList();
            std::copy(result.begin(), result.end(), std::back_inserter(paramVector));
        }
    }
return paramVector;
 }

也请使用switch代替if-elseif-elseif,避免重复代码

std::vector<ParameterClass> recursiveParser :: parseParamList()
{
    std::vector<ParameterClass> paramVector;

    switch(lexicator->getCurrentToken()->getTokenType())
    {
    case STRING:
        paramVector.push_back(ParameterClass(*lexicator->getCurrentToken()));
        break;
    case ID:
        paramVector.push_back(ParameterClass(*lexicator->getCurrentToken()));
        break;
    case LEFT_PAREN: // so as to not fail in Expression, i need to check to see that there is a left paren indicating that there should be an expression
        paramVector.push_back(ParameterClass(parseExpression()));
        break;
    }
    lexicator->advance();
    std::vector<ParameterClass> result = parseParamList();
    std::copy(result.begin(), result.end(), std::back_inserter(paramVector));
    return paramVector;
}

但使用@Spook 的模式,因为它允许尾调用优化

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 2013-10-10
    • 2021-12-23
    • 1970-01-01
    相关资源
    最近更新 更多