4.2 评价python列表
列表操作 | 最坏情况 |
v = list() | O(1) |
v = [0] * n | O(n) |
v[i] = x | O(1) |
v.append(x) | O(n) |
v.extend(w) | O(n) |
v.insert(x) | O(n) |
v.pop() | O(n) |
遍历 | O(n) |
列表遍历,遍历是对列表的每个元素进行一定的操作,很显然其步骤执行次数是O(n)。
列表创建,有以下两种方式:
- temp = list()
- valueList = [0] * n
向列表添加一个元素,这就要看此时底层数组的情况了。如果底层数组没满,则只需在数组的后一位设为相应值即可,但是如果底层数组已满,就必须先创建容量更大的底层数组,这需要O(1),其次是将列表中每一个元素复制到新建的底层数组中,这也同样隐含了遍历的意思,其时间复杂度是O(n)。最后是消除旧数组,需要O(1)。
扩展列表
假设两列表长度都是n,如果底层数组有足够的空间,则直接将另一数组直接复制,注意这也隐含了遍历的意思。如果底层数组的空间不足,则象上述那样,先创建新的,再复制,也是一种遍历,销毁旧数组。总时间复杂度都是O(n)和O(n)(2n)。
插入和删除
也是O(n)
4.3 平摊分析(Amortozed analysis)
列表的append()执行时间依赖于底层数组。
对于如下代码,n是2的指数次方,并且底层数组每次都是2倍的容量扩张,可以计算出以下代码的执行时间。这被称为统计分析(aggregate method)。
>>> L = list()
>>> for i in range(1, n+1) :
... L.append(i)
si表示列表储存第i个值所需时间(注意是包括了底层数组有容量时和底层数组扩容后),而ei则表示底层数组扩容所需时间。
所以在上述列表中添加入16个元素,则需16 + 15 = 31 < 2 * 16的时间,对于n个元素,可以肯定的是不会超过2 * n。由于底层数组扩容的次数比较少,大部分是直接添加,所以添加n个元素的平摊成本(Amortized cost)就不会超过2 * n / n = 2,也就是常数时间,即O(1)。
平摊分析(Amortized analysis)是通过计算平均成本来衡量一系列操作的时间复杂度的过程。
注意平摊成本并不等于平均情况时间,前者是计算一系列操作的平均成本,这一系列操作中,大部分所需时间较少,只有少数需要时间较长;而后者是对所有可能输入进行平均。(不大理解后者)