我正在学习大O符号的运行时间和摊销时间。我理解O(n)线性时间的概念,这意味着输入的大小成比例地影响算法的增长。。。例如,二次时间O(n2)等也是如此。甚至是通过阶乘增长的算法,如置换生成器,其O(n!)次。

例如,以下函数为O(n),因为算法与其输入n成比例增长:

f(int n) {
  int i;
  for (i = 0; i < n; ++i)
    printf("%d", i);
}

类似地,如果存在嵌套循环,时间将为O(n2)。

但O(log n)到底是什么?例如,说一个完整的二叉树的高度是O(log n)是什么意思?

我确实知道(也许不是很详细)对数是什么,从这个意义上说:log10 100=2,但我不知道如何识别具有对数时间的函数。


当前回答

但O(log n)到底是什么?例如,如果一个>完整二叉树的高度是O(logn),这意味着什么?

我会将其重新表述为“完整二叉树的高度是logn”。如果一步一步向下遍历,计算完整的二叉树的高度将是O(logn)。

我无法理解如何用对数来识别函数时间

对数本质上是幂的倒数。因此,如果函数的每个“步骤”都在从原始项集中删除一个元素因子,那就是对数时间算法。

对于树的示例,您可以很容易地看到,当您继续遍历时,逐步降低节点级别会减少指数级的元素数量。浏览按姓名排序的电话簿的流行示例基本上等同于遍历二进制搜索树(中间页面是根元素,您可以在每个步骤中推断是向左还是向右)。

其他回答

首先,我建议您阅读以下书籍:;

算法(第4版)

下面是一些函数及其预期的复杂性。数字表示语句执行频率。

以下Big-O复杂性图表也取自bigocheatsheet

最后,非常简单的展示展示了它是如何计算的;

剖析程序的语句执行频率。

分析程序的运行时间(示例)。

下面的解释是使用完全平衡的二叉树来帮助您理解我们如何获得对数时间复杂度。

二叉树是一种情况,其中大小为n的问题被划分为大小为n/2的子问题,直到我们达到大小为1的问题:

这就是你如何得到O(logn),这是在上面的树上需要完成的工作量,以获得解决方案。

具有O(logn)时间复杂度的常见算法是二进制搜索,其递归关系为T(n/2)+O(1),即在树的每个后续级别上,您将问题分成一半,并执行恒定数量的额外工作。

如果您有一个函数需要:

1 millisecond to complete if you have 2 elements.
2 milliseconds to complete if you have 4 elements.
3 milliseconds to complete if you have 8 elements.
4 milliseconds to complete if you have 16 elements.
...
n milliseconds to complete if you have 2^n elements.

然后需要log2(n)时间。广义地说,大O符号意味着关系只需要对大n成立,常数因子和小项可以忽略。

我可以补充一些有趣的东西,很久以前我在科尔曼等的书中读过。现在,想象一个问题,我们必须在问题空间中找到解决方案。这个问题空间应该是有限的。

现在,如果你能证明,在你的算法的每一次迭代中,你都切断了这个空间的一部分,这不小于某个极限,这意味着你的算法在O(logN)时间内运行。

我应该指出,我们这里讨论的是相对分数极限,而不是绝对分数极限。二进制搜索是一个经典的例子。在每一步中,我们都会丢掉1/2的问题空间。但二进制搜索并不是唯一的例子。假设,你以某种方式证明了,在每一步中,你至少丢掉了1/128的问题空间。这意味着,您的程序仍然以O(logN)时间运行,尽管比二进制搜索慢得多。这是分析递归算法的一个很好的提示。通常可以证明,在每一步递归都不会使用几个变量,这会导致问题空间中某些分数的截断。

分治算法通常具有运行时间的logn成分。这来自于输入的重复减半。

在二进制搜索的情况下,每次迭代都会丢弃一半的输入。需要注意的是,在Big-O表示法中,log是以2为底的log。

编辑:如上所述,对数基数并不重要,但当推导算法的Big-O性能时,对数因子将来自减半,因此我认为它是基数2。