0206:数据结构-大O表示法

发表信息: by Creative Commons Licence

本文依照学习难度,分成入门、进阶两个部分。

入门部分以直观、易于理解为主;进阶部分重点在于概念、推导等。

目录

入门

在使用算法时,总是会提及性能好、速度快,那么如何度量好与快呢?

使用 O(n),n为操作数

大O表示法让你能够比较操作数,它指出了算法运行时间的增速

关键词:操作数、增速

比如,在查找算法里,同样是在N个数里查找元素

简单查找和二分查找有这样的差异

|---------------------+------------+-----------------|
|                        简单查找  |    二分查找     | 
|---------------------|:-----------|:---------------:|
| 100个元素           |   100毫秒  |     7毫秒       |
| 10,000个元素        |   10秒     |     14毫秒      | 
| 1000,000,000个元素  |   11天     |     32毫秒      |
|---------------------+------------+-----------------|

可以看到随着元素个数的增加,差距越来越大。

有鉴于此,仅知道算法需要多长时间才能运行完毕还不够,还需要知道运行时间如何随列表增长而增加

特别注意的是,O(n)里面的n并不是指以秒为单位的速度,而是执行的操作数量。

为啥是n次呢,也可能第一个就找到了,O(n)是按照最糟糕情形来计算的,也就是n个元素,最后一个才找到自己想要的

O(n) 和 O(logn) 区别在哪里

目前使用大O表示法,log指的都是log2

一些常见的大O运行时间 O(logn):对数时间,例如:二分查找 O(n):线性时间,例如:简单查找 O(nlogn):例如:快速排序 O(n^2):例如:选择排序 O(n!):例如:旅行商问题

看电话簿里每个人的名字,需要n次,只看其中的A开头,O(n)并不会变成O(n/26),而依旧是O(n)

因为在很多情况下,常量无关紧要,比如

但有时候,常量的影响很大,例如在快速查找、合并查找情形下。

运行时间:

取决于输入

如果输入序列已经有序,那插入排序需要做的工作就很少了

如果输入序列是逆序,那情况最糟糕,需要大量的工作,不得不把所有元素的都整理一遍

取决于输入规模

规模越大,运行时间就越长,因此把输入规模参数化,把运行时间看做待排列数据规模的函数

一般想知道运行时间的上限,也就是想知道运行时间是不会超过某个特定量的。这代表了对用户的一种承诺。

告诉你:运行时间至少3s和最多3s,意义完全不一样

对算法有各种各样的分析,其中一种叫做“最坏情况分析”

此时,T(n)定义为输入规模为n时的最长运行时间,是一个函数关系,而不是相关关系。因为它需要将输入,最大化输出出来,一一对应。

有时候,也会讨论“平均情况”

这时,T(n)就是输入规模n下所有可能输入的期望时间。

这里期望指的是:每种输入的运行时间乘以那种输入出现的概率

但是一般不知道这个概率是多少 ==> 做假设(做假设需要符合哪些条件呢?) ==> 一个有关输入的统计分布的假设

最常见的假设之一就是:所有输入都是以等可能方式出现的,即所谓均匀分布

也有“最好情况假设”,一般人们喜欢把最好情况称为“假象”

因为一个人研发出了一个很慢速的算法,但是他拿最好的情况做说明,更像是一种欺骗行为了。

有人说,那运行速度也很受硬件设备的影响。

因此,在比较算法的时候,通常比较的是其相对速度,也就是假设两个算法在同一台机器上。

进阶

[1] 算法图解 Aditya Bhargava (作者) 袁国忠 (译者)