【发布时间】:2012-02-14 07:15:56
【问题描述】:
python wiki 说:“使用集合和字典进行成员资格测试 O(1) 比搜索序列 O(n) 快得多。在测试“a in b”时,b 应该是集合或字典,而不是一个列表或元组。”
每当速度在我的代码中很重要时,我一直在使用集合代替列表,但最近我一直想知道为什么集合比列表快得多。谁能解释一下,或者指向一个可以解释的来源,python 的幕后究竟发生了什么以使集合更快?
【问题讨论】:
python wiki 说:“使用集合和字典进行成员资格测试 O(1) 比搜索序列 O(n) 快得多。在测试“a in b”时,b 应该是集合或字典,而不是一个列表或元组。”
每当速度在我的代码中很重要时,我一直在使用集合代替列表,但最近我一直想知道为什么集合比列表快得多。谁能解释一下,或者指向一个可以解释的来源,python 的幕后究竟发生了什么以使集合更快?
【问题讨论】:
list:想象一下,你正在衣柜里找袜子,但你不知道袜子在哪个抽屉里,所以你必须一个抽屉一个抽屉地搜索,直到找到它们(或者也许你永远不会这样做)。这就是我们所说的O(n),因为在最坏的情况下,您会查看所有抽屉(其中n 是抽屉的数量)。
set:现在,假设您仍在衣橱里寻找袜子,但现在您知道袜子在哪个抽屉里了,比如在第三个抽屉里。因此,您将只在第三个抽屉中搜索,而不是在所有抽屉中搜索。这就是我们所说的O(1),因为在最坏的情况下,您只会看到一个抽屉。
【讨论】:
list / set 中的元素或元素的内存位置?
集合是使用hash tables 实现的。每当您将对象添加到集合中时,set 对象在内存中的位置是使用要添加的对象的哈希确定的。在测试成员资格时,需要做的基本上就是查看对象是否在其哈希确定的位置,因此此操作的速度不取决于集合的大小。相反,对于列表,需要搜索整个列表,随着列表的增长,搜索速度会变慢。
这也是集合不保留您添加的对象顺序的原因。
请注意,一般来说,集合并不比列表快——成员资格测试对集合来说更快,删除元素也是如此。只要您不需要这些操作,列表通常会更快。
【讨论】:
我认为你需要好好看看一本关于数据结构的书。基本上,Python 列表实现为dynamic arrays,集合实现为hash tables。
这些数据结构的实现赋予了它们截然不同的特征。例如,哈希表的查找时间非常快,但无法保留插入顺序。
【讨论】:
Python 使用 hashtables,它的查找时间为 O(1)。
【讨论】:
虽然到目前为止我还没有测量任何与 python 相关的性能,但我仍然想指出,列表通常更快。
是的,你有 O(1) 与 O(n)。但请始终记住,这仅提供有关某物的渐近行为的信息。这意味着如果你的 n 非常高,O(1) 总是会更快 - 从理论上讲。但在实践中,n 通常需要比您通常的数据集大得多。
所以集合本身并不比列表快,但前提是你必须处理大量元素。
【讨论】:
基本上,取决于您正在执行的操作……
*对于添加一个元素 - 那么一个集合不需要移动任何数据,它所要做的就是计算一个哈希值并将其添加到一个表中。对于列表插入,则可能存在要移动的数据。
*对于删除一个元素 - 一个集合需要做的就是从哈希表中删除哈希条目,对于一个列表它可能需要移动数据(平均 1/2 的数据。
*对于搜索(即 in 运算符) - 一个集合只需要计算数据项的哈希值,在哈希表中找到该哈希值,如果存在 - 然后宾果游戏。对于列表,搜索必须依次查找每个项目 - 平均为列表中所有术语的 1/2。即使对于 1000 多个项目,一组搜索也会快得多。
【讨论】:
必须逐个搜索列表,其中集合或字典具有索引以便更快地搜索。
【讨论】:
实际上,在每种情况下,集合并不比列表速度。通常,列表比集合速度快。 但是在搜索集合中的元素的情况下,它是速度,因为集合是使用哈希表实现的。所以基本上它不需要搜索完整的集合,所以平均时间复杂度是 O(1)。列表使用动态数组,它应该在完整数组中查找。所以它需要O(n)。 n 是列表的大小。
所以最后我们可以看到集合在某些情况下更好,而列表在某些情况下更好。由我们来根据我们的任务选择合适的数据结构。
【讨论】: