【问题标题】:python: list lookup vs dict lookuppython:列表查找与字典查找
【发布时间】:2014-07-21 04:26:59
【问题描述】:

我写了一段代码,其中列表大小随着每次迭代而增加,迭代次数可以达到近 100000 次。

样本:

def do_something():
    Lst.append(k)

while N < 100000:
    if k not in Lst:
        do_something()

现在,我注意到这个方法需要很长时间才能完成。请注意,我确实设置了 setrecursionlimit() 。事实上,够尴尬的,程序一直运行了几个小时。

后来,在尝试寻找优化代码的方法时,我将 Lst 转换为 Dct。所以代码看起来像:

def do_something():
    Dct[k] = True

while N < 100000:
    if Dct[k] == False:
        do_something()

代码运行得更快。在阅读了一些关于 SOF(Repeatedly appending to a large list (Python 2.6.6)) 的对话后,我意识到它不是慢的列表,而是如何处理更大的列表数据的内存。这个网站https://wiki.python.org/moin/TimeComplexity,阐明了列表和字典查找时间复杂度。列出它的 O(n),其中 Dct 查找是 O(1)。这就是 Dct 表现更好的原因吗?列表查找和字典查找执行的精确度如何?

【问题讨论】:

  • 为此使用set 而不是dict 会好得多。

标签: python list dictionary


【解决方案1】:

是的,字典查找需要固定的时间。您的if k not in Lst 可能需要扫描整个列表以查看该号码是否尚未在列表中,然后再追加。正是这种扫描使列表包含测试花费了 O(n) 时间,这就是杀死你的算法的原因。

另一方面,python 字典使用hash table 来测试成员资格。每个键都经过哈希处理(简化为一个数字),然后将数字转换为表中的索引。如果在该位置找到的密钥与您正在测试的密钥相同,则会找到匹配项。散列会导致冲突(两个值散列到同一个表索引),但 Python 字典实现有一个算法,然后以有效的方式寻找下一个槽。如果找到空槽,则收容测试失败,钥匙不存在。

因此,要测试k 是否在您的字典中,对于大多数测试,只需要进行 1 次计算。对于某些人来说,可能需要进行更多测试。但平均而言,查找时间是恒定的。

如果您很好奇并且足够了解 C,请查看 C implementation 了解所有(有据可查的)详细信息。您还可以观看 Pycon 2010 presentation by Brandon Rhodes 了解 CPython dict 的工作原理,或获取 Beautiful Code 的副本,其中包括由 Andrew Kuchling 编写的关于实现的一章。

你想看看set() type;这就像字典一样,是一个具有 O(1) 成员资格测试的无序集合,但只有值,没有键:

some_set = set()

def do_something():
    some_set.add(k)

while N < 100000:
    if k not in some_set:
        do_something()

在内部,set() 对象也使用哈希表。

【讨论】:

  • 谢谢。我会参考你提到的资源。那么我们可以考虑将列表循环作为线性搜索吗?
  • @durga:对列表的成员资格测试是线性搜索,所以k not in Lst 是这里的问题。
  • 谢谢你,我想我明白了,追加并不一定要扫描完整的列表,只是列表的最后一个索引,但正如你提到的,成员资格测试需要扫描一次列表至少要检查。我以前从未使用过 sets(),我会尝试一下。再次感谢!
  • 感谢 pycon talk Martijn 的链接。我之前假设迪克斯使用桶或 b 树。很高兴知道实际的实现。
猜你喜欢
  • 2010-10-05
  • 2021-12-14
  • 2017-11-13
  • 2021-02-27
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 2013-05-09
  • 2021-11-17
相关资源
最近更新 更多