排序列表的Python“in”关键字的效率

时间:2016-04-14 07:23:54

标签: python sortedlist

如果我有一个已经排序的列表并使用 in 关键字,例如:

a = [1,2,5,6,8,9,10]
print 8 in a

我认为这应该进行顺序搜索,但是我可以通过二进制搜索来加快速度吗? 是否有一种pythonic方式在排序列表中搜索?

2 个答案:

答案 0 :(得分:5)

标准库具有bisect模块,该模块支持按排序顺序进行搜索。

但是,对于小型列表,我敢打赌in运算符后面的C实现会击败bisect。您必须使用一堆常见情况进行测量,以确定目标硬件上真正的收支平衡点...

值得注意的是,如果您可以使用无序迭代(即set),那么您可以在O(1)时间平均进行查找(使用in运算符),与O(logN)上的inO(N)运算符的序列的二分相比,lambda。而且,通过一组,您还可以避免首先对其进行排序的成本: - )。

答案 1 :(得分:3)

标准库中的模块bisect中存在Python的二进制搜索。它不支持in / contains,但您可以编写一个小函数来处理它:

from bisect import bisect_left
def contains(a, x):
    """returns true if sorted sequence `a` contains `x`"""
    i = bisect_left(a, x)
    return i != len(a) and a[i] == x

然后

>>> contains([1,2,3], 3)
True
>>> contains([1,2,3], 4)
False

这不会很快,因为bisect是用Python编写的,而不是用C编写的,所以你可能会发现顺序in更快很多情况。 bisect自Python 2.4以来在CPython中有一个可选的C加速。

很难确定CPython的确切收支平衡点。这是因为代码是用C语言编写的;如果你检查的值是否大于或小于序列中的任何值,那么CPU的分支预测将对你起作用,你会得到:

In [2]: a = list(range(100))
In [3]: %timeit contains(a, 101)
The slowest run took 8.09 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 370 ns per loop

此处,3中的最佳值不能代表算法的 true 运行时间。

但是通过调整测试,我得出的结论是,对于只有30个元素的列表,二等分可能比in更快。

但是,如果你正在做很多in次操作,你应该使用set;你可以将列表转换成一个集合(它甚至不会被排序),in操作将比任何二进制搜索都渐近地快:

>>> a = [10, 6, 8, 1, 2, 5, 9]
>>> a_set = set(a)
>>> 10 in a_set
True

另一方面,排序列表的时间复杂度比构建集合的时间复杂度高,因此大部分时间都是一个集合。< / p>