List和Dict的in操作对比
首先设计一个性能试验来验证list中检索一个值,以及dict中检索一个值的计时对比
生成包含连续值的list和包含连续关键码key的dict,用随机数来检验操作符in的耗时
import timeit
import random
for i in range(10000,1000001,20000):
t = timeit.Timer("random.randrange(%d) in x"%i,
"from __main__ import random,x")
x = list(range(i))
lst_time = t.timeit(number=1000)
x = {j:None for j in range(i)}
d_time = t.timeit(number=1000)
print("%d,%10.3f,%10.3f" % (i, lst_time, d_time))
下表是程序运行的结果
规模大小 | 列表搜索所用时间 | 字典搜索所用时间 |
---|---|---|
10000 | 0.062 | 0.001 |
30000 | 0.189 | 0.001 |
50000 | 0.329 | 0.001 |
70000 | 0.440 | 0.001 |
90000 | 0.582 | 0.001 |
110000 | 0.710 | 0.001 |
130000 | 0.840 | 0.001 |
150000 | 0.951 | 0.001 |
170000 | 1.077 | 0.001 |
190000 | 1.227 | 0.001 |
210000 | 1.377 | 0.001 |
230000 | 1.499 | 0.001 |
250000 | 1.618 | 0.001 |
270000 | 1.738 | 0.001 |
290000 | 1.892 | 0.001 |
310000 | 2.055 | 0.001 |
从上表我们可以看到list的查找效率远远低于dict的效率,原因如下:
python中list对象的存储结构采用的是线性表,因此其查询复杂度为O(n),而dict对象的存储结构采用的是散列表,其在最优情况下查询复杂度为O(1)。
散列表的基本概念:
散列表(hash table,又称哈希表)是一种数据集,其中数据项的存储方式尤其有利于将来快速的查找定位。散列表中的每一个存储位置,称为槽(slot),可以用来保存数据项,每个槽有一个唯一的名称。实现从数据项到存储槽名称的转换的,称为散列函数(hash function)。下面示例中,散列函数接受数据项作为参数,返回整数值0~10,表示数据项存储的槽号(名称)。
散列表示例:
数据项:54,26,93,17,77,31
本例中我们的散列函数是最简单的求余:
按照散列函数h(item),为每个数据项计算出存放的位置之后,就可以将数据项存入相应的槽中。
Item | Hash value |
---|---|
54 | 10 |
26 | 4 |
93 | 5 |
17 | 6 |
77 | 0 |
31 | 9 |
要查找某个数据项是否存在于表中,我们只需要使用同一个散列函数,对查找项进行计算,测试下返回的槽号所对应的槽中是否有数据项即可,从而实现了O(1)时间复杂度的查找算法。