1、这里主要讨论python两种数据类型上各种操作的大O数量级:列表和字典
主要通过运行试验来估计其各种操作运行时间数量级
2、比较list和dict的操作
- 列表的各种操作的实现方法有很多(比如append,可以有多种实现方法),那么具体的,是如何选择哪种实现方法呢?
- 起始总的方案就是,让最常用的操作性能最好,牺牲不太常用的操作。
80/20准则:80%的功能其使用率只有20%。(简单来说,就是保证那些常用的骚操作性能好一点,不太常用的操作可以性能弱一点)
3、List列表数据类型的常用操作类型
- 最常用的是:索引,包括取值和赋值,如v = a[i], a[i] = v
- 列表增长:可以选择append()和__add__()、+
lst.append(v)执行时间是O(1)
lst = lst + [v]执行时间复杂度是O(n+k),k是被加的列表长度
选择哪个方法来操作列表,决定了程序的性能
实验:
- 4 种生成前n个整数列表的方法:
# 1、首先是循环连接列表(+)方式生成
def test1():
l = []
for i in range(1000):
l = l + [i]
# 2、用append方法添加元素生成
def test2():
l = []
for i in range(1000):
l.append(i)
# 3、用列表推导式生成
def test3():
l = [i for i in range(1000)]
# 4、用range函数生成
def test4():
l = list(range(1000))
然后使用timeit模块对函数计时
创建一个 Timer 对象 , 指定需要 反复运行 的 语句和只需要 运行一次 的 “ 安装语句“,然后调用这个对象的 timeit 方法 , 其中可以 指定反复运行多少次
运行结果:
可以看到,4 种方法运行时间差别很大:
列表连接最慢,list range最快,最多相差进200倍。
append也比列表连接快得多,列表推导式的速度是append的两倍左右。
4、list列表基本操作的大O数量级
- 观察上图可以发现,对pop这个操作:
pop()从列表末尾移除元素,O(1)
pop(i)从列表中间删除元素,O(n) ----->补充说明:实际上不一定是n,也可能是n/2等,但是数量级都是n
原因在于python选择的实现方法:从中部移除元素的话,要把移除元素后面的元素全部向前挪位复制一遍,这个看起来比较麻烦,但是这种实现方法能够保证按索引取值和赋值的操作很快,达到O(1),是对常用和不常用操作的折中方案
python对列表的大O数量级:
range < 列表推导式 < append < +
- list.pop()的计时实验
通过改变列表的长度来测试两个操作的增长趋势
将实验数据化成图表,可以看出增长趋势
pop()是常数,pop(0)是线性增长
5、dict字典数据类型
- 字典与列表不同 , 根据关键码 ( key ) 找到数据项 , 而列表是根据位置 ( index )
- 设计一个性能试验来验证list种检索一个值,以及字典中检索一个值(get函数)的时间对比
运行结果:
- 可见,字典的执行时间与字典的规模无关,是常数
- 列表的执行时间随着列表规模增大而线性上升
大多数情况下,dict比list更高效
6、pythong官方的算法复杂度网站:https://wiki.python.org/moin/TimeCompl