I'll do my best to explain it here on simple terms, but be warned that this topic takes my students a couple of months to finally grasp.
(我会尽力在这里简单地解释它,但要注意,这个主题需要我的学生花几个月的时间才能最终掌握。)
You can find more information on the Chapter 2 of the Data Structures and Algorithms in Java book. (您可以在《 Java中的数据结构和算法 》第二章中找到更多信息。)
There is no mechanical procedure that can be used to get the BigOh.
(没有可用于获取BigOh的机械程序 。)
As a "cookbook", to obtain the BigOh from a piece of code you first need to realize that you are creating a math formula to count how many steps of computations get executed given an input of some size.
(作为“食谱”,要从一段代码中获取BigOh ,您首先需要认识到您正在创建一个数学公式,以计算给定大小的输入后执行多少计算步骤。)
The purpose is simple: to compare algorithms from a theoretical point of view, without the need to execute the code.
(目的很简单:从理论的角度比较算法,而无需执行代码。)
The lesser the number of steps, the faster the algorithm. (步骤数越少,算法越快。)
For example, let's say you have this piece of code:
(例如,假设您有这段代码:)
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
}
This function returns the sum of all the elements of the array, and we want to create a formula to count the computational complexity of that function:
(此函数返回数组所有元素的总和,我们想创建一个公式来计算该函数的计算复杂度 :)
Number_Of_Steps = f(N)
So we have f(N)
, a function to count the number of computational steps.
(因此,我们有f(N)
,它是一个计算计算步数的函数。)
The input of the function is the size of the structure to process. (函数的输入是要处理的结构的大小。)
It means that this function is called such as: (这意味着将调用该函数,例如:)
Number_Of_Steps = f(data.length)
The parameter N
takes the data.length
value.
(参数N
取data.length
值。)
Now we need the actual definition of the function f()
. (现在我们需要函数f()
的实际定义。)
This is done from the source code, in which each interesting line is numbered from 1 to 4. (这是从源代码完成的,其中每个有趣的行从1到4编号。)
There are many ways to calculate the BigOh.
(有许多方法可以计算BigOh。)
From this point forward we are going to assume that every sentence that doesn't depend on the size of the input data takes a constant C
number computational steps. (从这一点出发,我们将假定不依赖于输入数据大小的每个句子都采用恒定的C
数计算步骤。)
We are going to add the individual number of steps of the function, and neither the local variable declaration nor the return statement depends on the size of the data
array.
(我们将添加函数的各个步骤,并且局部变量声明和return语句都不依赖于data
数组的大小。)
That means that lines 1 and 4 takes C amount of steps each, and the function is somewhat like this:
(这意味着第1行和第4行每个都执行C步,并且函数有点像这样:)
f(N) = C + ??? + C
The next part is to define the value of the for
statement.
(下一部分是定义for
语句的值。)
Remember that we are counting the number of computational steps, meaning that the body of the for
statement gets executed N
times. (请记住,我们正在计算计算步骤的数量,这意味着for
语句的主体被执行了N
次。)
That's the same as adding C
, N
times: (这与将C
相加N
次相同:)
f(N) = C + (C + C + ... + C) + C = C + N * C + C
There is no mechanical rule to count how many times the body of the for
gets executed, you need to count it by looking at what does the code do.
(没有机械规则来计算for
主体执行多少次,您需要通过查看代码的作用来计算它。)
To simplify the calculations, we are ignoring the variable initialization, condition and increment parts of the for
statement. (为了简化计算,我们忽略了for
语句的变量初始化,条件和增量部分。)
To get the actual BigOh we need the Asymptotic analysis of the function.
(为了获得实际的BigOh,我们需要对该函数进行渐近分析 。)
This is roughly done like this: (大致是这样完成的:)
- Take away all the constants
C
. (带走所有常数C
)
- From
f()
get the polynomium in its standard form
. (从f()
获得standard form
的多项式 。)
- Divide the terms of the polynomium and sort them by the rate of growth.
(除以多项式的项,然后按增长率对其进行排序。)
- Keep the one that grows bigger when
N
approaches infinity
. (当N
接近infinity
大时,保持增长的那个。)
Our f()
has two terms:
(我们的f()
有两个术语:)
f(N) = 2 * C * N ^ 0 + 1 * C * N ^ 1
Taking away all the C
constants and redundant parts:
(除去所有C
常量和冗余部分:)
f(N) = 1 + N ^ 1
Since the last term is the one which grows bigger when f()
approaches infinity (think on limits ) this is the BigOh argument, and the sum()
function has a BigOh of:
(由于最后一项是当f()
接近无穷大(考虑极限 )时会增大的项,因此这是BigOh参数,并且sum()
函数的BigOh为:)
O(N)
There are a few tricks to solve some tricky ones: use summations whenever you can.
(有一些技巧可以解决一些棘手的问题:尽可能使用求和 。)
As an example, this code can be easily solved using summations:
(例如,可以使用求和轻松地解决此代码:)
for (i = 0; i < 2*n; i += 2) { // 1
for (j=n; j > i; j--) { // 2
foo(); // 3
}
}
The first thing you needed to be asked is the order of execution of foo()
.
(您需要询问的第一件事是foo()
的执行顺序。)
While the usual is to be O(1)
, you need to ask your professors about it. (虽然通常是O(1)
,但您需要向教授询问。)
O(1)
means (almost, mostly) constant C
, independent of the size N
. (O(1)
表示(几乎,几乎是)常数C
,与大小N
无关。)
The for
statement on the sentence number one is tricky.
(关于第一句的for
语句很棘手。)
While the index ends at 2 * N
, the increment is done by two. (当索引以2 * N
结尾时,增量增加2。)
That means that the first for
gets executed only N
steps, and we need to divide the count by two. (这意味着第一个for
仅执行N
步骤,我们需要将计数除以2。)
f(N) = Summation(i from 1 to 2 * N / 2)( ... ) =
= Summation(i from 1 to N)( ... )
The sentence number two is even trickier since it depends on the value of i
.
(语句编号二是更加棘手,因为它取决于价值i
。)
Take a look: the index i takes the values: 0, 2, 4, 6, 8, ..., 2 * N, and the second for
get executed: N times the first one, N - 2 the second, N - 4 the third... up to the N / 2 stage, on which the second for
never gets executed. (看一下:索引i取值:0、2、4、6、8,...,2 * N,第二个for
执行:N乘以第一个,N-2第二个,N- 4第三个……直到N / 2阶段,第二个for
永远不会执行。)
On formula, that means:
(在公式上,这意味着:)
f(N) = Summation(i from 1 to N)( Summation(j = ???)( ) )
Again, we are counting the number of steps .
(同样,我们正在计算步骤数 。)
And by definition, every summation should always start at one, and end at a number bigger-or-equal than one. (并且根据定义,每次求和应始终始于一个,并以大于或等于1的数字结束。)
f(N) = Summation(i from 1 to N)( Summation(j = 1 to (N - (i - 1) * 2)( C ) )
(We are assuming that foo()
is O(1)
and takes C
steps.)
((我们假设foo()
为O(1)
并采取C
步。))
We have a problem here: when i
takes the value N / 2 + 1
upwards, the inner Summation ends at a negative number!
(我们这里有一个问题:当i
向上取值N / 2 + 1
时,内部求和运算将以负数结束!)
That's impossible and wrong. (那是不可能的,也是错误的。)
We need to split the summation in two, being the pivotal point the moment i
takes 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 )
Since the pivotal moment i > N / 2
, the inner for
won't get executed, and we are assuming a constant C execution c