大多数人有一定程度的CS肯定会知道什么 大O代表.它可以帮助我们衡量(在)高效率的算法真的是如果你知道 什么类别的问题你都在试图解决奠定了 你能弄明白如果它仍然是可以挤出一点额外的业绩。1

但我很好奇,怎么做 你的 计算出的或者近似的复杂的算法?

1 但是,正如他们所说的,不要过分, 早产的优化是所有罪恶的根源, 和优化没有一个合理的原因应该得到那名称。

有帮助吗?

解决方案

我会做我最好的解释它在这里简单的条件,但是警告说,这个主题需要我的学生们几个月来最终掌握。你可以找到更多的信息,在第2章的 数据结构和算法在Java 书。


有没有 机械过程 这可以被用来获得BigOh.

作为"菜谱",得到的 BigOh 从一段代码你首先需要意识到你正在创建一个数学公式来计算有多少步骤计算得到执行给予输入的一些大小。

目的是简单的:比较算法从理论的观点,而不需要执行的代码。较小数量的步骤,更快的算法。

例如,我们说你有这样的代码:

int sum(int* data, int N) {
    int result = 0;               // 1

    for (int i = 0; i < N; i++) { // 2
        result += data[i];        // 3
    }

    return result;                // 4
}

这一功能将返回的总和所有的元件阵列,我们希望创建一个公式来算的 计算的复杂性 这一功能:

Number_Of_Steps = f(N)

因此,我们有 f(N), 一函数来计数计算步骤。输入的功能结构的大小,以处理。这意味着这个函数,如:

Number_Of_Steps = f(data.length)

参数 N 需要的 data.length 值。现在我们需要的实际定义功能 f().这样做是从源代码,其中每一有趣的线编号1至4。

有许多方法来计算BigOh.从这个点前进,我们要假定的每一句话,这并不取决于尺寸的输入数据需要一定 C 数计算步骤。

我们将增加个人编号的步骤的功能,无论是局部变量声明也不回声明取决于大小的 data 阵列。

这意味着线1和4C量的步骤的每一个,以及功能是有点这样的:

f(N) = C + ??? + C

接下来的部分是定义的价值 for 发言。记住,我们是计数计算步骤,这意味着身体 for 声明得到执行 N 倍。那是相同的加入 C, N 时间:

f(N) = C + (C + C + ... + C) + C = C + N * C + C

没有的机械的规则来计算有多少次的身体 for 得到执行,你需要计算它看看是什么代码做。为了简化计算,我们忽略了变量的初始化、条件和增加的部分 for 发言。

得到实际BigOh我们需要的 渐近的分析 的功能。这大约是完成这样的:

  1. 带走所有的常量 C.
  2. f() 得到的 polynomium 在它的 standard form.
  3. 除的条款polynomium和排序它们的增长率。
  4. 保持这一增长大的时候 N 的办法 infinity.

我们 f() 有两个条件:

f(N) = 2 * C * N ^ 0 + 1 * C * N ^ 1

带走所有的 C 常数和冗余部分:

f(N) = 1 + N ^ 1

由于最后一个任期是一个长大的时候 f() 方法无穷(在想 限制)是这BigOh参数, sum() 能有一个BigOh:

O(N)

有一些技巧,以解决一些棘手的:使用 汇总 只要你能。

作为一个例子,这个代码可以很容易解决,使用求和计算:

for (i = 0; i < 2*n; i += 2) {  // 1
    for (j=n; j > i; j--) {     // 2
        foo();                  // 3
    }
}

第一件事,你需要要求是为执行 foo().虽然通常要 O(1), 你需要问问你的教授。 O(1) 装置(近,大多)恒 C, 独立的大小 N.

for 发言的句号是一个非常棘手。虽然指数结束 2 * N, ,增量是通过两个。这意味着,第一 for 得到执行的只有 N 步骤,并且我们需要划分的数通过两个。

f(N) = Summation(i from 1 to 2 * N / 2)( ... ) = 
     = Summation(i from 1 to N)( ... )

句号 两个 甚至是棘手的,因为它取决于价值的 i.看一看:索引我需要价值观:0, 2, 4, 6, 8, ..., 2 * N、和第二 for 得到执行:N次第一个N-2第二,N-4第三...最N/2阶段,在其第二 for 从来没有得到执行。

关于公式,这意味着:

f(N) = Summation(i from 1 to N)( Summation(j = ???)(  ) )

再次,我们指望 步骤的数目.与通过的定义,每求和应该开始在一个和最终在一些更大的或相等于一个。

f(N) = Summation(i from 1 to N)( Summation(j = 1 to (N - (i - 1) * 2)( C ) )

(我们假设 foo()O(1) 和需要 C 步骤。)

我们有一个问题:时 i 需要的价值 N / 2 + 1 向上、内总结束在一个负数!这是不可能的和错误的。我们需要分裂求和在两个,是关键的时刻 i 需要 N / 2 + 1.

f(N) = Summation(i from 1 to N / 2)( Summation(j = 1 to (N - (i - 1) * 2)) * ( C ) ) + Summation(i from 1 to N / 2) * ( C )

由于关键时刻 i > N / 2, ,内 for 不会得到执行,我们假定一个常C的执行复杂性在它的身体。

现在求和可以简化使用某些身份的规则:

  1. 求和(w从1到N)(C)=N*C
  2. 求和(w从1到N)(一(+/-)B)=求和(w从1到N)(A)(+/-)求和(w从1到N)(B)
  3. 求和(w从1到N)(w*C)=C*求和(w从1到N)(w)(C是一个不断的、独立的 w)
  4. 求和(w从1到N)(w)=(N*(N+1))/2

施加一些代数:

f(N) = Summation(i from 1 to N / 2)( (N - (i - 1) * 2) * ( C ) ) + (N / 2)( C )

f(N) = C * Summation(i from 1 to N / 2)( (N - (i - 1) * 2)) + (N / 2)( C )

f(N) = C * (Summation(i from 1 to N / 2)( N ) - Summation(i from 1 to N / 2)( (i - 1) * 2)) + (N / 2)( C )

f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2)( i - 1 )) + (N / 2)( C )

=> Summation(i from 1 to N / 2)( i - 1 ) = Summation(i from 1 to N / 2 - 1)( i )

f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2 - 1)( i )) + (N / 2)( C )

f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N / 2 - 1) * (N / 2 - 1 + 1) / 2) ) + (N / 2)( C )

=> (N / 2 - 1) * (N / 2 - 1 + 1) / 2 = 

   (N / 2 - 1) * (N / 2) / 2 = 

   ((N ^ 2 / 4) - (N / 2)) / 2 = 

   (N ^ 2 / 8) - (N / 4)

f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N ^ 2 / 8) - (N / 4) )) + (N / 2)( C )

f(N) = C * (( N ^ 2 / 2 ) - ( (N ^ 2 / 4) - (N / 2) )) + (N / 2)( C )

f(N) = C * (( N ^ 2 / 2 ) - (N ^ 2 / 4) + (N / 2)) + (N / 2)( C )

f(N) = C * ( N ^ 2 / 4 ) + C * (N / 2) + C * (N / 2)

f(N) = C * ( N ^ 2 / 4 ) + 2 * C * (N / 2)

f(N) = C * ( N ^ 2 / 4 ) + C * N

f(N) = C * 1/4 * N ^ 2 + C * N

和BigOh是:

O(N²)

其他提示

大O出上限为时间复杂的算法。它通常是结合使用与处理的数据集(名单),但可以用其他地方。

几个例子如何使用它在C码。

说我们有一系列的n元素

int array[n];

如果我们想要访问的第一个元件阵列,这将是O(1)由于不论多么大阵列,它总是需要同样的恒定的时间得到的第一个项目。

x = array[0];

如果我们想要找一些在清单:

for(int i = 0; i < n; i++){
    if(array[i] == numToFind){ return i; }
}

这将是O(n)由于在大多数我们就会看穿整个名单可以找到我们的号码。大-O仍然是O(n)虽然我们可能会找到我们的第一次尝试和运行过一次循环,因为大O介绍了上限的一个算法(欧米茄是用下限和费是用于紧绑).

当我们到套循环:

for(int i = 0; i < n; i++){
    for(int j = i; j < n; j++){
        array[j] += 2;
    }
}

这是O(n^2)由于为每一外循环(O(n))我们必须通过整个列表中再次这样的n的乘离开我们与n的平方。

这是几乎没有表面划伤,但是当你得到分析更加复杂的算法涉及复杂的数学证明来发挥作用。希望这能让您熟悉的基本知识,至少是虽然。

同时知道如何找出的大O时间为你的特殊问题是有用的,知道一些一般情况下可以走很长的路,在帮你做决定你的算法。

这里是一些最常见的情况下,提起 http://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions:

O(1)-如果确定一数量是偶数或奇数;使用恒定大查找表或散列表

O(的)查的一个项目的排序列有一个二元的搜索

O(n)-找到一个项目在未经分类整理的清单;添加两个n-两位数号码

O(n2)-乘两个n数字的号码,通过一个简单的算法;添加两个n×n矩阵;泡沫进行排序或插入排序

O(n3)-乘两个n×n矩阵通过简单的算法

O(cn)-找到(精确)解决旅行推销员问题采用动态方案拟订;如果确定两个合乎逻辑的发言是等效的使用暴力

O(n!) -解决的旅行推销员问题通过暴力搜索

O(nn)往往用于代替O(n!) 要获得简单的公式对复杂的渐近

小提醒:的 big O 符号是用来表示 渐近 复杂性(也就是说,当这个问题的大小长到无限的), 它隐藏了一个恒定不变。

这意味着之间的一个算法在O(n)和一个在O(n2的),最不总是第一个人(虽然还有总是存在一个n值,例如,对于问题的大小>n,第一算法是最快的).

注意隐藏的定在很大程度上取决于实现!

此外,在某些情况下,运行时不是一个确定性的功能 尺寸 n的输入。采取的分拣使用快速排序,例如:所需要的时间排序列的n元素不是一成不变的,但取决于开始结构的阵列。

有的时间不同的复杂性:

  • 最糟糕的情况(通常是最简单的图出,虽然并不总是很有意义的)
  • 平均情况(通常更难找出...)

  • ...

一个很好的介绍 介绍的分析算法 由R.塞奇威克和P.Flajolet.

就像你说的, premature optimisation is the root of all evil, ,和(如果可能的话) 分析 真的应该总是可以用于当优化码。它甚至可以帮助你确定复杂的算法。

看到答案在这里,我想我们可以得出结论,我们大多数人实际上接近秩序的算法 在它和使用常识而不是计算,例如, 主方法 因为我们认为在大学。与上述我必须补充一点,即使是教授鼓励我们(后来)实际上 想想 关于它而不是仅仅计算它。

此外,我想补充如何这样做是为了 递归功能:

假设我们有一个功能等(方案的代码):

(define (fac n)
    (if (= n 0)
        1
            (* n (fac (- n 1)))))

其递归算因子给出的数字。

第一步是要尝试和确定性能特征 身体的功能只 在这种情况下,没有什么特别的是在身体,只是个乘(或返回值1)。

所以 表现为身体是:O(1) (一定)。

接下来尝试和确定这个的 数字递归的电话.在这种情况下,我们有n-1递归的呼吁。

所以 性能用递归的电话是:O(n-1) (秩序是正,因为我们扔掉的微不足道的部分).

然后把那两个在一起和你的性能为整个递归功能:

1*(n-1)=O(n)


彼得, 回答 你提出问题; 这方法我在这里描述实际处理这个相当好。但记住,这仍然是一个 逼近 并不是一个完整的数学上正确的答案。这里描述的方法也是一种方法,我们曾在大学,以及如果我没有记错的话是用于远更高级的算法比因子我用这个例子。
当然这一切都取决于你如何可以估计运行时间的体的功能和数字递归的话,但这只是作为真正的其他方法。

如果你的成本是多项式,只要保持最高阶期,没有它的乘数。E.g.:

O((n/2+1)*(n/2))=O(n2/4+n/2)=O(n2/4)=O(n2)

这不适用于无限的系列介意你。没有一个单一的配方用于一般情况下,虽然对一些常见的情况下,以下不平等的申请:

O(日志 N) < O(N) < O(N 日志 N) < O(N2) < O(Nk) < O(en) < O(n!)

我认为,有关这方面的信息。任何问题包括学习一定数量的位。

你的基本工具的概念是决定点和它们的熵。熵的决定点是平均值的信息,它会给你的。例如,如果一个程序包含一个决定点与两个分支,它的熵是的概率各分支的时间的日志2 逆概率分支。这就是你学会通过执行这项决定。

例如,一个 if 声明具有两个分支,两者都同样可能的是,有一个熵1/2*日志(2/1)+1/2*日志(2/1) = 1/2 * 1 + 1/2 * 1 = 1.所以它的熵是1位。

假设你正在寻找一个表中的项目N,N=1024.这是一个10分位的问题,因为日志(1024)=10位。所以如果你可以搜索它如果发言,同样可能产生的结果,就应采取的10项决定。

这就是你所得到的二进行搜索。

假设你正在做的线搜索。你看看的第一个元素和问,如果这是你想要的。该概率的1/1024,它是和1023/1024,它不是。熵的这一决定的1/1024*日志(1024/1)+1023/1024*日志(1024/1023) = 1/1024 * 10 + 1023/1024 * 关于0=关于.01位。你已经学到了很小的!第二项决定是不是好多了。这就是为什么线索是如此缓慢。事实上,它是指数中位数你需要学习。

假设你正在做的索引。假设表是前排入大量的垃圾箱,并使用一些所有的位的关键指数直接表的条目。如果有1024箱,熵是的1/1024*日志(1024)+的1/1024*日志(1024)+...所有1024可能的结果。这是的1/1024*10次1024的结果,或10位的熵,一个索引操作。这就是为什么索引搜索速度快。

现在认为有关排序。你有N项目,并有一个列表。对于每一个项目,你有搜索,该项目的清单,然后将它添加到名单。因此排序需要大约N次数的步骤的基础搜索。

所以,各种各样的基础上的二进制的决定具有约同样可能产生的结果采取的所有有关O(N记录N)的步骤。O(N)排序的算法是可能的,如果它是根据索引搜索。

我发现,几乎所有计算性能的问题可以被看着是这样的。

让我们从头开始。

首先,接受原则,即某些简单的操作数据可以做 O(1) 时间,这就是,在时候,是独立的尺寸的输入。这些原始的行动在C包括

  1. 算术运算的(例如+或%).
  2. 逻辑操作(例如,&&).
  3. 比较操作(例如, <=).
  4. 结构访问的行动(例如阵列的索引样的一个[i],或指跟着 降低与->操作者)。
  5. 简单的分配等复制的价值进入一个变量。
  6. 呼吁图书馆功能(例如,scanf,printf).

该理由为这项原则要求的详细研究机指令(原始步骤)的典型计算机。每个描述的操作可以做一些小型号的机器说明;往往只有一或两条指令是必要的。因此,各种报表中的C可以执行 O(1) 时间,也就是说,在一些固定的时间独立的输入。这些简单包括

  1. 分配的语句并不涉及功能的电话在他们的表情。
  2. 阅读的发言。
  3. 写入报表,不需要功能的电话,以评估的参数。
  4. 跳声明的突破,继续、goto和表达返回,在那里 表达不包含一个函数。

在C,许多循环的形成,通过初始化指数变量有一定的价值和 递增变量的1每次循环。为循环结束的时候 该指标达到某些限制。例如,为循环

for (i = 0; i < n-1; i++) 
{
    small = i;
    for (j = i+1; j < n; j++)
        if (A[j] < A[small])
            small = j;
    temp = A[small];
    A[small] = A[i];
    A[i] = temp;
}

使用指数的变量。它递增我1每次循环,并迭代 停止当我到达n−1。

然而,目前,重点放在以简单的形式为环,这里的 差最后的和初始价值,除量指数变量增加告诉我们有多少次我们去周围的循环.这算是精确的,除非另有方法可以退出该循环,通过一个跳的声明;这是一个上限次数,在任何情况下。

例如,为回路迭代 ((n − 1) − 0)/1 = n − 1 times, 因为0的初始价值的我,n−1是最高价值达到了i(即,当我 达到n−1,环停止并且没有发生迭代i=n−1)和1个加入 来我在每一次迭代的循环。

在最简单的情况,在那里花费的时间循环的身体是同每 迭代, 我们可以乘大-哦,上限为体通过的数目 时代周围环.严格地说,我们必须然后 添加O(1)的初始化时间 循环的索引和O(1)时间为第一个比较的环索引 限制, 因为我们测试一个更多的时间比我们绕去的循环。然而,除非 它能够执行环零次,时间初始化循环和测试 限制一次是低以期就可以下降了求和规则。


现在考虑这个例子:

(1) for (j = 0; j < n; j++)
(2)   A[i][j] = 0;

我们知道 行(1) 需要 O(1) 时间。显然,我们去周围的环n次,作为 我们可以确定减去下限从上限上发现线 (1)后,添加1个。由于身体、线(2),需要O(1)时,我们可以忽视 时间以递增j和时间比较j用正,这两者也是O(1)。因此,运行时间线(1)和(2)是的 n和O(1), ,这是 O(n).

同样,我们可以往运行时间外循环构成的线路 (2)至(4),这是

(2) for (i = 0; i < n; i++)
(3)     for (j = 0; j < n; j++)
(4)         A[i][j] = 0;

我们已经建立了环路线(3)和(4)需要O(n)的时间。因此,我们可以忽略O(1)时要增我和测试是否我 < n 每次迭代,得出结论认为,每次迭代的外循环需要O(n)的时间。

初始化i=0外循环和(n+1)st测试条件 我 < n同样采取O(1)时间和可以被忽视。最后,我们观察我们走 围绕外部环n次,把O(n)时间为每次迭代,给予总 O(n^2) 运行时间。


一个更实际的例子。

enter image description here

如果你想要估计为你的代码经验,而不是通过分析代码,可以坚持在一系列的增加值n和时间代码。情节你的时间在一个日志的规模。如果代码是O(x^n)的值应该落在一线的斜率。

这有几个优点只是学习的代码。对于一件事情,你可以看看你是否是在范围运行时间的方法,其渐进的顺序。此外,您可以找到一些代码,你以为是了O(x)是真的了O(x^2),例如,由于时间花在图书馆的电话。

基本的事情,作物多达90%的时间仅仅是分析循环。你有单一、双重、三套循环?你必须O(n),O(n^2),O(n^3)运行时间。

很少(除非你正在写一个平台具有广泛基础的图书馆(例如,中。净BCL或C++'s STL)你会遇到任何东西,是更困难的不仅仅是看着你的循环(发言,同时,goto,etc...)

打破算法成碎片你知道的大O表示,将通过大O运营商。这是唯一的办法我知道的。

欲了解更多信息,请查看的 维基百科页 该问题。

大O符号是有用的,因为它是容易的工作并隐藏了不必要的复杂情况和详细信息(对于一些定义不必要的).一个很好的方式工作的复杂性,分而治之的算法是树的方法。让我们说你有一个版本的快速排序与中位的程序,所以你分数组成为完美的平衡阵列,每次。

现在建立一个树相对应的所有阵列的与你的工作。在根你有原来的阵列,根有两个孩子哪些是阵列.重复,直到你有单元件阵列在底部。

因为我们可以找到中间值为O(n)和时间分列的两部分中的O(n)时所做的工作,在每个节点是O(k)中k大小的阵列。每个级别的树包含(至多)整个阵,以便在工作的每一级是O(n)(大小的子数组加起来n,并且由于我们已经O(k)每个级别,我们可以添加这一)。只有日志(n)的各级在树,因为每次我们一半的输入。

因此,我们可以上限的工作量由O(n*日志(n))。

然而,大O隐藏了些细节我们有时不能忽视。考虑计算的斐波那契数列与

a=0;
b=1;
for (i = 0; i <n; i++) {
    tmp = b;
    b = a + b;
    a = tmp;
}

并且让我们假定a和b BigIntegers在Java或东西,可以任意地处理庞大数字。大多数人会说这是一个O(n)的算法,毫无畏惧.其理由是,你有n次迭代的循环和O(1)工作在侧循环。

但是斐波那契数字很大,n个斐波纳契数指数在n那么只要存储这将需要上了n字节。执行加大整数将采取O(n)的工作量。因此总量的工作要做,在这个过程是

1 + 2 + 3 + ...+n=n(n-1)/2=O(n^2)

所以这算法运行quadradic时间!

熟悉的算法/数据结构,我使用和/或快速浏览的分析迭代嵌套。困难的是当你呼叫一个图书馆的功能,可能是多次-你可以常常不能确定是否你打电话的功能不必要地的时候或什么的执行他们使用。也许图书馆的职能应具有复杂性/效率的措施,无论是大O或一些其他的指标,提供文件或甚至 IntelliSense.

少用通常,我觉得,但为了完整性还有一个 大米茄Ω, ,其中定义的下往上的一个算法的复杂性,以及一个 大西塔Θ, ,其中规定一个上限和下限。

作为"你如何计算"大O,这是一部分 计算复杂的理论.对一些(许多)的特殊情况下,可能能够提出一些简单的启发式(如乘循环计数用于嵌套循环),esp.当你想要的是任何上限估计,你不介意,如果它是太悲观了-我猜大概是你的问题是关于。

如果你真的想回答你的问题的任何算法的最好你可以做的是适用的理论。除了简单化的"最坏情况"的分析,我们发现 摊销的分析 中非常有用的做法。

第1种情况下,内环执行 n-i 次,因此总数处决是的总和 i 从去 0n-1 (因为低于,在不低于或等)的 n-i.你得到最后 n*(n + 1) / 2, ,所以 O(n²/2) = O(n²).

第2循环, i 是之间 0n 包括外循环;然后内环执行当 j 严格大于 n, ,然后将不可能的。

除了使用方法(或其中一个专业),我测试我的算法的实验。这不可能 证明 任何特定的复杂程度类是实现,但是它可以提供保证,学分析是合适的。为了帮助这种保证,我使用代码复盖率的工具,结合我的实验,以确保我行使所有的案件。

作为一个非常简单的例子说你想要做一个完整性检查的速度。净框架的列表进行排序。你可写的东西喜欢在下面,然后分析结果在Excel中,以确保他们不得超过一个n*日志(n)曲线。

在这个例子中,我测量数的比较,但它还是审慎的检查所需的实际时间用于每一个样品大小。但是然后你必须更加小心,你只是测算并不包括文物从你的测试的基础设施。

int nCmp = 0;
System.Random rnd = new System.Random();

// measure the time required to sort a list of n integers
void DoTest(int n)
{
   List<int> lst = new List<int>(n);
   for( int i=0; i<n; i++ )
      lst[i] = rnd.Next(0,1000);

   // as we sort, keep track of the number of comparisons performed!
   nCmp = 0;
   lst.Sort( delegate( int a, int b ) { nCmp++; return (a<b)?-1:((a>b)?1:0)); }

   System.Console.Writeline( "{0},{1}", n, nCmp );
}


// Perform measurement for a variety of sample sizes.
// It would be prudent to check multiple random samples of each size, but this is OK for a quick sanity check
for( int n = 0; n<1000; n++ )
   DoTest(n);

不要忘了也许对空间的复杂性,也可以是一个令人关切,如果一个具有有限的存储器资源。因此,例如,你可以听见有人想要一个不断空间的算法,它基本上是一种说法,空间量所采取的算法并不依赖于任何因素的内部编码。

有时复杂性可能来自多少次是所谓,如何经常是一个循环执行,常常是如何分配存储器等等是另一部分回答这个问题。

最后,大O可以用于坏的情况下,最好的情况下,并且分期偿还的情况下,通常这是最糟糕的情况,是用于描述如何糟糕的一个算法的可能。

什么常常被忽视的 预期 行为的算法。 它不会改变大-O你的算法, 但它不涉及声明中"过早的最优化。..."

预期行为的你的算法是非常简单化了-你能多快的期待你的算法工作的数据你是最有可能看到的。

例如,如果你正在寻找一个值在一个列表中,这是O(n),但是如果你知道大多数的名单你看见有你的价值最前面,典型的行为的算法是更快。

真的指甲下来,你需要的是能够描述的概率分布的"输入空间"(如果你需要整理的清单,常常是如何该名单已经要排?怎么经常是这完全扭转?怎么常常是它的主要排?) 它并不总是可行的,你知道的,但有时你做的。

伟大的问题!

免责声明:这个答案含有虚假陈述看到的评论如下。

如果你使用大O,你在谈论这糟糕的情况下(更多关于这意味着什么以后)。此外,还有资费用于平均水平的情况下和一个大的欧米茄为最好的情况下。

看看这个网站的一个可爱的正式定义的大O: https://xlinux.nist.gov/dads/HTML/bigOnotation.html

f(n)=O(g(n))意味着有正常c和k,这样,0≤f(n)≤cg(n)所有n≥k。值的c和k必须是固定的功能f并不取决于正。


好了,现在我们怎么说"最好的情况下"和"最坏情况"的复杂情况?

这可能是最清楚地说明通过实例。例如,如果我们使用的是线性的搜索找到一个数量在一个排列然后 最糟糕的是 是当我们决定 搜索的最后一个元素 阵列,因为这会采取许多步骤作为有项目数。的 最好的情况下 将在我们寻找的 第一个元素 因为我们将完成后的第一次检查。

点的所有这些 形容词-情况复杂性的是,我们正在寻找一种方式,以图形的时间量的假设的程序运行,以完成在条款的尺寸的具体变量。然而,对于许多算法你就可以争辩说,没有一个单一的时间用于一个特定尺寸的输入。请注意,这违背了基本要求的功能,任何输入应该不超过一个输出。所以我们来了 职能,来描述一个算法的复杂性。现在,尽管搜索一系列大小n可能需要不同数量的时间取决于你在找什么在列和根据按比例n,我们可以创建一个内容丰富的介绍算法的使用的最佳情况下,平均情况和最坏情况下的课程。

对不起,是这样写得不好,缺乏技术信息。但我希望它会让时间复杂的类更容易考虑。一旦你成为舒适用这些就变成一个简单的问题的分析,通过你的程序和寻找的东西喜欢循环,取决于列大小和推理的基础上你的数据结构是什么样的投入结果在琐碎的情况下和什么样的输入,将导致在最坏的情况。

我不知道如何编程方式解决这个问题,但第一件事的人不是我们的样本的算法对一些特定的模式在数量的操作所做的,说4n^2+2n+1我们有2个规则:

  1. 如果我们有一个总和条款、术语具有最大增长率保持与其他条款省略。
  2. 如果我们有一个产品的若干因素不变因素是省略。

如果我们简化f(x),其中f(x)是式的操作数量做,(4n^2+2n+1以上所解释),我们获得的大O值[O(n^2)在这种情况下].但是,这将必须考虑的拉格朗日内插在程序,这可能难以实现。什么如果真大-O值O(2^n),我们可能有什么样的O(x^n),因此这种算法,可能不会被编程。但是,如果有人证明我错了,给我的代码。...

用于编码,外循环将执行为 n+1 次,'1'时装置的过程,检查是否仍然符合要求。和内部循环的运行 n 次, n-2 。因此,0+2+..+(n-2)+n= (0+n)(n+1)/2= O(n²).

代码B,虽然内部循环不会的步骤和执行的foo(),内部循环将执行n次取决于外部环执行时间,这是O(n)

我想解释一下大-O一点点的不同方面。

大O只是比较复杂的程序,这意味着如何快速的是他们成长时的投入增加和不精确的时间是花做的行动。

恕我直言大-O式你最好不要采用更复杂的方程式(你可能只是坚持那些在下列图表。) 但是你仍然可以使用其他更精确的公式(3^n,n^3,...),但更多可以有时误导!因此,更好地保持尽可能简单。

enter image description here

我谨再次强调,我们在这里不想要得到一个准确的公式对我们的算法。我们只想要展示它是如何成长时的投入的增长和比较的其他算法。否则你会更好地使用不同的方法一样的长凳上标记。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top