线性查找并不总是O(N)的。当要找的元素在数组末尾,那确实是O(N)。但如果它在数组开头,1 步就能找到的话,那么技术上来说应该是O(1)。所以概括来说,线性查找的最好情况是O(1),最坏情况是O(N)。虽然大O可以用来表示给定算法的最好和最坏的情景,但若无特别说明,大O 记法一般都是指最坏情况。因此尽管线性查找有O(1)的最好情况,但大多数资料还是把它归类为O(N)。
这种悲观主义其实是很有用的:知道各种算法会差到什么程度,能使我们做好最坏打算,以选出最适合的算法。
在同一个有序数组里,二分查找比线性查找要快。
用大O 记法描述二分查找:它不能写成O(1),因为二分查找的步数会随着数据量的增长而增长。它也不能写成O(N),因为步数比元素数量要少得多,正如之前我们看到的,包含100 个元素的数组只要7 步就能找完。
二分查找的时间复杂度介于O(1)和O(N)之间。二分查找的大O 记法是:O(log N) 读作“O log N”。归于此类的算法,它们的时间复杂度都叫作对数时间。
O(log N)意味着该算法当数据量翻倍时,步数加1。
3 种时间复杂度,按照效率由高到低来排序的话,会是这样:O(1) O(log N) O(N)
O(log N)曲线的微弯,使其效率略差于O(1),却远胜于O(N)。
log 即是对数(logarithm)。对数是指数的反函数。
23 等于:2 × 2 × 2结果为8。log2 8 则将上述计算反过来,它意思是:要把2 乘以自身多少次,才能得到8。因为需要3次,所以,log2 8 = 3。
26 可以解释为:2 × 2 × 2 × 2 × 2 × 2 = 64 因为2 要乘以自身6 次才得到64,所以,log2 64 = 6。
log2 8 可以表达为:将8 不断地除以2 直到1,需要多少个2。8 / 2 / 2 / 2 = 1(注:按照从左到右的顺序计算。)或者说,将8 不断地除以2,要除多少次才能到1 呢?答案是3,所以,log2 8 = 3。
类似地,log2 64 可以解释为:将64 除以2 多少次,才能得到1。64 / 2 / 2 / 2 / 2 / 2 / 2 = 1 因为这里有6 个2,所以,log2 64 = 6。
O(log N)指的是O(log2 N),不过为了方便就省略了2而已。O(N)代表算法处理N 个元素需要N 步。如果元素有8 个,那么这种算法就需要8 步。
O(log N)则代表算法处理N 个元素需要log2 N 步。如果有8 个元素,那么这种算法需要3 步,因为log2 8 = 3。
从另一个角度来看,如果要把8 个元素不断地分成两半,那么得拆分3 次才能拆到只剩1 个元素。
这正是二分查找所干的事情。它就是不断地将数组拆成两半,直至范围缩小到只剩你要找的那个元素。
简单来说,O(log N)算法的步数等于二分数据直至元素剩余1 个的次数。
每次数据量翻倍时,O(N)算法的步数也跟着翻倍,O(log N)算法却只需加1。