One natural way to use recursion is to rewrite binary search.
Recall that our iterative implementation of binary search looked like this:
def binarySearch(item, lst):
"""
inputs: an item and a list of items
output: Boolean value (True if the item is in the list, False otherwise)
"""
low = 0
high = len(lst)-1
while low <= high:
mid = (low + high) // 2
if item == lst[mid]:
return True
elif item < lst[mid]:
high = mid - 1
elif item > lst[mid]:
low = mid + 1
return False
This code is pretty complicated, and we had to plan very carefully to make sure that the while
loop works the way we intended.
But binary search seems to lend itself to recursion --- our idea was "check the middle element, then update low or high and binary search again". This notion of "just binary search again, but on a smaller list" will make a recursive version much cleaner to read.
How will we pass around a "smaller" list? One way is to use a helper function. We can add the parameters low
and high
, since those are what we were tracking in the loop of the iterative version.
def binarySearchHelper(item, lst, low, high):
"""
input: an item, a list of items, and two indices in the list
output: Boolean value (True if the item is in the list, False otherwise)
"""
if low > high:
return False
else:
mid = (low + high) // 2
if item == lst[mid]:
return True
elif item < lst[mid]:
return binarySearchHelper(item, lst, low, mid-1)
elif item > lst[mid]:
return binarySearchHelper(item, lst, mid+1, high)
Notice that the condition from the while
loop has now become our base case: it tells us when to stop doing binary search (either to stop looping or to stop making recursive calls).
Now the only thing we need to do is figure out how to start a binary search. At the beginning, we know that low
and high
should have us search the entire list, so the implementation of binarySearch
is simply:
def binarySearch(item, lst):
return binarySearchHelper(item, lst, 0, len(lst)-1)
To see how this is working, let's add a print
statement at the beginning of the binarySearchHelper
function that prints low
and high
. Now when we run on an example list like [-20, -12, -4, 1, 7, 44, 45, 46, 58, 67, 99, 145]
and search for 7, we get:
low: 0 high: 11
low: 0 high: 4
low: 3 high: 4
low: 4 high: 4
... and then the search returns True
, because it finds that 7 is in position 4 of the list.
Another example, searching for 140 in the list:
low: 0 high: 11
low: 6 high: 11
low: 9 high: 11
low: 11 high: 11
low: 11 high: 10
... and then the search returns False
, because low
is greater than high
.
Try this out for yourself!
Complete code of my testing file:
def binarySearchHelper(item, lst, low, high):
"""
input: an item, a list of items, and two indices in the list
output: Boolean value (True if the item is in the list, False otherwise)
"""
print("low: %2d high: %d" % (low, high))
if low > high:
return False
else:
mid = (low + high) // 2
if item == lst[mid]:
return True
elif item < lst[mid]:
return binarySearchHelper(item, lst, low, mid-1)
elif item > lst[mid]:
return binarySearchHelper(item, lst, mid+1, high)
def binarySearch(item, lst):
"""
inputs: an item and a list of items
output: Boolean value (True if the item is in the list, False otherwise)
"""
return binarySearchHelper(item, lst, 0, len(lst)-1)
def main():
myList = [-20, -12, -4, 1, 7, 44, 45, 46, 58, 67, 99, 145]
searchItem = int(input("What number do you want to find? "))
result = binarySearch(searchItem, myList)
print(result)
main()