Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

大O表示法、时间复杂度、空间复杂度 #77

Open
aermin opened this issue Apr 18, 2020 · 0 comments
Open

大O表示法、时间复杂度、空间复杂度 #77

aermin opened this issue Apr 18, 2020 · 0 comments

Comments

@aermin
Copy link
Owner

aermin commented Apr 18, 2020

先复习下数学知识

image

大O表示法

image

大O表示法 让你能够比较操作数,它指出了算法运行时间的增速。
一个操作要花费某些单位时间,所以此次运算的操作数越多,时间自然越长了

所以图中的O(log n) 比 O(n) 操作数(纵坐标)的值随着元素的增大而上升得小越来越多,运行时间更少

算法的运行时间用大O表示法表示。

image
image

算法时间复杂度定义

T(n)=O(f(n))

T(n): 执行次数
f(n): 问题规模n的某个函数

一般情况下,随着n的增大,T(n)增长最慢的算法为最优算法。

常数阶

int sum = 0,n = 100; /* 执行一次 */

sum = (1 + n) * n / 2; /* 执行一次 */

printf("%d", sum); /* 执行一次 */

这个算法的运行次数函数是f(n)=3。 根据我们推导大O阶的方法, 第 一步就是把常数项3改为1。在保留最高阶项时发现,它根本没有最高阶项,所以这个算法的时间复杂度为O(1)。

线性阶

for (let i = 0; i < n; i++)

{ /* 时间复杂度为O(1)的程序步骤序列 */

}

下面这段代码,它的循环的时间复杂度为O(n),因为循环体中的代码需要执行n次。

对数阶

let count = 1;

while (count < n) {
    count = count * 2;
    /* 时间复杂度为O(1)的程序步骤序列 */
}

由于每次count乘以2之后,就距离n更近了一分。也就是说,有多少 个2相乘后大于n, 则会退出循环。 由2 x =n得到x=log 2 n。 所以这个 循环的时间复杂度为O(logn)。

平方阶

for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
        /* 时间复杂度为O(1)的程序步骤序列 */
    }
}

这是一个循环嵌套,它的内循环刚才我们已经分析过,时间复杂度为O(n)。

而对于外层的循环,不过是内部这个时间复杂度为O(n)的语句,再循环n次。所以这段代码的时间复杂度为O(n^2 )。

for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
        /* 时间复杂度为O(1)的程序步骤序列 */
    }
}

如果外循环的循环次数改为了m,时间复杂度就变为O(m×n)。

所以我们可以总结得出,循环的时间复杂度等于循环体的复杂度乘以 该循环运行的次数。

因此,我们可以总结推到大O阶的规律。

推导大O阶

1.用常数1取代运行时间中的所有加法常数。
2.在修改后的运行次数函数中,只保留最高阶项。
3.如果最高阶项存在且不是1,则去除与这个项相乘的常数。

下面这个循环嵌套,它的时间复杂度是多少呢?

for (let i = 0; i < n; i++) {
    /* 注意j = i 而不是0 */
    for (let j = i; j < n; j++) {
       /* 时间复杂度为O(1)的程序步骤序列 */
    }
}

由于当i=0时, 内循环执行了n次, 当i=1时, 执行了n-1次, ……当 i=n-1时,执行了1次。所以总的执行次数为:

image

第一条,没有加法常数不予考虑;
第二条, 只保留最高阶项,因此保留n^2/2;
第三条,去除这个项相乘的常数, 也就是去除1/2,最终这段代码的时间复杂度为O(n^2)。

image

常用的时间复杂度所耗费的时间从小到大依次是:

image

最坏情况与平均情况

最坏情况运行时间是一种保证,那就是运行时间将不会再坏了。在应用中,这是一种最重要的需求,通常,除非特别指定,我们提到的运行时间都是最坏情况的运行时间。

平均运行时间是所有情况中最有意义的,因为它是期望的运行时间。 也就是说,我们运行一段程序代码时,是希望看到平均运行时间的。 可现实中,平均运行时间很难通过分析得到,一般都是通过运行一定数量的实验数据后估算出来的。

对算法的分析,一种方法是计算所有情况的平均值,这种时间复杂度的计算方法称为平均时间复杂度。另一种方法是计算最坏情况下的时 间复杂度,这种方法称为最坏时间复杂度。一般在没有特殊说明的情 况下,都是指最坏时间复杂度。

空间复杂度

算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂 度的计算公式记作:S(n)=O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。

通常,我们都使用“时间复杂度”来指运行时间的需求,使用“空间复杂 度”指空间需求

最后

我们一般会选择效率最高的算法,以最大限度地减少运行时间或占用空间。

时间复杂度 => 运行时间
空间复杂度 => 占用空间

Reference

https://medium.com/@yk392/big-o-notation-e35e17febc05
《大话数据结构》

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant