Reputation: 437
As far as I can see, the binary search specified by the while loop should always continue searching until the min and max of the search space is equal. But on testing it, and always after having already sorted most of the items, it gets stuck in an infinite loop because mx
somehow obtains the value -2
.
I suppose I could change the condition of the while loop to patch that, but I'm trying to understand why it's behaving as it is, and have tried going over it with my eye and on paper but can't reproduce the event where mx = -2
.
def insort(seq):
for a in xrange(1, len(seq)):
if seq[a] > seq[a - 1]:
continue
else:
mn, mx = 0, a - 1
while mn != mx:
pivot = mn + ((mx - mn) / 2)
if seq[a] > seq[pivot]:
mn = pivot + 1
else:
mx = pivot - 1
seq.insert(mn, seq.pop(a))
Upvotes: 0
Views: 816
Reputation: 3537
NOTE: I am using python 2.7.3 . I'm not sure if other versions of python have different results arising from division, so here's a heads up.
Several changes are required:
mn != mx
to mn < mx
pivot = mn + ((mx - mn) / 2)
statement to pivot = int(math.floor((mn + mx) / 2))
or pivot = mn + int(math.floor((mx - mn) / 2))
to prevent any kind of surprises when it comes down to division.mn
, mx
is changed to a half open interval, given by [mn, mx)
, because that is something I'm more familiar with when it comes to a hand coded binary search. So mx
should be set to a
initially, and mx
should be set to pivot
instead of pivot - 1
in the case where seq[a] <= seq[pivot]
(iow, if the if
test is False
).So the code with the edits should look like:
import math
def insort(seq):
for a in xrange(1, len(seq)):
if seq[a] > seq[a - 1]:
continue
else:
mn, mx = 0, a
while mn < mx:
pivot = mn + int(math.floor(((mx - mn) / 2)))
if seq[a] > seq[pivot]:
mn = pivot + 1
else:
mx = pivot
seq.insert(mn, seq.pop(a))
For the original code, I will give you an example where mx
gets stuck at -2
.
Given this list: [10, 7, 8, 5, 13, 2, 6, 1, 50]
Everything works fine until the element at index 5, which has a value of 2
(Verify this for yourself by adding some print
statements). Since seq[a] > seq[a-1]
is false (2
is the smallest element so far), we enter the else branch of the if statement.
At this point:
seq = [5, 7, 8, 10, 13, 2, 6, 1, 50]
a = 5
mn = 0
mx = a - 1 = 4
Since mn != mx
(0 != 4
), we enter the while loop. pivot
is set to 0 + ((4 - 0) / 2)
= 2
. Next we perform if seq[a] > seq[pivot]
. seq[a] = 2
, while seq[pivot]
= 8
and 2 > 8
is False
, so we go to the else branch and perform mx = pivot - 1 = 2 - 1 = 1
At this point:
seq = [5, 7, 8, 10, 13, 2, 6, 1, 50]
a = 5
mn = 0
mx = 1
We perform the check at the while loop again. mn != mx
(0 != 1
), so we go inside the body of the while loop. We set pivot = 0 + ((1 - 0) / 2) = 0
(I am using python 2.7 to perform this division, so do verify at a repl), then perform the check seq[a] > seq[pivot]
(2 > 5
), which is False
. Hence, we set mx = pivot - 1 = 0 - 1 = -1
.
At this point:
seq = [5, 7, 8, 10, 13, 2, 6, 1, 50]
a = 5
mn = 0
mx = -1
Now, we perform the check at the while loop, mn != mx
(0 != -1
), so we enter the body of the while loop. pivot = 0 + ((-1 - 0) / 2) = -1
. Then we perform the check seq[a] > seq[pivot]
(seq[5] > seq[-1]
, which compares the 5th element with the last element of seq
, in other words 2 > 50
), and that is False
. So mx = pivot - 1 = -1 - 1 = -2
.
Now we've reached the final step:
seq = [5, 7, 8, 10, 13, 2, 6, 1, 50]
a = 5
mn = 0
mx = -2
At the while loop check, mn != mx
, so we go on to pivot = 0 + ((-2 - 0) / 2) = -1
. Observe that this is the same pivot as the above step. Then seq[5] > seq[-1]
is performed (2 > 50
), which is False
. So mx = pivot - 1 = -1 - 1 = -2
. And we end up in the same state as above. Which is why you see an infinite loop.
Finally, I just want to say that, binary search is a pretty tricky algorithm to code out since it's quite easy to make mistakes for the boundary indices. I've coded it by hand quite a lot of times and I still find it quite tricky. You might want to read this as well: http://en.wikipedia.org/wiki/Binary_search_algorithm
Hope that helps!
Upvotes: 3