【问题标题】:tail recursion on double factorial equation in CC中双因子方程的尾递归
【发布时间】:2020-04-12 13:44:00
【问题描述】:

我在实现以下问题的尾递归解决方案时遇到了困难:

双阶乘还有一个递归关系,也依赖于阶乘,就是上面的:(for n

我必须实现这个方程的递归关系-我按照上面的代码所做的工作

long long factorial(int n) {
    if (n < 0)
        return 0;
    if (n < 1)
        return 1;

     return n * factorial(n - 1);
}

long long doublefactorial(int n) {
    if (n < 0)
        return 0;
    if (n < 2)
        return 1;
    return factorial(n) / doublefactorial(n - 1);
}

现在我必须使用 尾递归 来解决同样的问题。有人可以告诉我如何做到这一点,因为我无法弄清楚。 (也不需要以尾递归的方式实现阶乘函数)

测试用例:

  • 5!! = 15
  • 10!! = 3840
  • 18!! = 185,794,560
  • -10!! = 0

【问题讨论】:

  • 向我们展示你对尾递归的尝试
  • 我建议你先尝试阶乘函数的尾递归版本(这在互联网上既容易又容易找到)
  • @muyustan 他们要求我们仅从 n=0 到 n=20 实施
  • @nicomp 我没有尝试过,因为我不知道该怎么做,我知道我需要向函数添加更多变量但不知道如何将其变成尾递归。
  • n!! = n(n-2)(n-4) ...(1 或 2,取决于 n 是奇数还是偶数)。所以一个计算 n 的尾递归函数!看起来几乎与 n! 相同。

标签: c tail-recursion


【解决方案1】:

这是阶乘函数的尾递归版本:

long factorial(int n, int factor)
{
    if (n == 0)
        return factor;

    return factorial(n-1, factor * n);
}

factorial(5, 1); // 120

这是一个逻辑更简单的尾递归双阶乘:

long doublefactorial(int n, int factor)
{
    if (n < 0)
        return 0;
    if (n < 2)
        return factor;

    return doublefactorial(n-2, factor * n);
}

printf("%d ", doublefactorial(5,1)); // 15
printf("%d ", doublefactorial(10,1)); // 3840
printf("%d ", doublefactorial(18,1)); // 185794560 

【讨论】:

  • 我知道如何对常规阶乘进行尾递归,但我不知道对我提出的问题进行尾递归,所以如果你知道这会有所帮助。
  • 在我看来,对这个问题的任何有用答案都可以解释为什么提供的版本是尾递归的。
  • 尾递归函数只是一个递归函数,它返回没有其他操作的递归调用(不乘/加/除任何值)。
  • 伙计,看看我发布的方程,我也知道如何制作尾阶乘和尾双阶乘分离,我如何制作我的方程的尾递归
【解决方案2】:

如果你稍微扩展你的数学,你会发现阶乘函数结果在最终结果的分子和分母之间迭代。

所以这段代码将在 Python 中执行此操作

def _factorial(n, m):
    if n < 0:
        return 0
    elif n == 0:
        return 1.0 * m
    return _factorial(n - 1, n * m)

def factorial(n):
    return _factorial(n, 1)

def _doublefactorial(n, m, is_even):
    if n < 0:
        return 0
    elif n < 2:
        return 1.0 * m

    if is_even:
        m *= factorial(n)
    else:
        m /= factorial(n)

    return _doublefactorial(n - 1, m, (not is_even))

def doublefactorial(n):
    return _doublefactorial(n, 1, True)

在 C 中:

unsigned int _factorial(const unsigned int n, const unsigned int m) {
    if (n < 0) {
        return 0;
    } else if (n == 0) {
        return m;
    }
    return _factorial(n - 1, n * m);
}

unsigned int factorial(const unsigned int n) {
    return _factorial(n, 1);
}

double _doublefactorial(const unsigned int n, const double m, const char is_even) {
    double value = m;

    if (n < 0) {
        return 0;
    } else if (n < 2) {
        return m;
    }

    if (is_even) {
        value *= factorial(n);
    } else {
        value /= factorial(n);
    }

    return _doublefactorial(n - 1, value, !is_even);
}

double doublefactorial(const unsigned int n) {
    return _doublefactorial(n, 1, 1);
}

【讨论】:

    【解决方案3】:

    你对这个double factorial函数的定义不完整:你需要一个初始值,比如0!! = 1。从递归定义看来,p!! 是从 1 到 pp 具有相同奇偶性的所有数字的乘积:

    • 5!! = 1 * 3 * 5 = 15
    • 6!! = 2 * 4 * 6 = 48
    • 10!! = 2 * 4 * 6 * 8 * 10 = 3840

    由于整数类型的有限范围和阶乘函数的指数增长,通过计算阶乘并除以前一个数字的双阶乘的结果来计算双阶乘对于大于 19 的数字将失败。双阶乘也增长很快,但其对数的增长速度是阶乘函数的一半。

    这是一个递归函数:

    unsigned long long doublefactorial(int n) {
        if (n < 0)
            return 0;
        if (n < 2)
            return 1;
        return n * doublefactorial(n - 2);
    }
    

    这是一个带有辅助函数的尾递归实现:

    unsigned long long doublefactorial_helper(int n, unsigned long long res) {
        if (n < 2)
            return res;
        return doublefactorial(n - 2, res * n);
    }
    
    unsigned long long doublefactorial(int n) {
        return doublefactorial_helper(n, n >= 0);
    }
    

    将第一个函数转换为尾递归函数的技巧不是等待结果然后乘以n,而是将更新的中间结果传递给递归函数。乘法以相反的顺序执行,但会产生相同的结果(即使模 ULLONG_MAX+1)。

    【讨论】:

      猜你喜欢
      • 2012-03-22
      • 2011-02-11
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 2016-03-21
      相关资源
      最近更新 更多