【问题标题】:Unexpected error for recursive collatz implementation递归 collat​​z 实现的意外错误
【发布时间】:2017-03-06 16:00:18
【问题描述】:

编辑:当我将代码上传到自动测试平台时,程序不会在那里崩溃 - 它会返回正确的结果,但需要的时间太长(超过 5 秒)... wtf...强>

对于大学,我必须通过遵循 collat​​z 猜想来实现一个函数,该函数返回从输入达到 1 的步数。猜想很简单——给定任意整数:

1. 如果是偶数 - 除以二 (n/2)

2. 如果是奇数 - 乘以 3 并加一 (n*3+1)

猜想是所有数字最终都会达到1。我们不必证明或检查这一点,我们只需要返回对给定数字采取的步骤即可。

我们以前做过这个问题,但这次我们必须检查更大的数字(他们指定使用 long 而不是 int)AND 使用递归。他们给了我们框架代码,并要求我们只实现函数 - 所以我所有的代码都包含在里面

int lengthCollat​​z(long n) { //mycode }

main中的骨架代码收集两个输入值——a和b,其中a

我添加的函数似乎工作得很好,但是在较大的值(当输入 2 以百万计时)它似乎无缘无故崩溃并且没有给出错误。我已经尝试将所有内容更改为 unsigned longs 甚至 long longs 以查看是否有溢出 - 在这种情况下,程序就会卡住......我不明白出了什么问题,请帮我诊断错误。附言如何提高这些计算的速度?我们有 5 秒的限制。

我所有的代码都在 lengthCollat​​z 函数内(以及它上面的 length 全局变量)你能找出问题所在吗?

#include <stdio.h>
#define MAX64 9223372036854775807L /* 2ˆ63 -1 */

int length = 0;

int lengthCollatz(long n) {
    length++;
    //if not 1
    if(n!=1){
        //if odd
        if(n&1) {
            lengthCollatz(n=n*3+1);
        }
        //if even
        else {
            lengthCollatz(n/=2);
        }

    }
    //if reached n = 1
    else {
        //return amount of steps taken
        int returnLength  = length;
        length = 0;
        return returnLength;
    }
}
int main(int argc, char *argv[])
{

int n, a, b, len=-1;

scanf ("%d %d", &a, &b);

while (a <= b) {

    int l = lengthCollatz(a);
        if (l > len) {
            n = a;
            len = l;
        }
        a++;
}
printf("%d\n", n);
return 0;
}

更新功能:

int lengthCollatz(long n) {
        if(n==1){
            //return depthRecursion;
        }
        else {
            if(n&1) {
                n=n*3+1;
            }
            else {
                n/=2;
            }
            return lengthCollatz(n);
        }
}

【问题讨论】:

  • 尝试通过调试器运行您的代码。它可能崩溃的唯一原因是由于递归太深导致的堆栈溢出。有时它会在没有消息的情况下退出,除非您使用调试器。
  • 您的递归调用也不需要n=n*3 + 1n /= 2。只需使用n*3 + 1n/2
  • 你确定你应该使用递归吗?当您没有很好地处理所需的递归深度时,这只是在自找麻烦。
  • 在任何情况下,使用文件范围变量来帮助您跟踪递归深度是不必要的,而且我有理由相信这不是您的讲师希望您做的事情。我认为这与您的问题无关,但我建议您考虑如何在不依赖任何文件范围变量的情况下执行计算。
  • 您的递归调用忽略了函数的返回值。并不是所有的控制路径都返回一个值。您是否启用了编译器警告?

标签: c collatz


【解决方案1】:

这是一个替代版本,它不会对 OP 给出的输入范围进行段错误:

int collatz(unsigned long n)
{
    if (n == 1)
        return 1;
    else if (n & 1) 
        return 1 + collatz(n * 3 + 1);
    else
        return 1 + collatz(n >> 1);
}

AFAICT,它工作正常,但速度很慢。在我平庸的 PC 上 29 秒。当可以预先计算结果时,优化的版本通过不调用自身来快两秒,但该版本接近手动循环展开。 FWIW:

int collatz(unsigned long n)
{
    if (n == 1)
        return 1;

    if (n & 1) 
        return 2 + collatz((n * 3 + 1) >> 1);

    // Is n dividable by 16?
    if (n & 0xF == 0)
        return 4 + collatz(n >> 4);

    // Is n dividable by 8?
    if (n & 0x7 == 0)
        return 3 + collatz(n >> 3);

    // Is n dividable by 4?
    if (n & 0x3 == 0)
        return 2 + collatz(n >> 2);

    return 1 + collatz(n >> 1);
}

当然还有其他方法可以解决这个问题,但要在五秒内完成?如果您找到解决方案,请发布解决方案。

【讨论】:

  • 嘿,我刚刚尝试运行第一个函数,但程序仍然在 1m+ 范围内崩溃......虽然你编写的逻辑非常令人印象深刻和有趣!我不太明白。我的逻辑是使用递归直到数字达到 1,然后打印递归深度。您不会在任何地方跟踪递归的深度,但我想是 +1 以某种方式做到了这一点。你能解释一下这是如何/为什么起作用的吗?感谢回复
  • 很高兴你喜欢它 :) 你能满足五秒的要求吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 2014-07-07
  • 1970-01-01
相关资源
最近更新 更多