大O表示法¶
当试图在独立于任何特定程序或计算机的执行时间方面表征算法的效率时,量化算法所需的操作或步骤的数量非常重要。 如果将这些步骤中的每一个都视为计算的基本单元,则算法的执行时间可以表示为解决问题所需的步骤数。 决定适当的基本计算单位可能是一个复杂的问题,并且取决于算法的实现方式。
用于比较前面所示的求和算法的一个很好的基本计算单位可能是为计算总和而执行的赋值语句的数量。 在函数sum_of_n
中,赋值语句的数量为 1 (
在上面给出的求和函数中,使用求和中的项数来表示问题的大小是有意义的。 然后我们可以说前 100,000 个整数的总和是比前 1,000 个整数的总和更大的求和问题实例。 因此,解决较大案件所需的时间比解决较小案件所需的时间更长似乎是合理的。 我们的目标是展示算法的执行时间如何随着问题的大小而变化。
计算机科学家更愿意将这种分析技术更进一步。 事实证明,确切的操作次数并不像确定
在上面的例子中,
再举一个例子,假设对于某些算法,确切的步骤数是
尽管我们在求和示例中没有看到这一点,但有时算法的性能取决于数据的精确值,而不仅仅是问题的大小。 对于这些类型的算法,我们需要根据最佳情况、最坏情况或平均情况性能来表征其性能。 最坏情况性能是指算法性能特别差的特定数据集,而完全相同算法的不同数据集可能具有非常好的(最佳情况)性能。 然而,在大多数情况下,算法的性能介于这两个极端之间(平均情况性能)。 对于计算机科学家来说,理解这些区别非常重要,这样他们就不会被某一特定案例误导。
当您研究算法时,许多非常常见的数量级函数会反复出现。 这些如“表 1”所示。 为了确定这些函数中的哪一个是任何
表 1: 大 O 的常用函数
f(n) | 名称 |
---|---|
常量(Constant) | |
对数(Logarithmic) | |
线性(Linear) | |
对数线性(Log linear) | |
二次方(Quadratic) | |
立方(Cubic) | |
指数(Exponential) |
“图 1”显示了“表 1”中常见功能的图表。 请注意,当 n 很小时,函数之间的定义不是很好。 很难说哪个占主导地位。 然而,随着 n 的增长,存在着明确的关系,并且很容易看出它们如何相互比较。

作为最后一个示例,假设我们有“清单 2”中所示的 Python 代码片段。 尽管这个程序实际上并没有做任何事情,但了解我们如何获取实际代码并分析性能还是很有启发性的。
清单 2
a = 5
b = 6
c = 10
for i in range(n):
for j in range(n):
x = i * i
y = j * j
z = i * j
for k in range(n):
w = a * k + 45
v = b * b
d = 33
赋值运算的次数是四项之和。 第一项是常量 3,代表片段开头的三个赋值语句。 第二项是

图 2
显示了一些常见的 大 O 函数与上面讨论的
自检
编写两个 Python 函数来查找列表中的最小数字。 第一个函数应该将每个数字与列表中的每个其他数字进行比较。
Big O Notation
When trying to characterize an algorithm’s efficiency in terms of execution time, independent of any particular program or computer, it is important to quantify the number of operations or steps that the algorithm will require. If each of these steps is considered to be a basic unit of computation, then the execution time for an algorithm can be expressed as the number of steps required to solve the problem. Deciding on an appropriate basic unit of computation can be a complicated problem and will depend on how the algorithm is implemented.
A good basic unit of computation for comparing the summation algorithms shown earlier might be the number of assignment statements performed to compute the sum. In the function sum_of_n
, the number of assignment statements is 1 (
In the summation functions given above, it makes sense to use the number of terms in the summation to denote the size of the problem. We can then say that the sum of the first 100,000 integers is a bigger instance of the summation problem than the sum of the first 1,000. Because of this, it might seem reasonable that the time required to solve the larger case would be greater than for the smaller case. Our goal then is to show how the algorithm’s execution time changes with respect to the size of the problem.
Computer scientists prefer to take this analysis technique one step further. It turns out that the exact number of operations is not as important as determining the most dominant part of the
In the above example,
As another example, suppose that for some algorithm, the exact number of steps is
Although we do not see this in the summation example, sometimes the performance of an algorithm depends on the exact values of the data rather than simply the size of the problem. For these kinds of algorithms we need to characterize their performance in terms of best-case, worst-case, or average-case performance. The worst-case performance refers to a particular data set where the algorithm performs especially poorly, whereas a different data set for the exact same algorithm might have extraordinarily good (best-case) performance. However, in most cases the algorithm performs somewhere in between these two extremes (average-case performance). It is important for a computer scientist to understand these distinctions so they are not misled by one particular case.
A number of very common order of magnitude functions will come up over and over as you study algorithms. These are shown in Table 1
. In order to decide which of these functions is the dominant part of any
Table 1: Common Functions for Big O
f(n) | Name |
---|---|
Constant | |
Logarithmic | |
Linear | |
Log linear | |
Quadratic | |
Cubic | |
Exponential |
Figure 1
shows graphs of the common functions from Table 1
. Notice that when n is small, the functions are not very well defined with respect to one another. It is hard to tell which is dominant. However, as n grows, there is a definite relationship and it is easy to see how they compare with one another.

As a final example, suppose that we have the fragment of Python code shown in Listing 2
. Although this program does not really do anything, it is instructive to see how we can take actual code and analyze performance.
Listing 2
a = 5
b = 6
c = 10
for i in range(n):
for j in range(n):
x = i * i
y = j * j
z = i * j
for k in range(n):
w = a * k + 45
v = b * b
d = 33
The number of assignment operations is the sum of four terms. The first term is the constant 3, representing the three assignment statements at the start of the fragment. The second term is

Figure 2 <fig_graphfigure2>
shows a few of the common Big O functions as they compare with the
Self Check
Write two Python functions to find the minimum number in a list. The first function should compare each number to every other number on the list.
创建日期: 2023年10月10日