What I usually do and I think it is the easiest way to prove the algorithm is correct is to think of it smallest unit. So let start by giving a scenario which algorithm might fail and test whether it will fail.
Assuming that the first = 0 and the last = 1. Then, the mid = (0 + 1 )/ 2 = 0. So there are 3 possible cases.
- When the
a[mid] == x, then great, you found the answer.
- When the
a[mid] > x, then you will move your, last = mid - 1 = -1. Great, you terminate because last is not greater than first and it is true because x is less than value of the first element of the sorted list, so it is impossible for x to be in the list.
- When the
a[mid] < x. then you will move your first = mid + 1 = 1. Now, in this case, you terminate your loop. But, there is something wrong, because a[1] might hold the value of what you are looking for. You simply skip a possible option.
The following is a visualize of the case when your algorithm fail. Assuming the x = 5 and denote F = first and L = last.
(1 5) 6 7 8 9 15
^ ^
F L
As you see, the bold part is the possible option. You have 2 possible options which is a[0] and a[1] when first = 0 and last = 1. Then when you calculate the mid = (0 + 1) / 2 = 0 and when you detect that a[mid] = a[0] = 1 < 5. Then you move your first = 1 and last = 1. You terminate the loop because last is no longer greater than first which in this case, you only check a[0], but you skip a[1].
So this is what I suggest to do
def binarysearch(a, x):
low = 0
high = length(a)
while low <= high:
mid = (high + low) / 2
if (a[mid] == x): return mid
elseif (a[mid] > x) : low = mid + 1
else : high = mid - 1
return -1
In your code, you do not have mechanism to tell whether the item you are searching for does not found. I return -1 when x is not found. So, you can simply create function replace in this way.
def replace(a, x, y):
# replace x with y
i = binarysearch(a, x)
if i >= 0:
a[i] = y
else:
print "x does not exist"