【问题标题】:How are return results computed in a recursive function?如何在递归函数中计算返回结果?
【发布时间】:2016-09-15 11:02:20
【问题描述】:

到目前为止,我认为我理解了 return 是如何工作的,但是一旦我进入递归,我想我比最初想象的更迷茫。

假设,我有一个计数函数,计算一个字符在字符串中弹出多少次。

int frequency(char ch, string input, int pos) {
   if (pos == inputString.length()) {
      return 0;
   }

   if (inputString[pos] == ch) {
      return 1 + frequency(ch, inputString, pos + 1);
   }
   else {
      return frequency(ch, inputString, pos+1);
   }
}

如果我将字符串“Jeff”传递给它并寻找“f”,它会返回一个值2

那么,它如何知道何时停止?

  • return 0 是否以返回类型 int 结束任何方法?

  • 如果是这样,为什么当 final 返回返回 0 时,它仍然返回 2 的值?

【问题讨论】:

  • 如果pos > inputString.length() 是真的呢?
  • 那么它只会返回 0?显然,当我调用该方法时,我将 pos 参数传递给 0。字符串不能保存长度值 -1,可以吗?

标签: c++ recursion return


【解决方案1】:

最后一次返回

return 0;

只是递归过程中最后一次调用该函数。这是在某些时候停止递归所必需的。对于执行此最后一个其他返回语句之前的调用,例如:

return 1 + frequency(ch, inputString, pos + 1);

因此,0 与 1 和任何先前的递归结果相加。

PS: 只要函数返回语句再次调用该函数,递归就会继续。只有当 return 只是返回一些东西(没有再次调用函数)时,递归才会停止。

这里有一个更简单的例子,它计算所有整数的总和,直到 N:

int calcSum(int N){

    if ( N == 1 ) return 1;          // recursion stops here

    return N + calcSum( N-1 );       // otherwise continue to add up 

}

一个函数中的多个 return 语句对于递归来说并不特殊。该函数仅在遇到的第一个返回时返回。

【讨论】:

  • 调用0时,递归如何知道它已经完成?到目前为止,我遇到的任何方法都以返回方法结束,但是这个方法有多个返回。返回值 0 时返回类型为 int 的方法是否结束?另外,递归的回报是加法的吗?它们也可以是乘法或除法吗?
  • “当调用 0 时,递归如何知道它已经完成?” 这是在第一个 if() 语句的主体中完成的。它只是返回,而不添加另一个递归调用。
  • @tobi303 啊啊啊。我真的没有那样想。返回 0 有效地出现在递归之外。递归只有在不等于 strlen 时才会发生。一旦等于它,它就会返回 0,导致它不能继续递归。然后堆栈完成它们的处理,回到基本情况,然后将 0 添加到递归中返回的任何内容。
  • @JeffreyDilley 是的,以我为例,例如 calcSum(3) 的最终总和只有在对 calcSum(3) 的调用最终返回时才会得到,但要这样做,递归首先必须停止,这发生在电话calcSum(1)。只有当函数不再被调用时,堆栈才会被展开
  • @JeffreyDilley 可能是我的回答,它试图分解正在发生的事情,有助于使这种行为更清晰。
【解决方案2】:

那么,它如何知道何时停止?

当不再从递归调用函数的特定分支添加递归调用时,它将停止,调用堆栈将被清除,返回值与发出调用的相反顺序 (LIFO)。在这里完成:

if (pos == inputString.length()) {
    return 0;
}

任何其他分支都递归调用该函数,并在调用堆栈中下移一步:

if (inputString[pos] == ch) {
    return 1 + frequency(ch, inputString, pos + 1);
            // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
}
else {
    return frequency(ch, inputString, pos+1);
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
}
  • return 0; 是否结束任何返回类型为 int 的方法?

是的,它适用于任何可以用0初始化的返回类型

  • 如果是这样,为什么它仍然返回 2 的值,而最终返回是返回 0

因为递归调用的结果是在栈上累加的:

   return 1 + frequency(ch, inputString, pos + 1);
//          ^ the result of the operation will be saved on the stack when the call returns

...您会在驱动程序函数中看到(第一次)递归调用的最终结果。


顺便说一句,通过性能和内存使用来实现更便宜的实现将是一个简单的循环。无论如何,线性时间行为没有任何缺点:

int frequency(char ch, string input) {
   int result = 0;
   for(int pos = 0; pos < input.size(); ++pos) {
        if (input[pos] == ch) {
           ++result;
        }
    }
    return result;
}

【讨论】:

    【解决方案3】:

    将递归调用视为函数调用堆栈。在某些时候它可能会命中return 0; 这意味着堆栈上的函数调用之一已完成。因此,堆栈上的元素被弹出。函数的 final 返回发生在堆栈为空时。

    【讨论】:

    • 那么是的,a return 0 有效地“弹出”了一个堆栈,这是什么结束它?
    • @JeffreyDilley “结束是什么?” 当堆栈为空时,无法再弹出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 2021-09-01
    相关资源
    最近更新 更多