algorithm - 递归算法中的基本情况和时间复杂度

标签 algorithm performance recursion big-o sicp

我想对 O(N) 函数进行一些说明。我正在使用 SICP .

考虑书中用伪代码生成递归过程的阶乘函数:

function factorial1(n) {
    if (n == 1) {
        return 1;
    }
    return n*factorial1(n-1);
}

我不知道如何测量步数。也就是我不知道“step”是怎么定义的,所以我用书上的说法来定义一个step:

Thus, we can compute n ! by computing (n-1)! and multiplying the result by n.

我认为这就是他们所说的一步的意思。举个具体的例子,如果我们追踪(阶乘 5),

  • 阶乘(1) = 1 = 1 步(基本情况 - 常数时间)
  • 阶乘(2) = 2*阶乘(1) = 2 步
  • 阶乘(3) = 3*阶乘(2) = 3 步
  • 阶乘(4) = 4*阶乘(3) = 4 步
  • 阶乘(5) = 5*阶乘(4) = 5 步

我认为这确实是线性的(步数与 n 成正比)。

另一方面,这是我一直看到的另一个阶乘函数,它的基本情况略有不同。

function factorial2(n) {
    if (n == 0) {
        return 1;
    }
    return n*factorial2(n-1);
}

这与第一个完全相同,只是添加了另一个计算(步骤):

  • 阶乘(0) = 1 = 1 步(基本情况 - 常数时间)
  • 阶乘(1) = 1*阶乘(0) = 2 步
  • ...

现在我相信这仍然是 O(N),但是如果我说 factorial2 更像 O(n+1)(其中 1 是基本情况)而不是 factorial1 恰好是 O(N),我是否正确(包括基本情况)?

最佳答案

需要注意的一件事是 factorial1 对于 n = 0 是不正确的,在典型的实现中可能会下溢并最终导致堆栈溢出。 factorial2 对于 n = 0 是正确的。

撇开这一点不谈,您的直觉是正确的。 factorial1 是 O(n),factorial2 是 O(n + 1)。但是,由于 n 的影响优于常数因子(+ 1),因此通常将其简化为 O(n)。关于 Big O Notation 的维基百科文章描述这个:

...the function g(x) appearing within the O(...) is typically chosen to be as simple as possible, omitting constant factors and lower order terms.

不过,从另一个角度来看,更准确的说法是这些函数在pseudo-polynomial time中执行。 .这意味着它是关于 n 的数值的多项式,但是关于表示 n 的值所需的位数的指数。有一个很好的先前答案描述了这种区别。

What is pseudopolynomial time? How does it differ from polynomial time?

关于algorithm - 递归算法中的基本情况和时间复杂度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45309982/

相关文章:

C:二叉树搜索法

c# - 使用 JSON.NET 将递归 JSON 反序列化为 C#

Python:防止双for循环返回列表的相同索引

algorithm - 堆 - 对未知输入执行 DeleteMax 操作 - 实现

android - Unity 背景 Sprite 会影响 fps

css - css 中有太多背景图片会影响性能吗?

algorithm - 以最少的重新编号对项目进行排序

c++ - 如何将递归代码更改为迭代形式

internet-explorer-9 - IE 通过函数调用运行得更快?

c++ - 有没有办法使类递归?