内置类型操作的时间复杂度¶
本页面记录了 CPython 中各种内置类型操作的时间复杂度。其他 Python 实现可能具有不同的性能表现。此外,下面列出的时间复杂度假定操作对象是内置类型本身,对于这些类型的子类的实例,相同操作的开销可能有所不同。
本页面中使用 Big O notation 来表示某个操作所需的运行时间随输入规模增长的速度。除非另有说明,n 代表当前这个容器中的元素数量,k 表示某个数值参数的值,例如索引或重复次数。
list¶
列表是可变的序列;有关实现的更多细节,请参阅 列表是如何在 CPython 中实现的?。最大的开销通常来自超出当前分配大小后的扩展(因为所有元素都必须移动),或来自在接近起始位置处插入或删除元素(因为该位置之后的所有元素都必须移动)。如果需要在两端同时添加或删除元素,可以考虑改用 collections.deque。
运算 |
复杂度 |
|---|---|
拷贝 ( |
O(n) |
添加 ( |
O(1) |
O(n - k) |
|
O(n - k) |
|
获取条目 ( |
O(1) |
设置条目 ( |
O(1) |
删除条目 ( |
O(n - k) |
迭代 |
O(n) |
获取切片 ( |
O(j - i) |
设置切片 ( |
如果 len(t) == j - i 则为 O(j - i),否则为 O(n - i + len(t)) |
删除条目 ( |
O(n - i) |
O(len(t)) |
|
排序 ( |
O(n log n) |
拼接 ( |
O(len(l1) + len(l2)) |
相乘 ( |
O(nk) |
|
O(n) |
|
O(n) |
获取长度 ( |
O(1) |
tuple¶
tuple 是一个 不可变 序列。由于元组永远不会改变,因此不存在插入或删除开销;创建副本只会返回同一个对象,因此属于常数时间操作(O(1))。
运算 |
复杂度 |
|---|---|
拷贝 ( |
O(1) |
获取条目 ( |
O(1) |
获取切片 ( |
O(j - i) |
拼接 ( |
O(len(t1) + len(t2)) |
相乘( |
O(nk) |
迭代 |
O(n) |
|
O(n) |
|
O(n) |
获取长度( |
O(1) |
dict, frozendict¶
dict 对象中列出的时间均为平均情况下的时间;这些时间假设对象的哈希函数具有足够的鲁棒性,从而使得碰撞发生概率较低。同时,这些时间还假设键在可能的键集合中分布良好。在最坏情况下,当每个键哈希到相同值时,以下每项 O(1) 操作的实际耗时将变为 O(n)。此外,这些时间还假设键的哈希运算与比较操作的时间复杂度为 O(1)。有关实现的更多细节,请参阅 字典是如何在 CPython 中实现的?。
frozendict 是不可变的,因此不支持对其中条目进行设置、删除或更新。以下其他操作同样以相同的开销对其生效。
运算 |
复杂度 |
|---|---|
|
O(1) |
O(n) |
|
获取元素( |
O(1) |
设置元素( |
O(1) |
删除元素( |
O(1) |
O(len(t)) |
|
迭代 [7] |
O(n) |
获取长度( |
O(1) |
set, frozenset¶
可将 dict 视为参考实现,因为 set 和 frozenset 的实现方式相似,且同样存在上述注意事项。在最坏情况下,原本为 O(1) 次操作的耗时会增至 O(n);而需要遍历每个元素的操作,其性能也会相应下降。
frozenset 即为 不可变,因此不支持添加、丢弃或就地更新操作。以下其他操作同样以相同代价适用于它。
运算 |
复杂度 |
|---|---|
|
O(1) |
O(n) |
|
添加( |
O(1) |
丢弃( |
O(1) |
并集( |
O(len(s1) + len(s2)) |
O(len(s2)) |
|
O(min(len(s1), len(s2))) |
|
O(min(len(s1), len(s2))) |
|
O(len(s1)) |
|
O(min(len(s1), len(s2))) |
|
对称差集( |
O(len(s1) + len(s2)) |
对称差集更新( |
O(len(s2)) |
获取长度( |
O(1) |
str, bytes, bytearray¶
str 和 bytes 对象分别是不可变的字符序列和字节序列。与元组类似,复制其中一个对象会返回原始对象。bytearray 是可变的,此外还以相同的开销支持 list 的修改操作(sort() 除外)。不过,使用 del (del b[0]、del b[:k])从前端删除时,只会将缓冲区起始位置前移,而不会移动剩余的字节;其摊还复杂度为 O(1)。
运算 |
复杂度 |
|---|---|
获取元素( |
O(1) |
获取切片( |
O(j - i) |
拼接( |
O(len(s) + len(t)) |
相乘( |
O(nk) |
子字符串搜索 ( |
O(n) |
O(n × len(x)) |
|
编码或解码 [13] |
O(n) |
迭代 |
O(n) |
获取长度( |
O(1) |
memoryview¶
memoryview 对象允许 Python 代码在不进行复制的情况下访问支持 buffer protocol 的对象内部数据。具体而言,对内存视图进行切片操作会返回一个指向同一缓冲区的新视图。
运算 |
复杂度 |
|---|---|
创建( |
O(1) |
获取元素( |
O(1) |
获取切片( |
O(1) |
O(n) |
|
计数( |
O(n) |
转换为字节( |
O(n) |
获取长度( |
O(1) |
range¶
range 对象会根据其 start、stop 和 step 值按需计算其中的项目,因此大多数操作并不依赖于该范围的长度。
运算 |
复杂度 |
|---|---|
获取元素( |
O(1) |
获取切片( |
O(1) |
|
O(1) |
索引并计数 ( |
O(1) |
迭代 |
O(n) |
|
O(n) |
获取长度( |
O(1) |