您将如何编写非递归算法来计算阶乘?

发布于 2024-07-08 20:22:58 字数 38 浏览 7 评论 0原文

您将如何编写非递归算法来计算 n!

How would you write a non-recursive algorithm to compute n!?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(22

悍妇囚夫 2024-07-15 20:22:58

因为 Int32 在任何大于 12 的数据上都会溢出! 不管怎样,只要这样做:

public int factorial(int n) {
  int[] fact = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 
                362880, 3628800, 39916800, 479001600};
  return fact[n];
}

Since an Int32 is going to overflow on anything bigger than 12! anyway, just do:

public int factorial(int n) {
  int[] fact = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 
                362880, 3628800, 39916800, 479001600};
  return fact[n];
}
生活了然无味 2024-07-15 20:22:58

在伪代码中

ans = 1
for i = n down to 2
  ans = ans * i
next

in pseudocode

ans = 1
for i = n down to 2
  ans = ans * i
next
时光沙漏 2024-07-15 20:22:58

为了科学的利益,我对计算阶乘的算法的各种实现进行了一些分析。 我用 C# 和 C++ 创建了每种方法的迭代、查找表和递归实现。 我将最大输入值限制为 12 或更少,因为是 13! 大于 2^32(32 位 int 所能容纳的最大值)。 然后,我运行每个函数 1000 万次,循环遍历可能的输入值(即将 i 从 0 增加到 1000 万次,使用 i 模 13 作为输入参数)。

以下是标准化为迭代 C++ 数字的不同实现的相对运行时间:

            C++    C#
---------------------
Iterative   1.0   1.6
Lookup      .28   1.1
Recursive   2.4   2.6

并且,为了完整起见,以下是使用 64 位整数并允许输入值最多 20 的实现的相对运行时间:

            C++    C#
---------------------
Iterative   1.0   2.9
Lookup      .16   .53
Recursive   1.9   3.9

In the interests of science I ran some profiling on various implementations of algorithms to compute factorials. I created iterative, look up table, and recursive implementations of each in C# and C++. I limited the maximum input value to 12 or less, since 13! is greater than 2^32 (the maximum value capable of being held in a 32-bit int). Then, I ran each function 10 million times, cycling through the possible input values (i.e. incrementing i from 0 to 10 million, using i modulo 13 as the input parameter).

Here are the relative run-times for different implementations normalized to the iterative C++ figures:

            C++    C#
---------------------
Iterative   1.0   1.6
Lookup      .28   1.1
Recursive   2.4   2.6

And, for completeness, here are the relative run-times for implementations using 64-bit integers and allowing input values up to 20:

            C++    C#
---------------------
Iterative   1.0   2.9
Lookup      .16   .53
Recursive   1.9   3.9
山有枢 2024-07-15 20:22:58
public double factorial(int n) {
    double result = 1;
    for(double i = 2; i<=n; ++i) {
        result *= i;
    }
    return result;
}
public double factorial(int n) {
    double result = 1;
    for(double i = 2; i<=n; ++i) {
        result *= i;
    }
    return result;
}
饮惑 2024-07-15 20:22:58

将递归解决方案重写为循环。

Rewrite the recursive solution as a loop.

梦幻的心爱 2024-07-15 20:22:58

除非像 Python 中那样有任意长度的整数,否则我会将 Factorial() 的预先计算值存储在大约 20 个长整型的数组中,并使用参数 n 作为索引。 n! 的增长率 比较高,计算20! 或21! 无论如何,即使在 64 位机器上,你也会遇到溢出。

Unless you have arbitrary-length integers like in Python, I would store the precomputed values of factorial() in an array of about 20 longs, and use the argument n as the index. The rate of growth of n! is rather high, and computing 20! or 21! you'll get an overflow anyway, even on 64-bit machines.

分開簡單 2024-07-15 20:22:58

这是预先计算的函数,但实际上是正确的。 正如前面所说,13! 溢出,因此计算这么小的值范围是没有意义的。 64 位更大,但我希望这个范围仍然相当合理。

int factorial(int i) {
    static int factorials[] = {1, 1, 2, 6, 24, 120, 720, 
            5040, 40320, 362880, 3628800, 39916800, 479001600};
    if (i<0 || i>12) {
        fprintf(stderr, "Factorial input out of range\n");
        exit(EXIT_FAILURE); // You could also return an error code here
    }
    return factorials[i];
} 

资料来源:http://ctips.pbwiki.com/Factorial

Here's the precomputed function, except actually correct. As been said, 13! overflows, so there is no point in calculating such a small range of values. 64 bit is larger, but I would expect the range to still be rather reasonable.

int factorial(int i) {
    static int factorials[] = {1, 1, 2, 6, 24, 120, 720, 
            5040, 40320, 362880, 3628800, 39916800, 479001600};
    if (i<0 || i>12) {
        fprintf(stderr, "Factorial input out of range\n");
        exit(EXIT_FAILURE); // You could also return an error code here
    }
    return factorials[i];
} 

Source: http://ctips.pbwiki.com/Factorial

瞳孔里扚悲伤 2024-07-15 20:22:58
long fact(int n) {
    long x = 1;
    for(int i = 1; i <= n; i++) {
        x *= i;
    }
    return x;
}
long fact(int n) {
    long x = 1;
    for(int i = 1; i <= n; i++) {
        x *= i;
    }
    return x;
}
汹涌人海 2024-07-15 20:22:58
int total = 1
loop while n > 1
    total = total * n
    n--
end while
int total = 1
loop while n > 1
    total = total * n
    n--
end while
还不是爱你 2024-07-15 20:22:58

我喜欢 pythonic 解决方案:

def fact(n): return (reduce(lambda x, y: x * y, xrange(1, n+1)))

I love the pythonic solution to this:

def fact(n): return (reduce(lambda x, y: x * y, xrange(1, n+1)))
生寂 2024-07-15 20:22:58
fac = 1 ; 
for( i = 1 ; i <= n ; i++){
   fac = fac * i ;
}
fac = 1 ; 
for( i = 1 ; i <= n ; i++){
   fac = fac * i ;
}
新人笑 2024-07-15 20:22:58
public int factorialNonRecurse(int n) {
    int product = 1;

    for (int i = 2; i <= n; i++) {
        product *= i;
    }

    return product;
}
public int factorialNonRecurse(int n) {
    int product = 1;

    for (int i = 2; i <= n; i++) {
        product *= i;
    }

    return product;
}
南城追梦 2024-07-15 20:22:58

在运行时这是非递归的。 在编译时它是递归的。 运行时性能应为 O(1)。

//Note: many compilers have an upper limit on the number of recursive templates allowed.

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}

At run time this is non-recursive. At compile time it is recursive. Run-time performance should be O(1).

//Note: many compilers have an upper limit on the number of recursive templates allowed.

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}
叫嚣ゝ 2024-07-15 20:22:58

对于非递归方法,没有比这更简单的了

int fac(int num) {
    int f = 1;
    for (int i = num; i > 0; i--)
        f *= i;
    return f;
}

For a non-recursive approach, it can't get simpler than this

int fac(int num) {
    int f = 1;
    for (int i = num; i > 0; i--)
        f *= i;
    return f;
}
素染倾城色 2024-07-15 20:22:58

伪代码

total = 1
For i = 1 To n
    total *= i
Next

Pseudo code

total = 1
For i = 1 To n
    total *= i
Next
离旧人 2024-07-15 20:22:58

假设您希望能够处理一些非常大的数字,我将按如下方式编码。 如果您希望在常见情况下(低数字)有足够的速度,但希望能够处理一些超繁重的计算,则可以使用此实现。 我认为这是理论上最完整的答案。 在实践中,我怀疑除了家庭作业问题之外,您是否需要计算如此大的阶乘

#define int MAX_PRECALCFACTORIAL = 13;

public double factorial(int n) {
  ASSERT(n>0);
  int[MAX_PRECALCFACTORIAL] fact = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 
                362880, 3628800, 39916800, 479001600};
  if(n < MAX_PRECALCFACTORIAL)
    return (double)fact[n];

  //else we are at least n big
  double total = (float)fact[MAX_PRECALCFACTORIAL-1]
  for(int i = MAX_PRECALCFACTORIAL; i <= n; i++)
  {
    total *= (double)i;  //cost of incrimenting a double often equal or more than casting
  }
  return total;

}

assuming you wanted to be able to deal with some really huge numbers, I would code it as follows. This implementation would be for if you wanted a decent amount of speed for common cases (low numbers), but wanted to be able to handle some super hefty calculations. I would consider this the most complete answer in theory. In practice I doubt you would need to compute such large factorials for anything other than a homework problem

#define int MAX_PRECALCFACTORIAL = 13;

public double factorial(int n) {
  ASSERT(n>0);
  int[MAX_PRECALCFACTORIAL] fact = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 
                362880, 3628800, 39916800, 479001600};
  if(n < MAX_PRECALCFACTORIAL)
    return (double)fact[n];

  //else we are at least n big
  double total = (float)fact[MAX_PRECALCFACTORIAL-1]
  for(int i = MAX_PRECALCFACTORIAL; i <= n; i++)
  {
    total *= (double)i;  //cost of incrimenting a double often equal or more than casting
  }
  return total;

}
秋意浓 2024-07-15 20:22:58

我会使用记忆法。 这样,您可以将该方法编写为递归调用,并且仍然可以获得线性实现的大部分好处。

I would use memoization. That way you can write the method as a recursive call, and still get most of the benefits of a linear implementation.

只为一人 2024-07-15 20:22:58
long fact(int n)
{
    long fact=1;
    while(n>1)
      fact*=n--;
    return fact;
}

long fact(int n)
{
   for(long fact=1;n>1;n--)
      fact*=n;
   return fact;
}
long fact(int n)
{
    long fact=1;
    while(n>1)
      fact*=n--;
    return fact;
}

long fact(int n)
{
   for(long fact=1;n>1;n--)
      fact*=n;
   return fact;
}
很快妥协 2024-07-15 20:22:58

迭代:

int answer = 1;
for (int i = 1; i <= n; i++){
    answer *= i;
}

或者...在 Haskell 中使用尾递归:

factorial x =
    tailFact x 1
    where tailFact 0 a = a
        tailFact n a = tailFact (n - 1) (n * a)

在这种情况下尾递归的作用是使用累加器来避免堆栈调用上的堆积。

参考:Haskell 中的尾递归

Iterative:

int answer = 1;
for (int i = 1; i <= n; i++){
    answer *= i;
}

Or... using tail recursion in Haskell:

factorial x =
    tailFact x 1
    where tailFact 0 a = a
        tailFact n a = tailFact (n - 1) (n * a)

What tail recursion does in this case is uses an accumulator to avoid piling on stack calls.

Reference: Tail Recursion in Haskell

情未る 2024-07-15 20:22:58

Java 中的非递归阶乘。 该解决方案使用自定义迭代器(以演示迭代器的使用:))。

/** 
 * Non recursive factorial. Iterator version,
 */
package factiterator;

import java.math.BigInteger;
import java.util.Iterator;

public class FactIterator
{   
    public static void main(String[] args)
    {
        Iterable<BigInteger> fact = new Iterable<BigInteger>()
        {
            @Override
            public Iterator<BigInteger> iterator()
            {
                return new Iterator<BigInteger>()
                {
                    BigInteger     i = BigInteger.ONE;
                    BigInteger total = BigInteger.ONE;

                    @Override
                    public boolean hasNext()
                    {
                        return true;
                    }

                    @Override
                    public BigInteger next()
                    {                        
                        total = total.multiply(i);
                        i = i.add(BigInteger.ONE);
                        return total;
                    }

                    @Override
                    public void remove()
                    {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
        int i = 1;
        for (BigInteger f : fact)
        {
            System.out.format("%d! is %s%n", i++, f);
        }
    }
}

Non recursive factorial in Java. This solution is with custom iterator (to demonstrate iterator use :) ).

/** 
 * Non recursive factorial. Iterator version,
 */
package factiterator;

import java.math.BigInteger;
import java.util.Iterator;

public class FactIterator
{   
    public static void main(String[] args)
    {
        Iterable<BigInteger> fact = new Iterable<BigInteger>()
        {
            @Override
            public Iterator<BigInteger> iterator()
            {
                return new Iterator<BigInteger>()
                {
                    BigInteger     i = BigInteger.ONE;
                    BigInteger total = BigInteger.ONE;

                    @Override
                    public boolean hasNext()
                    {
                        return true;
                    }

                    @Override
                    public BigInteger next()
                    {                        
                        total = total.multiply(i);
                        i = i.add(BigInteger.ONE);
                        return total;
                    }

                    @Override
                    public void remove()
                    {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
        int i = 1;
        for (BigInteger f : fact)
        {
            System.out.format("%d! is %s%n", i++, f);
        }
    }
}
怀念你的温柔 2024-07-15 20:22:58
int fact(int n){
    int r = 1;
    for(int i = 1; i <= n; i++) r *= i;
    return r;
}
int fact(int n){
    int r = 1;
    for(int i = 1; i <= n; i++) r *= i;
    return r;
}
分分钟 2024-07-15 20:22:58

递归地使用带有缓存的 JavaScript。

var fc = []
function factorial( n ) {
   return fc[ n ] || ( ( n - 1 && n != 0 ) && 
          ( fc[ n ] = n * factorial( n - 1 ) ) ) || 1;
}

Recursively using JavaScript with caching.

var fc = []
function factorial( n ) {
   return fc[ n ] || ( ( n - 1 && n != 0 ) && 
          ( fc[ n ] = n * factorial( n - 1 ) ) ) || 1;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文