虽然 Python 中没有明确的二进制搜索算法,但有一个模块 -bisect
旨在使用二进制搜索在排序列表中查找元素的插入点。这可以被“欺骗”执行二进制搜索。这样做的最大优势与大多数库代码所具有的优势相同——它性能卓越、经过良好测试并且可以正常工作(特别是二进制搜索可能很难成功实现——尤其是在没有仔细考虑边缘情况的情况下)。
基本类型
对于像 Strings 或 ints 这样的基本类型,这很容易——你只需要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']
显然,如果需要,您可以只返回索引而不是该索引处的值。
对象
对于自定义类型或对象,事情有点棘手:您必须确保实现丰富的比较方法才能正确比较 bisect。
>>> import bisect
>>> class Tag(object): # a simple wrapper around strings
... 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