我正在学习大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)。

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

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

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

其他回答

如果您有一个函数需要:

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成立,常数因子和小项可以忽略。

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

算法(第4版)

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

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

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

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

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

如果你在图形计算器或类似的东西上绘制一个对数函数,你会发现它的上升速度非常慢——甚至比线性函数还要慢。

这就是为什么对数时间复杂度算法备受追捧的原因:即使对于真正大的n(例如,假设n=10^8),它们的性能也超出了可接受的范围。

O(logN)基本上意味着时间线性上升,而N指数上升。因此,如果计算10个元素需要1秒,则计算100个元素需要2秒,计算1000个元素需要3秒,依此类推。

​当我们进行分而治之的算法(如二进制搜索)时,它是O(logn)。另一个例子是快速排序,每次我们将数组分成两部分,每次都需要O(N)时间才能找到一个枢轴元素。因此,N O(log N)

这个问题已经有了很多好的答案,但我相信我们真的错过了一个重要的答案,那就是图解的答案。

说一个完整的二叉树的高度是O(logn)是什么意思?

下图描述了一个二叉树。请注意,与上面的级别相比,每个级别包含的节点数量是两倍(因此是二进制的):

二进制搜索是一个复杂度为O(logn)的示例。假设图1中树底部的节点表示某个排序集合中的项目。二进制搜索是一种分而治之的算法,图中显示了我们需要(最多)4次比较才能找到我们在这个16项数据集中搜索的记录。

假设我们有一个包含32个元素的数据集。继续上面的图,发现我们现在需要5次比较才能找到我们正在搜索的内容,因为当我们乘以数据量时,树只增长了一层。结果,该算法的复杂性可以用对数级数来描述。

在一张普通纸上绘制对数(n)将生成曲线图,其中曲线的上升速度随着n的增加而减慢: