随着城市化步伐的加快,城市里的车也越来越多,车一多就需要找地方停,因此“车位”一词对大家来说应该不会陌生。车位按空间大小又分微型、小型、中型、大型、子母型等等,衡量车位的标准就是车位大小。
在算法的世界里,又应该以哪种方式来衡量算法的效率呢?
在日常工作中,我们经常听到这样的说法:A算法比B算法快一倍。通过以下分析,我们很容易发觉这句话存在问题。
- 数据量为常量K的时候,A算法和B算法一样快;
- 数据量为常量K*2的时候,A算法比B算法快一倍;
- 数据量为常量K/2的时候,A算法是B算法的一半;
其实衡量算法的效率,是和数据量有关的。
无序数组的插入
无序数据的插入算法是和数组个数无关的,新数据插入的位置是在数组的末尾array[nElements],插入完成之后nElements增加1。无论数组的长度为多少,一次插入的时间都是相同的。换句话说,我们插入数组的时间T为常量K。
T = K
现实中,K的值受cpu时间片,书写代码程序的效率等有关。
线性数组的查找
我们假设数组的长度为N,数组查找的时间T和N/2成正比,将2合并为常量,可以用下面公式来表达。
T = K * N
二分查找
二分查找又叫折半查找,是对有序数组进行查找的一种高效率算法,比线性数组查找效率更高。随着数据量的增加,查找的时间可以用以下公式来表达。
T = K * logN
准确地说,这儿的对数应该是以2为底。因为不管对数的底为多少,都可以看成底为2的对数乘上一个常量(例如:log2N = 3.32 * log10N),所以这儿可以忽略对数的底。
说到这儿,我们可以引出大O表示法了。大O表示法使用大写字母O,可以简单认为是Order by(略等于)的意思。它是上述公式的抽象,并且省略掉了常量K。综合一些简单的算法,我们可以罗列出他们效率的大O表示。
算法 | 大O表示法的运行时间 |
---|---|
线性查找 | O(N) |
二分查找 | O(logN) |
无序数组的插入 | O(1) |
有序数组的插入 | O(N) |
无序数组的删除 | O(N) |
有序数组的删除 | O(N) |
表格中罗列出了他们的大O表示法。通过比较不同的大O表示,我们可以比较直观地观察出他们的效率:O(1)效率最高,O(logN)良好,O(N)还行,O(N²)要差一些。
大O表示法的本质并不是给出算法执行的实际值,而是表达了效率如何受数据个数的影响。