尽管Python中没有显式的二进制搜索算法,但有一个模块-bisect
用于使用二进制搜索在排序列表中查找元素的插入点。这可以“诱骗”执行二进制搜索。这种方法的最大优点是大多数库代码都具有相同的优点-高性能,经过良好测试并且可以正常工作(特别是二进制搜索很难成功实现-尤其是在没有仔细考虑边缘情况的情况下)。
基本类型
对于像字符串或整数这样的基本类型,这非常简单-您所需要的只是bisect
模块和排序列表:
>>> import bisect
>>> names = ['bender', 'fry', 'leela', 'nibbler', 'zoidberg']
>>> bisect.bisect_left(names, 'fry')
1
>>> keyword = 'fry'
>>> x = bisect.bisect_left(names, keyword)
>>> names[x] == keyword
True
>>> keyword = 'arnie'
>>> x = bisect.bisect_left(names, keyword)
>>> names[x] == keyword
False
您还可以使用它来查找重复项:
...
>>> names = ['bender', 'fry', 'fry', 'fry', 'leela', 'nibbler', 'zoidberg']
>>> keyword = 'fry'
>>> leftIndex = bisect.bisect_left(names, keyword)
>>> rightIndex = bisect.bisect_right(names, keyword)
>>> names[leftIndex:rightIndex]
['fry', 'fry', 'fry']
显然,如果需要,您可以只返回索引而不是该索引处的值。
对象
对于自定义类型或对象,事情有些棘手:您必须确保实现丰富的比较方法,以使等分正确地进行比较。
>>> import bisect
>>> class Tag(object):
... def __init__(self, tag):
... self.tag = tag
... def __lt__(self, other):
... return self.tag < other.tag
... def __gt__(self, other):
... return self.tag > other.tag
...
>>> tags = [Tag('bender'), Tag('fry'), Tag('leela'), Tag('nibbler'), Tag('zoidbe
rg')]
>>> key = Tag('fry')
>>> leftIndex = bisect.bisect_left(tags, key)
>>> rightIndex = bisect.bisect_right(tags, key)
>>> print([tag.tag for tag in tags[leftIndex:rightIndex]])
['fry']
这至少应该在Python 2.7-> 3.3中有效