How do you implement binary search so that it is correct on the first try, and what are the common mistakes?
Fix the interval convention before you write the loop. The classic closed form starts with low at zero and high at the length minus one, and the loop runs while low is less than or equal to high. Inside, compute the midpoint as low plus half of the high minus low, which avoids overflow in fixed width languages. Compare, and then either move low to mid plus one or high to mid minus one. Getting the midpoint as the average of low and high is also correct, but it is the source of overflow bugs in other languages.
def binary_search(values, target):
low, high = 0, len(values) - 1
while low <= high:
mid = low + (high - low) // 2
if values[mid] == target:
return mid
if values[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
data = [1, 3, 5, 7, 9, 11]
print(binary_search(data, 7))
print(binary_search(data, 4))The outputs are 3 and minus one. The target 7 sits at index three, and 4 is not present, so the search exhausts the interval and reports failure.
The mechanism is the halving. Each comparison discards half of the remaining candidates because the array is sorted, so after k steps the interval has shrunk by a factor of two to the power k and the search finishes in logarithmically many steps.
The trade-off to name is that binary search only works on ordered data, and that the ordering has to be by the key you are comparing. The classic mistakes are mixing conventions, such as starting high at the length and then also using the closed form, and forgetting to move the wrong pointer, which makes the search loop forever. Another subtle bug is returning the first match when duplicates exist, because the binary search has no idea which occurrence it landed on. In an interview, stating the interval convention out loud before you type is what prevents these, and it is the habit the interviewer is really checking.