如果我有一个已经排序的列表并使用in关键字,例如:
a = [1,2,5,6,8,9,10]
print 8 in a
Run Code Online (Sandbox Code Playgroud)
我认为这应该进行顺序搜索,但是我可以通过二进制搜索来加快速度吗?是否有一种pythonic方式在排序列表中搜索?
标准库中的 module 中有对 Python 的二分搜索bisect。它不支持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
Run Code Online (Sandbox Code Playgroud)
然后
>>> contains([1,2,3], 3)
True
>>> contains([1,2,3], 4)
False
Run Code Online (Sandbox Code Playgroud)
不过,这不会很快,因为它是用 Python 编写的,而不是用 C 编写的,所以在很多情况下, bisect您可能会发现顺序更快。inbisect自 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
Run Code Online (Sandbox Code Playgroud)
这里,3中最好的并不代表算法的真实运行时间。
但通过调整测试,我得出的结论是,平分可能比in只有 30 个元素的列表更快。
但是,如果您要执行很多in操作,则应该使用set; 您可以将列表一次转换为集合(甚至不排序),并且该in操作将比任何二分搜索更快:
>>> a = [10, 6, 8, 1, 2, 5, 9]
>>> a_set = set(a)
>>> 10 in a_set
True
Run Code Online (Sandbox Code Playgroud)
另一方面,对列表进行排序比构建集合具有更大的时间复杂度,因此大多数情况下集合是可行的方法。
| 归档时间: |
|
| 查看次数: |
232 次 |
| 最近记录: |