I have a list with numbers from 0-9:
mylist = list(range(10))
I am getting an error with the division command to get mid
:
def binary_search(mylist, element, low, high):low=0high= len(mylist)mid=low + (high- mymin)/2if mid==len(mylist):return Falseelif mylist[mid]==element:return midelif high==low:return Falseelif mylist[mid]<element:return binary_search(mylist, element, mymin, mid-1)elif mylist[mid]<element:return binary_search(mylist, element, mid+1, mymax)else:return mid
and if I wanted to return True
how would I write that on top of return binary_search(mylist, element, mymin, mid-1)
?
Best Answer
Recursive solution:
def binary_search_recursive(arr, elem, start=0, end=None):if end is None:end = len(arr) - 1if start > end:return Falsemid = (start + end) // 2if elem == arr[mid]:return midif elem < arr[mid]:return binary_search_recursive(arr, elem, start, mid-1)# elem > arr[mid]return binary_search_recursive(arr, elem, mid+1, end)
Iterative solution:
def binary_search_iterative(arr, elem):start, end = 0, (len(arr) - 1)while start <= end:mid = (start + end) // 2if elem == arr[mid]:return midif elem < arr[mid]:end = mid - 1else: # elem > arr[mid]start = mid + 1return False
Here's an elegant recursive solution if you're:
1) Trying to return the INDEX of the target in the original list being passed in, before it is halved. Getting the target is the easy part.
2) Only want to have to pass in 2 arguments: (list, target) instead of 4 arguments including the upper/lower (right/left) bounds of each array being passed in recursively.
3) Don't want out of bounds, maximum recursion depth, or target not found errors.
# Base Case: one item (target) in array.# Recursive Case: cut array by half each recursive call.def recursive_binary_search(arr, target):mid = len(arr) // 2if len(arr) == 1:return mid if arr[mid] == target else Noneelif arr[mid] == target:return midelse:if arr[mid] < target:callback_response = recursive_binary_search((arr[mid:]), target)return mid + callback_response if callback_response is not None else Noneelse:return recursive_binary_search((arr[:mid]), target)
please correct me, if the code presents any bugs
def binary_recursive(array, val):if val < array[0] or val > array[-1]:return Falsemid = len(array) // 2left = array[:mid]right = array[mid:]if val == array[mid]:return Trueelif array[mid] > val:return binary_recursive(left, val)elif array[mid] < val:return binary_recursive(right, val)else:return False
`Please correct me if I am wrong as I am a new programmer but here is my solution:
def binary_search(test_cases, item_to_be_found):try:if item_to_be_found == test_cases[len(test_cases) // 2]:return Trueelif item_to_be_found < test_cases[len(test_cases) // 2]:test_cases = test_cases[:len(test_cases) // 2]else:test_cases = test_cases[len(test_cases) // 2:]return binary_search(test_cases, item_to_be_found)except RecursionError:return False
The first solution looks wrong because it doesn't index the list.
This problem tripped me up too the first time I wrote a solution so be sure to test your algorithm well.
Here's what I ended up with:
def binary_search(value, items, low=0, high=None):"""Binary search function.Assumes 'items' is a sorted list.The search range is [low, high)"""high = len(items) if high is None else highpos = low + (high - low) / len(items)if pos == len(items):return Falseelif items[pos] == value:return poselif high == low:return Falseelif items[pos] < value:return binary_search(value, items, pos + 1, high)else:assert items[pos] > valuereturn binary_search(value, items, low, pos)
And when I test it, the answers look correct:
In [9]: for val in range(7):...: print val, binary_search(val, [1, 2, 3, 5])...:0 False1 02 13 24 False5 36 False
Btw, Python has a library module for just this kind of thing named bisect.
Though it's too late, it might help someone else :-
def bsearch_helper(arr, key, low, high):if low > high:return Falsemid = (low + high)//2if arr[mid] == key:return Trueelif arr[mid] < key:return bsearch_helper(arr, key, mid + 1, high)else:return bsearch_helper(arr, key, low, mid - 1)return Falsedef bsearch(arr, key):return bsearch_helper(arr, key, 0, len(arr) - 1)if __name__ == '__main__':arr = [8, 3, 9, 2, 6, 5, 1, 7, 4]print (bsearch(sorted(arr), 5))
You can make use of list slicing too.
def binary_search_recursive(list1, element):if len(list1) == 0:return Falseelse:mid = len(list1)//2if (element == list1[mid]):return Trueelse:if element > list1[mid]:return binary_search_recursive(list1[mid+1:],element)else:return binary_search_recursive(list1[:mid],element)
However, note that list slicing introduces additional complexity.
There are a lot of solutions here already. Below is one more solution without slicing and that just requires element and list as arguments:
def binary_search(item, arr):def _binary_search(item, first, last, arr):if last < first:return Falseif last == first:return arr[last] == itemmid = (first + last) // 2if arr[mid] > item:last = midreturn _binary_search(item, first, last, arr)elif arr[mid] < item:first = mid + 1return _binary_search(item, first, last, arr)else:return arr[mid] == itemreturn _binary_search(item, 0, len(arr) - 1, arr)print(binary_search(-1, [0, 1, 2, 3, 4, 5]))
Recursion Binary Search for sorted list.
The print statements are helpful to see how it all works.
# n = number we are searching for# lst = the sorted list we are searching in# sp = list start position# ep = list end postiondef binary_search_recursion(n: int, lst: list, sp: int = 0, ep: int = None) -> bool:# first time searching, start position will be 0# and end position will be Noneif ep is None:# End position equals total length minus 1 since 0 indexedep = len(lst) - 1# get the midpoint of the list (lst)mid = (sp + ep) // 2mid_item = lst[mid]print(f"Start: lst[{sp}] = {lst[sp]}\nMid: lst[{mid}] = {mid_item}\nEnd: lst[{ep}] = {lst[ep]}")# If mid item matches the searching number then successif mid_item == n:print(f"Success!!! Number {n} found in lst[{mid}]")return True# Else if mid item is greater than number, we eliminate everything to the left and move rightelif mid_item > n:new_ep = mid - 1 if new_ep < 0: print(f"Number {n} is too low. Lowest number found is {lst[sp]}")return Falseelse:print(f"Number {n} is less than mid item {mid_item}, change ep {ep} to {new_ep}.\n")binary_search_recursion(n, lst, sp, new_ep)# Else if mid item is lower than number, we eliminate everything to the right and move leftelif mid_item < n:new_sp = mid + 1if new_sp > ep:print(f"Number {n} is too High. Highest number found is {lst[ep]}")return Falseelse:print(f"Number {n} is greater than mid item {mid_item}, change sp {sp} to {new_sp}.\n")binary_search_recursion(n, lst, new_sp, ep)
Testing out the function:
# A sorted listnum_list = [10,20,30,40,50,60,70,80,90,100,110]# Search for 10 in num_listbinary_search_recursion(10, num_list)Start: lst[0] = 10Mid: lst[5] = 60End: lst[10] = 110Number 10 is less than mid item 60, change ep 10 to 4.Start: lst[0] = 10Mid: lst[2] = 30End: lst[4] = 50Number 10 is less than mid item 30, change ep 4 to 1.Start: lst[0] = 10Mid: lst[0] = 10End: lst[1] = 20Success!!! Number 10 found in lst[0]# Search for 110 in num_listbinary_search_recursion(110, num_list)Start: lst[0] = 10Mid: lst[5] = 60End: lst[10] = 110Number 110 is greater than mid item 60, change sp 0 to 6.Start: lst[6] = 70Mid: lst[8] = 90End: lst[10] = 110Number 110 is greater than mid item 90, change sp 6 to 9.Start: lst[9] = 100Mid: lst[9] = 100End: lst[10] = 110Number 110 is greater than mid item 100, change sp 9 to 10.Start: lst[10] = 110Mid: lst[10] = 110End: lst[10] = 110Success!!! Number 110 found in lst[10]# Search for 6 in num_listbinary_search_recursion(6, num_list)Start: lst[0] = 10Mid: lst[5] = 60End: lst[10] = 110Number 6 is less than mid item 60, change ep 10 to 4.Start: lst[0] = 10Mid: lst[2] = 30End: lst[4] = 50Number 6 is less than mid item 30, change ep 4 to 1.Start: lst[0] = 10Mid: lst[0] = 10End: lst[1] = 20Number 6 is too low. Lowest number found is 10# Search for 1111 in num_listbinary_search_recursion(1111, num_list)Start: lst[0] = 10Mid: lst[5] = 60End: lst[10] = 110Number 1111 is greater than mid item 60, change sp 0 to 6.Start: lst[6] = 70Mid: lst[8] = 90End: lst[10] = 110Number 1111 is greater than mid item 90, change sp 6 to 9.Start: lst[9] = 100Mid: lst[9] = 100End: lst[10] = 110Number 1111 is greater than mid item 100, change sp 9 to 10.Start: lst[10] = 110Mid: lst[10] = 110End: lst[10] = 110Number 1111 is too High. Highest number found is 110
Your first one won't even get started, because list(mid)
will immediately raise a TypeError: 'list' object is not callable
.
If you fix that (by using list[mid]
), your next problem is that you ignore the min
and max
arguments you receive, and instead set them to 0
and len(list)-1
each time. So, you will infinitely recurse (until you eventually get a RecursionError
for hitting the stack limit).
Think about it: the first call to binarySearch(l, 5, 0, 10)
recursively calls binarySearch(l, 5, 0, 4)
. But that call ignores that 4
and acts as if you'd passed 10
, so it recursively calls binarySearch(l, 5, 0, 4)
. Which calls binarySearch(l, 5, 0, 4)
. And so on.
If you fix that (by removing those two lines), you've got another problem. When you give it the number 10
, binarySearch(l, 10, 0, 10)
will call binarySearch(
l, 10, 6, 10), which will call
binarySearch(l, 10, 8, 10)
, then binarySearch(
l, 10, 9, 10), then
binarySearch(l, 10, 10, 10)
. And that last one will check list[10] > element
. But list[10]
is going to raise an IndexError
, because there aren't 11 elements in the list.
And once you fix that off-by-one error, there are no problems left. The problem you asked about cannot possibly ever occur. Here's an example run:
>>> a = range(10)>>> for i in -3, -1, 0, 1, 4, 5, 9, 10, 11:... print i, binarySearch(a, i, 0, 10)-3 False-1 False0 01 14 45 59 910 False11 False
Your second version isn't recursive. bSearch
never calls bSearch
, and that's the whole definition of recursion.
There's nothing wrong with writing an iterative algorithm instead of a recursive algorithm (unless you're doing a homework problem and recursion is the whole point), but your function isn't iterative either—there are no loops anywhere.
(This version also ignores the start
and end
arguments, but that's not as much of a problem in this case, because, again, you're not doing any recursion.)
Anyway, the only return False
in the function is in that first if len(list) == 0
. So, for any non-empty list, it's either going to return True
, or a number. With your input, it will return 4
for anything less than the value at the midpoint of the list (5), and True
for anything else.
Your problem here is that you're redeclaring min and max in each loop, so although it should be recursive, passing in a new min or max each time, this isn't in fact happening.
You can solve this by using defaults in the arguments:
def binary_search(list, element, min=0, max=None):max = max or len(list)-1if max<min:return Falseelse:mid= min + (max-min)/2if mid>element:return binary_search(list, element, min, mid-1)elif mid<element:return binary_search(list, element, mid+1, max)else:return mid
If you're not familiar with the syntax on line 2, max = max or len(list)-1max will be set to len(list)-1 only if max is not passed in to the method.
So you can call the method simply using:
binary_search(range(10), 7)# Returns 7binary_search(range(10), 11)# Returns False
Just another answer to the same question:
def binary_search(array, element, mini=0, maxi=None):"""recursive binary search."""maxi = len(array) - 1 if maxi is None else maxiif mini == maxi:return array[mini] == elementelse:median = (maxi + mini)/2if array[median] == element:return Trueelif array[median] > element:return binary_search(array, element, mini, median)else:return binary_search(array, element, median+1, maxi)print binary_search([1,2,3],2)
I made this one. Correct me if there's any bug.
import mathdef insert_rec(A,v,fi,li):mi = int(math.floor((li+fi)/2))if A[mi] == v:print("Yes found at: ",mi)returnif fi==li or fi>li:print("Not found")returnif A[mi] < v:fi = mi+1insert_rec(A,v,fi,li)if A[mi] > v:li = mi-1insert_rec(A,v,fi,li)
def bs(list,num): #presume that the list is a sorted list#base casemid=int(len(list)/2) # to divide the list into two partsif num==list[mid]:return Trueif len(list)==1:return False#recursionelif num<list[mid]: #if the num is less than midreturn bs(list[0:mid],num) #then omit all the nums after the midelif num>list[mid]: #if the num is greater than midreturn bs(list[mid:],num) # then omit all the nums before the mid#return Falselist=[1,2,3,4,5,6,7,8,9,10]print(bs(list,20))<<< Falseprint(bs(list,4))<<< True
You can implement binary search in python in the following way.
def binary_search_recursive(list_of_numbers, number, start=0, end=None):# The end of our search is initialized to None. First we set the end to the length of the sequence.if end is None:end = len(list_of_numbers) - 1if start > end:# This will happen if the list is empty of the number is not found in the list.raise ValueError('Number not in list')mid = (start + end) // 2 # This is the mid value of our binary search.if number == list_of_numbers[mid]:# We have found the number in our list. Let's return the index.return midif number < list_of_numbers[mid]:# Number lies in the lower half. So we call the function again changing the end value to 'mid - 1' Here we are entering the recursive mode.return binary_search_recursive(list_of_numbers, number, start, mid - 1)# number > list_of_numbers[mid]# Number lies in the upper half. So we call the function again changing the start value to 'mid + 1' Here we are entering the recursive mode.return binary_search_recursive(list_of_numbers, number, mid + 1, end)
We should check our code with good unittest to find loop holes in our code.
Hope this helps you.
Here is My Recursion Solution of Binary Search
def recBinarySearch(arr,ele):if len(arr) == 0:return Falseelse:mid = len(arr)/2if arr[mid] == ele:return Trueelse:if ele < arr[mid]:return recBinarySearch(arr[:mid], ele)else:return recBinarySearch(arr[mid+1], ele)
You can do it this way as well:
def recursive_binary_search(list, item):"""find the index of the given item in the list recursively"""low = 0high = len(list) - 1if low <= high:mid = low + highguess = list[mid]if guess == item:return midif guess > item: # item must be in the first splitreturn recursive_binary_search(list[low:mid], item)else: # check in second split otherwisereturn recursive_binary_search(list[mid:high], item)return Nonedef main():print(recursive_binary_search([2,3,4,5,6,7,8], 3)) # will print 1if __name__ == "__main__":main()