递归效率与指数迭代的效率

时间:2012-01-17 05:55:13

标签: c++ performance recursion iteration

所以我正在尝试实现一种更有效的计算2^n的方法。

我知道您可以将其拆分为O(logn)并且使用递归很容易。你继续除以2,然后乘以奇数(或类似的东西)时的较低功率。问题是我用手写出了我的乘法方法,因为它的数字很大。所以它需要返回多个参数。

我能想到的一个解决方案是制作一个包含所有必需信息的对。除此之外我虽然试图弄清楚如何使用迭代来编写它。我能看到的唯一方法是使用某种数据结构,然后循环将n除以2,并在n为奇数时存储该值。然后编写for循环并在每次迭代时检查该值是否包含在数据结构中。在我看来,这似乎是一项相对昂贵的操作。

它最终可能会比递归版本效率低吗?

我这样做是因为:

  1. 我无法让gnp工作。
  2. 我认为我正在学习编写大数字课程并使用它。

2 个答案:

答案 0 :(得分:6)

如果你打算使用大数字,而不是重新发明轮子,你可能应该看一下GNU MP Bignum Library

关于递归与迭代问题,答案是你总是可以把它们写成等价的;一个仅将自身称为tail call的递归函数与while循环一样高效(只要您的编译器支持尾调用优化,但最常见的编译器)。例如,您正在描述的快速取幂函数的尾递归版本是(伪代码):

function fastExp(base, exponent, accumulator) {
  if(exponent == 0) {
    return accumulator;
  } else if(exponent % 2 == 0) {
    return fastExp(base * base, exponent/2, accumulator);
  } else {
    return fastExp(base, exponent-1, base * accumulator); 
  }
}

将此递归函数视为循环,其中循环条件为exponent != 0,并且递归调用类似于循环开始时的goto。 (顺便说一下,当你开始时,你需要用accumulator = 1来调用它。)它等同于以下内容:

function fastExp(base, exponent) {
  var accumulator = 1;
  while(exponent != 0) {
    if(exponent % 2 == 0) {
      base *= base;
      exponent /= 2;
    } else {
      exponent -= 1;
      accumulator *= base;
    }
  }
  return accumulator;
}

因此,您可以看到它们是等效的,因此将执行相同数量的操作。

答案 1 :(得分:0)

如果您将所有内容存储为 1 s和 0 s..ie。二进制格式的序列,则2 ^ n是只需 0 的序列,前面有单个1 ,也许您可​​以使用fact来简单地编写代码

2^1 = 10
2^2 = 100
2^3 = 1000
2^4 = 10000

等等,除非这是一个学习练习,否则我会选择标准的任意精度库,就像Philippe建议的那样