【问题标题】:How to change code, to create a recursive function如何更改代码,创建递归函数
【发布时间】:2019-07-16 15:24:51
【问题描述】:

我参加了一门名为 CS50 的课程。我最近一直在学习递归函数,虽然我创建了一个名为 Collat​​z 的程序,它可以完成我想要它做的事情,但它内部没有递归函数,因为该函数不会调用自身。我被卡住了,我想不通,我应该如何实现一个递归函数,让它看起来整洁干净并调用自己。

我试图在我的主要功能旁边实现一个功能。但是我不知道那个函数应该是什么样子,它是如何调用自己的。

//int x(int n);

int main(void)
{
    int n;
    //j is a counter for the number of times 'n' has to be calculated to get n==1
    int j = 0;

    //Ask for an integer
    printf("Int: ");
    scanf("%i", &n);

    //Check for 0 or less
    if (n <= 0)
    {
        printf("ERROR.")
        return 1;
    }

    //This is where recursion should be implemented
    while (n != 1)
    {
        if (n % 2 != 0)
        {
            while ((n % 2) != 0)
            {
                n = 3*n + 1 ;
                j++;
            }
        }
        else if ((n % 2) == 0)
        {
            while (n != 1)
            {
                n /= 2;
                j++;
            }
        }
    }
    printf("N: %i, number of times: %i \n", n,j);
}

/*
int x(int n)
{
    Should a recursive function be implemented here?
}
*/

输出正常。 输出应该是数字 n,它应该始终为 1,因此要证明程序有效并始终到达数字 1,以及从 n 到 1 需要多少步。

【问题讨论】:

  • 提示:将循环转换为递归有时会非常棘手。采用 Collat​​z 问题的原始公式并将其直接写为递归要简单得多。这要简单得多。
  • 其他提示:为了熟悉递归,把阶乘函数写成递归函数。
  • 提示:您的代码中真的需要内部 while 循环吗?

标签: c function recursion cs50


【解决方案1】:

给你。:)

#include <stdio.h>

unsigned int collatz( unsigned int n )
{
    return n < 2 ? 0 : 1 + collatz( n % 2 == 0 ? n / 2 : 3 * n + 1 );
}

int main(void) 
{
    while ( 1 )
    {
        unsigned int n;

        printf( "Enter a non-negative number (0 - exit): " );

        if ( scanf( "%u", &n ) != 1 || n == 0 ) break;

        printf( "The number of steps is %u\n\n", collatz( n ) );
    }

    return 0;
}

程序输出可能看起来像

Enter a non-negative number (0 - exit): 19
The number of steps is 20

Enter a non-negative number (0 - exit): 0

【讨论】:

    【解决方案2】:

    对于这样的事情,我建议使用一个递归函数,它返回使 n 等于 1 所花费的时间,因为这确实是您想要跟踪的全部内容。由于您尝试进行递归的代码是一个循环,因此可以相对容易地找到您的基本情况(或退出条件)将是什么。在这种情况下,它将是当 n == 1 时。所以这条线索是我们拥有这样的东西

    int recursive_function(int n) {
        if (n == 1) {
            return 0;
        }
    }
    

    现在我们需要关注逻辑,为了跟踪函数运行的次数(本质上是 j),我们应该让函数返回它运行的次数,那么这将使它成为更容易跟踪。因此,为此我们将向函数添加另一个返回语句,并使其再次运行,因为我们已经设置了退出条件来告诉我们何时停止。之后你只需要添加逻辑,但我们最终应该是这样的:

    int recursive_function(int n) {
        if (n == 1) {
            return 0;
        } else if (n % 2 != 0 ) {
            n = 3 * n + 1 ;
        } else if (n % 2 == 0) {
            n /= 2;
        }
        return 1 + recursive_function(n);
    }
    

    【讨论】:

      【解决方案3】:

      好吧,既然您不知道递归函数可能是什么样子,也不知道它应该如何调用自己,这里有一个简单的示例。

      int fact(int n)
      {
        if (n == 0) // this is the stopping case
          return 1;
        else
          return n * fact(n-1)); // this is what makes the function recursive
      }
      

      在这个例子中,我们正在计算一个数字的阶乘。我们需要有一个分支,这样当我们知道什么时候应该停止调用该函数时。这个递归函数本质上是一样的:

      for (int i = 0; i < n; i ++)
      {
        result = result * i;
      }
      

      让函数递归意味着它摆脱了循环。我鼓励您从最外层​​的 while 循环开始,并确定如何通过在代码的各个部分实现一些返回函数以使其递归来消除它。作为提示,您应该有以下 if 声明:

      if (n != 1)
        return /* whatever is fit for your stopping case, should be an integer */
      

      使用递归函数需要注意的另一件重要事情是,当您调用函数本身时,输入需要更改。我的意思是,你不应该有这样的功能:

      int x(int n)
      {
        if (n == 0)
          return 1;
        else
          return x(n);
      }
      

      输入相同的数字并且没有return x(n-1) 之类的内容将创建一个无限循环,因为没有办法到达停止状态,除非输入的原始数字到达停止状态。

      当然,您也可以通过递归调用添加更多计算,并编写类似return 7 * x(n) / 2; 的内容。许多初学者在学习递归函数时经常忘记这一点,只想为他们的返回语句写return x(n-2);之类的东西。

      在您的情况下,“停止情况”似乎应该是if (n == 1)

      希望这足以让您入门!

      【讨论】:

      • 你的意思是在你的第一个例子中返回n * fact(n - 1)
      猜你喜欢
      • 2021-10-10
      • 2019-03-01
      • 2019-08-07
      • 1970-01-01
      • 1970-01-01
      • 2015-03-14
      • 1970-01-01
      • 2014-10-23
      相关资源
      最近更新 更多