问题中的代码只做一件事:将文件中的所有单词填充到列表中。复杂度是 O(n)。
将相同的单词填充到任何其他类型的容器中仍然至少具有 O(n) 复杂度,因为它必须从文件中读取所有单词并且必须将所有单词放入容器中。
dict 有什么不同?
找出某个东西是否在list 中具有O(n) 复杂度,因为算法必须逐项遍历列表并检查它是否是查找的项。该项目可以在位置 0 找到,这很快,或者它可能是最后一个项目(或根本不在列表中),这使得它成为 O(n)。
在dict 中,数据被组织在“buckets” 中。当键:值对保存到dict 时,会计算键的hash,并使用该数字来标识存储数据的bucket。稍后,当查找密钥时,再次计算hash(key) 以识别存储桶,然后仅搜索该存储桶。每个bucked通常只有一个key:value对,因此搜索可以在O(1)中完成。
更多详情,请参阅the article about DictionaryKeys on python.org。
set 怎么样?
集合类似于只有键而没有值的字典。该问题包含以下代码:
word_dict = dict((elt, 1) for elt in word_list)
这显然是一个不需要值的字典,所以一个集合会更合适。
顺便说一句,没有必要先创建一个列表word_list,然后将其转换为set 或dict。第一步可以跳过:
set_of_words = {elt.strip() for elt in open("bible_words.txt", "r").readlines()}
有什么缺点吗?
总是;)
集合没有重复项。因此,计算一个单词在集合中出现的次数永远不会返回 2。如果需要,请不要使用集合。
一组未排序。没有办法检查哪个是集合中的第一个单词。如果需要,请不要使用集合。
保存到集合的对象必须是可散列的,这意味着它们是不可变的。如果可以修改对象,那么它的 hash 会改变,所以它会在错误的存储桶中并且搜索它会失败。无论如何,str、int、float 和 tuple 对象是不可变的,所以至少它们可以进入集合。
写入 到集合可能会比写入列表要慢一些。仍然是 O(n),但是更慢的 O(n),因为它必须计算散列并组织到桶中,而列表只是一个接一个地转储一个项目。请参阅下面的时间安排。
从集合中读取所有内容也会比从列表中读取所有内容要慢一些。
所有这些都适用于dict 以及set。
一些计时例子
写入列表与集合:
>>> timeit.timeit('[n for n in range(1000000)]', number=10)
0.7802875302271843
>>> timeit.timeit('{n for n in range(1000000)}', number=10)
1.025623542189976
从列表与集合中读取:
>>> timeit.timeit('989234 in values', setup='values=[n for n in range(1000000)]', number=10)
0.19846207875508526
>>> timeit.timeit('989234 in values', setup='values={n for n in range(1000000)}', number=10)
3.5699193290383846e-06
因此,写入集合似乎慢了大约 30%,但是当有数千个项目时,在集合中找到一个项目的速度要快数千倍。