python:列表查找与dict查找

python:列表查找与dict查找,python,list,dictionary,Python,List,Dictionary,我写了一段代码,其中列表大小随着每次迭代而增加,迭代次数可以达到近100000次 样本: def do_something(): Lst.append(k) while N < 100000: if k not in Lst: do_something() def do_something(): 附加(k) 当N

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

样本:

def do_something():
    Lst.append(k)

while N < 100000:
    if k not in Lst:
        do_something()
def do_something():
附加(k)
当N<100000时:
如果k不在Lst中:
做某事
现在,我注意到这个方法花了很长时间才完成。请注意,我确实设置了setrecursionlimit()。事实上,令人尴尬的是,这个程序持续运行了几个小时

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

def do_something():
    Dct[k] = True

while N < 100000:
    if Dct[k] == False:
        do_something()
def do_something():
Dct[k]=真
当N<100000时:
如果Dct[k]==False:
做某事

代码运行速度大大加快。在阅读了SOF()上的几篇对话之后,我意识到它并不是列表速度慢,而是如何处理较大列表数据的内存。该网站揭示了列表和dict查找时间的复杂性。对于列出它的O(n),其中作为Dct查找是O(1)。这就是Dct性能更好的原因吗?列表查找和Dict查找的执行情况如何

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

另一方面,python字典使用A来测试成员资格。每个键都经过哈希运算(减少为一个数字),然后将数字转换为表中的索引。如果在该位置找到的密钥与正在测试的密钥相同,则会找到匹配项。散列可能会导致冲突(两个值散列到同一个表索引),但是Python字典实现有一个算法,可以高效地查找下一个插槽。如果发现一个空插槽,说明安全壳测试失败,钥匙不存在

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

如果您很好奇,并且对C理解得足够好,那么可以查看一下,以了解所有(有良好文档记录的)详细信息。您还可以观看关于CPython
dict
如何工作的文章,或者选择一份,其中包括一章关于Andrew Kuchling编写的实现

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

some_set = set()

def do_something():
    some_set.add(k)

while N < 100000:
    if k not in some_set:
        do_something()
some_set=set()
定义做某事():
一些集合。添加(k)
当N<100000时:
如果k不在某个集合中:
做某事

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

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

另一方面,python字典使用A来测试成员资格。每个键都经过哈希运算(减少为一个数字),然后将数字转换为表中的索引。如果在该位置找到的密钥与正在测试的密钥相同,则会找到匹配项。散列可能会导致冲突(两个值散列到同一个表索引),但是Python字典实现有一个算法,可以高效地查找下一个插槽。如果发现一个空插槽,说明安全壳测试失败,钥匙不存在

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

如果您很好奇,并且对C理解得足够好,那么可以查看一下,以了解所有(有良好文档记录的)详细信息。您还可以观看关于CPython
dict
如何工作的文章,或者选择一份,其中包括一章关于Andrew Kuchling编写的实现

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

some_set = set()

def do_something():
    some_set.add(k)

while N < 100000:
    if k not in some_set:
        do_something()
some_set=set()
定义做某事():
一些集合。添加(k)
当N<100000时:
如果k不在某个集合中:
做某事

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

使用
set
而不是
dict
会更好。使用
set
而不是
dict
会更好。谢谢。我将参考你提到的资源。所以我们可以考虑,把循环作为一个线性搜索吗?@杜尔卡:列表上的成员测试是一个线性搜索,所以<代码> K不在LST < /代码>是问题。谢谢,我想我明白了,追加并不需要扫描整个列表,只是列表的最后一个索引,但正如您提到的,会员资格测试要求至少扫描一次列表以进行检查。我以前从未使用过set(),我将尝试一下。再次感谢!感谢链接到pycon talk Martijn。我以前以为迪克用桶或b型树。很高兴知道实际执行情况。谢谢。我将参考你提到的资源。所以我们可以考虑,把循环作为一个线性搜索吗?@杜尔卡:列表上的成员测试是一个线性搜索,所以<代码> K不在LST < /代码>是问题。谢谢,我想我明白了,追加并不需要扫描整个列表,只是列表的最后一个索引,但正如您提到的,会员资格测试要求至少扫描一次列表以进行检查。我以前从未使用过set(),我将尝试一下。再次感谢!感谢链接到pycon talk Martijn。我以前以为迪克用桶或b型树。很高兴知道实际执行情况。