我正在学习二进制搜索,示例代码使用“low = mid +1 and high = mid -1
”,但我不明白为什么我们不使用“low = mid and high = mid
”代替?
def binarysearch(sequence, value):
lo, hi = 0, len(sequence) - 1
while lo <= hi:
mid = (lo + hi) // 2
if sequence[mid] < value:
lo = mid + 1
elif value < sequence[mid]:
hi = mid - 1
else:
return mid
return None
my_list = [1, 3, 5, 7, 9]
binarysearch(my_list, 3)
答案 0 :(得分:1)
原因是避免重叠搜索;它将搜索范围的边界放在尚未检查的项目上。
例如:如果mid位于索引10,则下一个搜索左侧将查看索引9之前的值,右侧搜索索引11处的值。
mid
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| | | |
<-from 0 to mid-1-> <-- from mid+1 to the end -->
note that in this example, the boundary values are included
答案 1 :(得分:0)
请让我试着解释为什么二进制搜索有效。假设我们有以下序列A=[-5, 10, 14, 33, 42, 42, 42]
和searched_value = 14
:
Iteration 1, lo = 0, hi = 6, mid = 3 A[mid] > 14
Iteration 2, lo = 0, hi = 2, mid = 1 A[mid] < 14
Iteration 3, lo = 2, hi = 2, mid = 2 A[mid] = 14 (found!)
在算法的每次迭代中,我们可以得出结论:lo
和hi
总是包含搜索值的位置,我们将通过归纳证明迭代次数:
归纳假设:如果搜索到的值出现在序列中,它将始终包含在lo
和hi
之间。
基本案例:在迭代1 lo = 0
和hi = n-1
包含所有元素,因此如果搜索到的值出现在序列中,它将包含在{{lo
之间1}}和hi
,并且不变量非常正确。
归纳步骤:如果搜索到的值包含在lo
和hi
之间的任何步骤中,它将继续包含在lo
和hi
之间{1}}在下一次迭代中。我们有3种可能性(这是问题的答案):
A[mid] = searched_value
:在这种情况下,算法会正确报告搜索值在序列中的位置,并且不变量是正确的,因为搜索的值介于lo
和hi
之间。 A[mid] < searched_value
:知道它是一个排序的序列,A[lo...mid] < searched_value
之间的所有元素(包括A[mid]
),因此我们可以分配lo=mid+1
(仅在在上一次迭代中,不变量仍然是正确的。A[mid] > searched_value
:知道它是一个已排序的序列,A[mid...hi] > searched value
(包括A[mid]
)之间的所有元素,因此我们可以协助hi=mid-1
(仅在searched_value
中安全搜索下半部分,并且在下一次迭代中,不变量仍然是正确的。鉴于此,在每次迭代时,算法总是在较小的段上搜索
在序列中,终止条件得到保证,因为只有1个元素是mid+1
或者它是不同的,并且在下一次迭代中,算法将报告序列中不存在这样的元素。
结果证明算法是正确的(以及我们使用mid-1
和it 'should do something', transactional: false do
end
)的原因。
答案 2 :(得分:0)
我认为代码不起作用,因为当数组大小为偶数时,您不会退出 while 循环当我们使 l 或 r 等于 mid(wrong),而不是 mid + 1 或mid -1(正确)
正如您在下面看到的,它陷入了无止境的循环。
例如:
Binary Search
Array = [8, 9, 11, 13]; target = 10
0 1 2 3
l m r m = (0 + 3)/2 = 1.5 or 1, arr[m] < target (coz 9 < 10), make l = m,
l m r m = (1+3)/2 = 2, arr[m] > target (coz 11 > 10), make r = m,
l(m) r m = (1+2)/2 = 1.5 or 1, arr[m] < target (coz 9 < 10), make l = m
l r(m) m = (1+3)/2 = 2, arr[m] > target (coz 11 > 10), make r = m.
l(m) r m = (1+2)/2 = 1.5 or 1, arr[m] < target (coz 9 < 10), make l = m
l r(m) m = (1+3)/2 = 2, arr[m] > target (coz 11 > 10), make r = m.
...
...