【问题标题】:While using recursive function calls when to use 'return'?在使用递归函数调用时何时使用'return'?
【发布时间】:2019-10-21 06:37:32
【问题描述】:

我很困惑在使用递归函数调用时何时使用“返回”。

我试图找到两个数字的“GCD(最大公约数)”。我实际上认为可行的是:

  include <stdio.h>
  int gcd (int a, int b);

  int main ()
  {
   int a, b;
   printf ("Enter two numbers \n");
   scanf ("%d %d", &a, &b);
   printf ("GCD for numbers %d and %d is %d\n", a, b, gcd(a,b));
   return (0);
   }

   int gcd (int a, int b)
   {
    while (a!=b)
     {
      if (a > b)
       gcd(a-b,b);
      else if (b > a)
       gcd(a,b-a);
     }
    return (a);
   }

但是上面的代码不断地从终端接受数字并且无法运行代码。

但是,当我按如下方式替换函数定义时,代码按预期工作,返回正确的值。

   int gcd (int a, int b)
   {
    while (a!=b)
     {
      if (a > b)
       return gcd(a-b,b);
      else if (b > a)
       return gcd(a,b-a);
     }
    return (a);
   }

如您所见,唯一的变化是在递归函数调用之前添加了“return”。为什么在我调用 gcd(arg1, arg2) 函数的两种情况下都需要返回?

【问题讨论】:

  • 与您的问题无关,但请考虑一下该循环......ab何时会改变,使条件改变?
  • 至于你的问题,你说函数应该返回一个int 值,但是你将从函数返回什么值?如果你想从一个函数中返回一个值,你需要一个显式的return 语句。

标签: c function recursion


【解决方案1】:

考虑到我调用 gcd(arg1, arg2) 函数的两种情况,为什么这里需要返回?

与其他任何时候调用函数并希望返回该函数调用返回的值的原因相同;因为调用它只会调用它,而不会对结果值做任何其他事情。

我很困惑在使用递归函数调用时何时使用“返回”。

return 用于递归调用,只要您将return 用于任何其他函数调用 - 即:何时以及因为该调用返回您希望这次返回的值。

想象一下我们有

#include "magic.h" /* defines gcd2(), which computes GCD in some mysterious way */

然后我们不进行递归调用,而是将一些工作委托给它:

/* Of course this solution also works, but is not interesting
int gcd(int a, int b)
{
    return gcd2(a, b);
} */

/* So, let's do something that actually shows off the recurrence relation */
int gcd(int a, int b)
{
    if (a > b)
        return gcd2(a-b, b);
    else if (b > a)
        return gcd2(a, b-a);
    else
        return a;
}

(我还删除了while 循环,因为它与算法无关;当然,在任何情况下都会达到return,这会打破循环。)

我假设我不需要复习数学理论;而且我认为很清楚为什么gcd2 结果需要return

但如何委派工作实际上并不重要;如果gcd 是一个正确计算GCD 的函数,并且gcd2 也是这样,那么对gcd2 的调用可能会被对gcd 的调用替换。这就是秘密 - 递归调用函数与正常调用函数实际上并没有什么不同。只是考虑到这种可能性,需要更清楚地了解调用函数的工作原理和实际作用。


当然,也可以充分利用原始的while 循环——在递归之前 尽可能多地减去。这可能看起来像:

int gcd(int a, int b)
{
    if (a > b)
        while (a > b)
            a -= b; /* prepare a value for the recursion. */
        return gcd(a, b); /* and then recurse with that value. */
    else if (b > a)
        while (b > a)
            b -= a; /* similarly. */
        return gcd(a, b);
    else /* a == b */
        return a;        
}

但那我们不妨一路走下去,转为迭代法:

int gcd(int a, int b)
{
    while (a != b)
        /* whichever is greater, adjust it downward, leaving an (a, b)
           pair that has the same GCD. Eventually we reach an equal pair,
           for which the result is known. */
        if (a > b)
            a -= b;
        else
            b -= a;
    return a; /* since the loop exited, they are equal now. */
}

(我们也可以做模运算来一次完成多个减法;这留作练习。)

【讨论】:

  • 这可能比它需要的要长很多——很难在解释问题和一般解释递归之间找到正确的分界点。另外,我已经很久没有写任何C代码了,所以肯定有什么地方出错。
  • 我认为你需要一些大括号。
【解决方案2】:

第一个 gcd 函数“尝试”计算 gcd,但最后总是返回 a 不变。

第二个 gcd 函数递归计算 gcd,每次调用都返回一个 gcd。

【讨论】:

  • 从技术上讲,如果a 不等于b,第一个变体根本不会返回。
  • 我们来看一个例子; gcd(9,12) -> gcd (9,3) -> gcd (6,3) -> gcd (3,3)。我在这里退出 while 循环(当我到达函数调用 gcd(3,3) 时),然后返回值 '3'。即使在我不使用 return 的第一种情况下,这也不应该改变吗?
  • @SaideepPavuluri 如果没有return 语句,您不会“跳出循环”。是什么让你认为你的循环会结束?
  • @SaideepPavuluri 就像我之前说的,要从一个函数返回,它需要结束。通过结束 } 或使用明确的 return 语句。在您的示例中,您递归到 `gcd (3,3)`,它将返回(因为条件 a != b 为 false 并且循环永远不会发生)但随后您返回到 gcd (6,3) 调用,其中 a != balways 是真的,循环永远不会结束,并且永远继续调用gcd (3,3)
  • @SaideepPavuluri 你真的需要学习如何使用调试器来单步调试你的代码(并进入函数调用),然后你就可以很容易地看到这种情况发生。
猜你喜欢
  • 1970-01-01
  • 2020-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 1970-01-01
  • 2013-11-06
  • 1970-01-01
相关资源
最近更新 更多