【发布时间】:2013-12-16 07:52:58
【问题描述】:
在我的理解中,bisect_left 和 bisect_right 是做同一件事的两种不同方式:二等分,一种来自左侧,另一种来自右侧。因此,它们具有相同的结果。在什么情况下这两个不相等,即假设列表和正在搜索的值相同,它们何时返回不同的结果?
【问题讨论】:
标签: python python-2.7
在我的理解中,bisect_left 和 bisect_right 是做同一件事的两种不同方式:二等分,一种来自左侧,另一种来自右侧。因此,它们具有相同的结果。在什么情况下这两个不相等,即假设列表和正在搜索的值相同,它们何时返回不同的结果?
【问题讨论】:
标签: python python-2.7
bisect_left 和bisect_right 返回可以在不改变元素顺序的情况下插入值的最左边和最右边的索引。如果列表中不存在该值,则它们都返回相同的索引。当值存在于列表中时,就会出现差异。例如,要将10 插入列表[10,20,30] 而不破坏顺序,最左边的索引将是0,最右边的索引将是1。但是,要将10.5 插入同一个列表,最左边和最右边的索引都将等于1。这是代码中的相同示例:
>>> from bisect import bisect_left, bisect_right
>>> bisect_left([10,20,30],10)
<<< 0
>>> bisect_right([10,20,30],10)
>>> 1
,对于值存在于数组中的情况,和
>>> bisect_left([10,20,30],10.5)
<<< 1
>>> bisect_right([10,20,30],10.5)
>>> 1
,用于数组中不存在该值的情况。
bisect_left 和 bisect_right 之间的区别通过查看它们的实现变得清晰。下面是一段代码 sn-p 展示了他们的准系统实现(取自 python 标准库):
def bisect_right(a, x, lo=0, hi=None):
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if a[mid] <= x: # <--- less than or equal to
lo = mid+1
else:
hi = mid
return lo
def bisect_left(a, x, lo=0, hi=None):
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < x: # <--- less than
lo = mid + 1
else:
hi = mid
return lo
两者之间的唯一区别在于将中点值与查找值进行比较的条件。 bisect_right 使用<=,表示如果数组中存在值,则将搜索窗口移动到元素的右侧,而bisect_left 使用<,将搜索窗口移动到值的左侧(如果存在)。否则(如果该值不存在于数组中),两种实现会产生相同的输出。
【讨论】:
有两点需要理解:
bisect.bisect 和 bisect.bisect_right 工作方式相同。这些返回可以在不破坏元素顺序的情况下插入元素的最右边位置。但与上述相反,bisect.bisect_left 返回可以插入元素的最左侧位置。谨慎使用。
【讨论】:
对我来说,bisect_left/bisect_right 的这种解释更清楚:
bisect_left 返回插入元素 w.r.t 的最大索引。 < bisect_right 返回插入元素 w.r.t 的最大索引。 <= 例如,如果您的数据是[0, 0, 0],而您查询0:
bisect_left 返回索引 0,因为这是插入元素真正较小的最大可能插入索引。bisect_right 返回索引 3,因为“小于或等于”时,搜索会通过相同的元素进行。这种行为可以简化为:
bisect_left 会在相同元素的左侧插入元素。bisect_right 会在相同元素的右侧插入元素。【讨论】:
正如其他人所指出的,当正在查找的元素出现在列表中时,bisect_left 和 bisect_right 返回不同的结果。
事实证明 bisect_left 更有用,因为它返回正在查找的元素的确切索引(如果它存在于列表中)。
>>> import bisect
>>> bisect.bisect_left([1,2,3,4,5], 2)
1
使用 bisect_left 的 binary_search 示例:
from bisect import bisect_left
def binsearch(l,e):
'''
Looks up element e in a sorted list l and returns False if not found.
'''
index = bisect_left(l,e)
if index ==len(l) or l[index] != e:
return False
return index
如果你想使用 bisect_right 而不是 bisect_left 并得到相同的结果,上面的代码会有一个小的变化。
【讨论】:
bisect.bisect_left 返回排序列表中最左边的位置以插入给定元素。
bisect.bisect_right 返回排序列表中最右边的位置以插入给定元素。
另一个问题是它们何时等效?通过回答这个问题,您的问题的答案就很清楚了。
当要插入的元素不在列表中时,它们是等效的。因此,当要插入的元素在列表中时,它们是不等价的。
【讨论】:
当要定位的目标在列表中时,bisect_left、bisect_right返回不同的结果。
例如:
>>> import bisect
>>> bisect.bisect_left([1,2,3], 2)
1
>>> bisect.bisect_right([1,2,3], 2)
2
【讨论】: