我正在学习大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(ln n),因为搜索结果如下:

1 2 3 4 5 6 7 8 9 10 11 12

搜索4个会产生3次命中:6次,3次,然后4次。而log2 12=3,这是一个很好的近似值,以多少命中需要。

其他回答

完整的二进制示例是O(ln n),因为搜索结果如下:

1 2 3 4 5 6 7 8 9 10 11 12

搜索4个会产生3次命中:6次,3次,然后4次。而log2 12=3,这是一个很好的近似值,以多少命中需要。

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

算法(第4版)

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

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

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

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

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

O(logn)有点误导,更准确地说,它是O(log2n),即(以2为底的对数)。

平衡二叉树的高度是O(log2n),因为每个节点都有两个(注意log2n中的“两个”)子节点。因此,具有n个节点的树的高度为log2n。

另一个例子是二进制搜索,它的运行时间为O(log2n),因为在每一步中,您都将搜索空间除以2。

实际上,如果您有一个n个元素的列表,并从该列表中创建一个二叉树(就像在除法和征服算法中一样),您将一直除以2,直到达到大小为1的列表(树叶)。

在第一步,你除以2。然后,您有2个列表(2^1),将每个列表除以2,因此您有4个列表(2*2),然后再进行一次除法,您有8个列表(3^3),依此类推,直到列表大小为1

这给出了一个等式:

n/(2^步)=1<=>n=2^步<=>lg(n)=步

(取每边的lg,lg为对数基数2)

我可以举一个for循环的例子,也许一旦掌握了这个概念,在不同的上下文中理解起来会更简单。

这意味着在循环中,步长呈指数增长。例如。

for (i=1; i<=n; i=i*2) {;}

该程序的O表示法的复杂性为O(log(n))。让我们尝试手动循环(n介于512和1023之间(不包括1024):

step: 1   2   3   4   5    6    7    8     9     10
   i: 1   2   4   8   16   32   64   128   256   512

尽管n介于512和1023之间,但只进行了10次迭代。这是因为循环中的步骤呈指数增长,因此只需要10次迭代就可以到达终点。

x的对数(到a的底)是a^x的反函数。这就像说对数是指数的倒数。

现在试着这样看,如果指数增长非常快,那么对数增长(相反)非常慢。

O(n)和O(log(n))之间的差异是巨大的,类似于O(n(n)与O(a^n)之间的区别(a是常数)。