Binary search in a Python list - python

I am trying to perform a binary search on a list in python. List is created using command line arguments. User inputs the number he wants to look for in the array and he is returned the index of the element. For some reason, the program only outputs 1 and None. Code is below.
Any help is extremely appreciated.
import sys
def search(list, target):
min = 0
max = len(list)-1
avg = (min+max)/2
while (min < max):
if (list[avg] == target):
return avg
elif (list[avg] < target):
return search(list[avg+1:], target)
else:
return search(list[:avg-1], target)
print "The location of the number in the array is", avg
# The command line argument will create a list of strings
# This list cannot be used for numeric comparisions
# This list has to be converted into a list of ints
def main():
number = input("Please enter a number you want to search in the array !")
index = int(number)
list = []
for x in sys.argv[1:]:
list.append(int(x))
print "The list to search from", list
print(search(list, index))
if __name__ == '__main__':
main()
CL :
Anuvrats-MacBook-Air:Python anuvrattiku$ python binary_search.py 1 3 4 6 8 9 12 14 16 17 27 33 45 51 53 63 69 70
Please enter a number you want to search in the array !69
The list to search from [1, 3, 4, 6, 8, 9, 12, 14, 16, 17, 27, 33, 45, 51, 53, 63, 69, 70]
0
Anuvrats-MacBook-Air:Python anuvrattiku$

In Python2 and Python3 you can use bisect as written in the comments.
Replace your search with the following
from bisect import bisect_left
def search(alist, item):
'Locate the leftmost value exactly equal to item'
i = bisect_left(alist, item)
if i != len(alist) and alist[i] == item:
return i
raise ValueError
alist = [1,2,7,8,234,5,9,45,65,34,23,12]
x = 5
alist.sort() # bisect only works on sorted lists
print(search(alist, x)) # prints 2 as 5 is on position 2 in the sorted list
Also, the AS SortedCollection (Python recipe) could be useful.
The following code (from here) performs the binary search and returns position and if the item was found at all.
def binarySearch(alist, item):
first = 0
last = len(alist)-1
found = False
while first<=last and not found:
pos = 0
midpoint = (first + last)//2
if alist[midpoint] == item:
pos = midpoint
found = True
else:
if item < alist[midpoint]:
last = midpoint-1
else:
first = midpoint+1
return (pos, found)
Will return (2, True) if used in the example above.

Well, there are some little mistakes in your code. To find them, you should either use a debugger, or at least add traces to understand what happens. Here is your original code with traces that make the problems self evident:
def search(list, target):
min = 0
max = len(list)-1
avg = (min+max)/2
print list, target, avg
...
You can immediately see that:
you search in a sub array that skips avg-1 when you are below avg
as you search in a sub array you will get the index in that subarray
The fixes are now trivial:
elif (list[avg] < target):
return avg + 1 + search(list[avg+1:], target) # add the offset
else:
return search(list[:avg], target) # sublist ends below the upper limit
That's not all, when you end the loop with min == max, you do not return anything (meaning you return None). And last but not least never use a name from the standard Python library for your own variables.
So here is the fixed code:
def search(lst, target):
min = 0
max = len(lst)-1
avg = (min+max)/2
# uncomment next line for traces
# print lst, target, avg
while (min < max):
if (lst[avg] == target):
return avg
elif (lst[avg] < target):
return avg + 1 + search(lst[avg+1:], target)
else:
return search(lst[:avg], target)
# avg may be a partial offset so no need to print it here
# print "The location of the number in the array is", avg
return avg

Recursive:
def in_list(l, x):
if len(l) < 2:
if l[0] == x:
return True
else:
return False
mid = len(l) // 2
if x < l[mid]:
return in_list(l[:mid], x)
else:
return in_list(l[mid:], x)
or iterative:
def in_list2(l, x):
low = 0
high = len(l) - 1
while low <= high:
mid = (low + high) // 2
if l[mid] == x:
return True
if x < l[mid]:
high = mid - 1
else:
low = mid + 1
return False

#Serge Ballesta 's solution is undoubtly the correct answer to this question.
I am just going to add another way of solving this:
def search(arr, item, start, end):
if end-start == 1:
if arr[start] == item:
return start
else:
return -1;
halfWay = int( (end-start) / 2)
if arr[start+halfWay] > item:
return search(arr, item, start, end-halfWay)
else:
return search(arr, item, start+halfWay, end)
def binarysearch(arr, item):
return search(arr, item, 0, len(arr))
arr = [1, 3, 4, 6, 8, 9, 12, 14, 16, 17, 27, 33, 45, 51, 53, 63, 69, 70]
print("Index of 69: " + str(binarysearch(arr, 69))) # Outputs: 16

The reason you aren't getting correct result is because in every recursive call your code is sending sliced array. So the array length keeps reducing. Ideally you should work out a way to send original array and work with only start, end indices.

Related

Why is my Binary search program in python not working correctly?

# Binary search in python
def BinarySearch(A,n,x):
start = n - 1
end = 0
while start <= end:
mid = (start + end)//2
if x == A[mid]:
return mid
elif x < A[mid]:
end = mid - 1
else:
start = mid + 1
return -1
A = [4, 5, 7, 45, 64, 66, 80, 81, 92, 99]
n = len(A)
x = 64
result = BinarySearch(A,n,x)
if result != -1:
print(result)
else:
print("element is not in the array")
output : element is not in the array
whatever element I am providing to this code it's always giving the same output
Swap start and end variable values:
start = 0
end = n-1
That's because you have assigned wrong values to start and end as per algo.
start = 0
end = n - 1
Put these values and it runs.

Python query in list without for loop

I want to find a sum with pair of numbers in python list.
List is sorted
Need to check consecutive combinations
Avoid using for loop
I used a for loop to get the job done and its working fine. I want to learn other optimized way to get the same result.
Can I get the same result with other ways without using a for loop?
How could I use binary search in this situation?
This is my code:
def query_sum(list, find_sum):
"""
This function will find sum of two pairs in list
and return True if sum exist in list
:param list:
:param find_sum:
:return:
"""
previous = 0
for number in list:
sum_value = previous + number
if sum_value == find_sum:
print("Yes sum exist with pair {} {}".format(previous, number))
return True
previous = number
x = [1, 2, 3, 4, 5]
y = [1, 2, 4, 8, 16]
query_sum(x, 7)
query_sum(y, 3)
this is the result.
Yes sum exist with pair 3 4
Yes sum exist with pair 1 2
You can indeed use binary search if your list is sorted (and you are only looking at sums of successive elements), since the sums will be monotonically increasing as well. In a list of N elements, there are N-1 successive pairs. You can copy and paste any properly implemented binary search algorithm you find online and replace the criteria with the sum of successive elements. For example:
def query_sum(seq, target):
def bsearch(l, r):
if r >= l:
mid = l + (r - l) // 2
s = sum(seq[mid:mid + 2])
if s == target:
return mid
elif s > target:
return bsearch(l, mid - 1)
else:
return bsearch(mid + 1, r)
else:
return -1
i = bsearch(0, len(seq) - 1)
if i < 0:
return False
print("Sum {} exists with pair {} {}".format(target, *seq[i:i + 2]))
return True
IDEOne Link
You could use the built-in bisect module, but then you would have to pre-compute the sums. This is a much cheaper method since you only have to compute log2(N) sums.
Also, this solution avoids looping using recursion, but you might be better off writing a loop like while r >= l: around the logic instead of using recursion:
def query_sum(seq, target):
def bsearch(l, r):
while r >= l:
mid = l + (r - l) // 2
s = sum(seq[mid:mid + 2])
if s == target:
return mid
elif s > target:
r = mid - 1
else:
l = mid + 1
return -1
i = bsearch(0, len(seq) - 1)
if i < 0:
return False
print("Yes sum exist with pair {} {}".format(*seq[i:i + 2]))
return True
IDEOne Link
# simpler one:
def query_sum(seq, target):
def search(seq, index, target):
if index < len(seq):
if sum(seq[index:index+2]) == target:
return index
else:
return search(seq, index+1, target)
else:
return -1
return search(seq, 0, target)

Binary Search python 3.5

I'm trying to write binary search in python 3.5 but it wont work I'm not sure why.
def binarySearch(alist, value):
first = 0
last = len(alist)-1
midpoint = (last//2)
while binarySearch:
if value == alist[midpoint]:
return True and print ("found")
else:
if value < midpoint:
last = midpoint-1
else:
if value > midpoint:
first = midpoint+1
binarySearch([1,2,3,4,5,6,7,8],3)
if I put value as 4 it displays found, if I put anything else nothing happens and its stuck running doing nothing.
Thanks for your help.
User1915011 beat me to my answer. In line with his answer and #wim's comment, I have made the following changes your binarySearch method.
Changed the loop to use the found variable
Added an additional assignment to midpoint inside the loop
Ensure the loop terminates by adding first<=last
Return found after the while loop to indicate success or failure.
def binarySearch(alist, value):
first = 0
last = len(alist)-1
found = False
while first<=last and not found:
midpoint = (first + last)//2
if value == alist[midpoint]:
found = True
else:
if value < alist[midpoint]:
last = midpoint-1
else:
if value > midpoint:
first = midpoint+1
return found
if binarySearch([1,2,3,4,5,6,7,8],3):
print "found"
Your looping condition is just wrong while binarySearch?
You change value of midpoint only once instead you should be changing it every loop iteration.
You compare value with index (midpoint) and should be comparing with
list value (alist[midpoint])
This is wrong: return True and print ("found") it will always return None.
Here is a detailed explanation how it works:
def binarySearch(array, i):
## Binary search is the algorithm which is used to search an element in a sorted array
## The time complexity of the binary search is O(log n)
## Which means that in an array of length(2^(n-1)) elements we need to look at only n elements
## That is why we say that binary search algorithm runs in logarithmic time, which is much faster than linear time
start = 0
last = len(array)-1
result = False
count = 0 ## to debug
print("\n******************************************************************\n")
while(start <= last and not result):
## Debugger Begin
mid = 0
print("Loop number: ", count)
print("Start element: ", array[start], " Position of Start Element: ", start)
print("Last element: ", array[last], " Position of Last Element: ", last)
## Debugger End
mid = (start + last)//2 ## '//' indicates the floor division(ignores the value after the period)
if(array[mid] == i):
print("***Mid***")
result = True;
else:
if(i < array[mid]):
print("***The value of the item:",i," we are searching for is LESS than the current middle element***")
last = mid - 1
else:
print("***The value of the item:",i," we are searching for is GREATER than the current middle element***")
start = mid + 1
## Debugger
count = count+1
print("Mid element: ", array[mid], " Position of Mid Element: ", mid, "\n")
## Debugger
print("******************************************************************")
if(result == True):
print("\nThe element:",i ,"is in the array")
else:
print("\nItem is not in the array")
return result
## Array you want to search
array = [9, 11, 12, 21, 23, 34, 45, 49, 65, 98]
## Item you want to search in the array
i = 21
print("Searching the element: ",i , "\nIn the Array: ", array)
print("Length of the array is: ", len(array))
## Binary Search
binarySearch(array, i)
binary converters are also cool
num = int(input('please enter your number: '))
list = []
for i in (128, 64, 32, 16, 8, 4, 2, 1):
if num >= i:
list.append(1)
num = num-i
else:
list.append(0)
print(list)

Python 3 Recursion for Fibonacci Sequence - Listed

I'm trying to make a list of numbers on a single line that follow the Fib sequence. I'm using the recursive method of Fib(n) = Fib(n-1)+Fib(n-2) and this gives me a single value of course, when I use:
return fib(n-1)+fib(n-2)
How can I make this loop and give me a list? For example:
[1,1,2,3,5,8,13] if I typed in: 7 for n.
OK, so in some ways I have fixed it.
I now ask the user to input a value, say x, which is then used in a while loop. It passes the x value through the recursive fib function, appends this new value to a list and then decrements f by 1.
Then I used list.reverse() to reverse the list so that the numbers appear in ascending order and I then print the list.
This list has spaces between each number though, and I don't want that.
Is there a solution to this?
Slightly more streamlined than d-coder's version:
def fib(n):
a,b = 1,1
for i in xrange(n):
yield a
a,b = b,a+b
>>> list(fib(11))
>>> [1,1,2,3,5,8,13,21,34,55,89]
An iterator is the "most Pythonic solution".
class Fib:
# init creates the iterator
def __init__(self, start=0, end=None):
self.now = 0 # the most recent number in the Fibonacci sequence
self.last = 0 # second most recent number in the Fibonacci sequence
self.i = 0 # current place in the sequence
self.end = end # last place before we stop
# loop through sequence until we get to start
for i in range(start):
void = self.next()
def __iter__(self):
return self
# next() for Python 2
def next(self):
# stop if end is reached
if self.end is not None and self.i > self.end:
raise StopIteration
# find the next Fibonacci number
next = self.now + self.last
self.last = self.now
self.now = next if next > 0 else 1
# keep track of how many numbers we've output
self.i += 1
# return the next number
return self.last
# __next__() for Python 3
def __next__(self):
return next(self)
Then use it like so:
# print starting at 0
for i in Fib(0, 5):
print i
0
1
1
2
3
# print starting at 1
for i in Fib(1, 6):
print i
1
1
2
3
5
# make a list
list(Fib(end=10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
The obvious solution would be:
l = []
for i in range(n):
l.append(fib(i))
However, this would be rather inefficient. Another approach would be modifying your recursive function to return a list of fibonacci numbers until n:
def fib(n):
if n <= 0:
raise ValueError
elif n == 1:
return [1]
elif n == 2:
return [1, 1]
else:
prev = fib(n-1)
return prev + [prev[-2] + prev[-1]]
Try the following code and let me know it helped you.About generators you can find help here and here
def fibonacci(n):
a, b, counter = 0, 1, 0
while True:
if (counter > n): return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(7) ## pass the value here
my_list =[]
for x in f:
my_list.append(x)
print my_list
Recursive version, using memoization for performance:
def fib(n, hash = {0:1, 1:1}):
if n not in hash:
hash[n] = fib(n-1) + fib(n-2)
return hash[n]
testing:
>>> print(list(fib(i) for i in range(7)))
[1, 1, 2, 3, 5, 8, 13]
>>> print(list(fib(i) for i in range(11)))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
def fib(n):
if n <= 0:
return 0
elif n == 1 or n == 2:
return 1
else:
return fib(n-1)+ fib(n-2)
n=10
l = []
for i in range(n):
l.append(fib(i))
print(l)

Recursion binary search in Python [duplicate]

This question already has answers here:
What is the difference between '/' and '//' when used for division?
(16 answers)
Closed 7 months ago.
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=0
high= len(mylist)
mid=low + (high- mymin)/2
if mid==len(mylist):
return False
elif mylist[mid]==element:
return mid
elif high==low:
return False
elif 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)?
Recursive solution:
def binary_search_recursive(arr, elem, start=0, end=None):
if end is None:
end = len(arr) - 1
if start > end:
return False
mid = (start + end) // 2
if elem == arr[mid]:
return mid
if 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) // 2
if elem == arr[mid]:
return mid
if elem < arr[mid]:
end = mid - 1
else: # elem > arr[mid]
start = mid + 1
return 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) // 2
if len(arr) == 1:
return mid if arr[mid] == target else None
elif arr[mid] == target:
return mid
else:
if arr[mid] < target:
callback_response = recursive_binary_search((arr[mid:]), target)
return mid + callback_response if callback_response is not None else None
else:
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 False
mid = len(array) // 2
left = array[:mid]
right = array[mid:]
if val == array[mid]:
return True
elif 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 True
elif 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 high
pos = low + (high - low) / len(items)
if pos == len(items):
return False
elif items[pos] == value:
return pos
elif high == low:
return False
elif items[pos] < value:
return binary_search(value, items, pos + 1, high)
else:
assert items[pos] > value
return 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 False
1 0
2 1
3 2
4 False
5 3
6 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 False
mid = (low + high)//2
if arr[mid] == key:
return True
elif arr[mid] < key:
return bsearch_helper(arr, key, mid + 1, high)
else:
return bsearch_helper(arr, key, low, mid - 1)
return False
def 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 False
else:
mid = len(list1)//2
if (element == list1[mid]):
return True
else:
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 False
if last == first:
return arr[last] == item
mid = (first + last) // 2
if arr[mid] > item:
last = mid
return _binary_search(item, first, last, arr)
elif arr[mid] < item:
first = mid + 1
return _binary_search(item, first, last, arr)
else:
return arr[mid] == item
return _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 postion
def 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 None
if ep is None:
# End position equals total length minus 1 since 0 indexed
ep = len(lst) - 1
# get the midpoint of the list (lst)
mid = (sp + ep) // 2
mid_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 success
if 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 right
elif 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 False
else:
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 left
elif mid_item < n:
new_sp = mid + 1
if new_sp > ep:
print(f"Number {n} is too High. Highest number found is {lst[ep]}")
return False
else:
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 list
num_list = [10,20,30,40,50,60,70,80,90,100,110]
# Search for 10 in num_list
binary_search_recursion(10, num_list)
Start: lst[0] = 10
Mid: lst[5] = 60
End: lst[10] = 110
Number 10 is less than mid item 60, change ep 10 to 4.
Start: lst[0] = 10
Mid: lst[2] = 30
End: lst[4] = 50
Number 10 is less than mid item 30, change ep 4 to 1.
Start: lst[0] = 10
Mid: lst[0] = 10
End: lst[1] = 20
Success!!! Number 10 found in lst[0]
# Search for 110 in num_list
binary_search_recursion(110, num_list)
Start: lst[0] = 10
Mid: lst[5] = 60
End: lst[10] = 110
Number 110 is greater than mid item 60, change sp 0 to 6.
Start: lst[6] = 70
Mid: lst[8] = 90
End: lst[10] = 110
Number 110 is greater than mid item 90, change sp 6 to 9.
Start: lst[9] = 100
Mid: lst[9] = 100
End: lst[10] = 110
Number 110 is greater than mid item 100, change sp 9 to 10.
Start: lst[10] = 110
Mid: lst[10] = 110
End: lst[10] = 110
Success!!! Number 110 found in lst[10]
# Search for 6 in num_list
binary_search_recursion(6, num_list)
Start: lst[0] = 10
Mid: lst[5] = 60
End: lst[10] = 110
Number 6 is less than mid item 60, change ep 10 to 4.
Start: lst[0] = 10
Mid: lst[2] = 30
End: lst[4] = 50
Number 6 is less than mid item 30, change ep 4 to 1.
Start: lst[0] = 10
Mid: lst[0] = 10
End: lst[1] = 20
Number 6 is too low. Lowest number found is 10
# Search for 1111 in num_list
binary_search_recursion(1111, num_list)
Start: lst[0] = 10
Mid: lst[5] = 60
End: lst[10] = 110
Number 1111 is greater than mid item 60, change sp 0 to 6.
Start: lst[6] = 70
Mid: lst[8] = 90
End: lst[10] = 110
Number 1111 is greater than mid item 90, change sp 6 to 9.
Start: lst[9] = 100
Mid: lst[9] = 100
End: lst[10] = 110
Number 1111 is greater than mid item 100, change sp 9 to 10.
Start: lst[10] = 110
Mid: lst[10] = 110
End: lst[10] = 110
Number 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 callbinarySearch(l, 10, 8, 10), then binarySearch(l, 10, 9, 10), thenbinarySearch(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 False
0 0
1 1
4 4
5 5
9 9
10 False
11 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)-1
if max<min:
return False
else:
mid= min + (max-min)/2
if 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)-1
max 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 7
binary_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 maxi
if mini == maxi:
return array[mini] == element
else:
median = (maxi + mini)/2
if array[median] == element:
return True
elif 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 math
def insert_rec(A,v,fi,li):
mi = int(math.floor((li+fi)/2))
if A[mi] == v:
print("Yes found at: ",mi)
return
if fi==li or fi>li:
print("Not found")
return
if A[mi] < v:
fi = mi+1
insert_rec(A,v,fi,li)
if A[mi] > v:
li = mi-1
insert_rec(A,v,fi,li)
def bs(list,num): #presume that the list is a sorted list
#base case
mid=int(len(list)/2) # to divide the list into two parts
if num==list[mid]:
return True
if len(list)==1:
return False
#recursion
elif num<list[mid]: #if the num is less than mid
return bs(list[0:mid],num) #then omit all the nums after the mid
elif num>list[mid]: #if the num is greater than mid
return bs(list[mid:],num) # then omit all the nums before the mid
#return False
list=[1,2,3,4,5,6,7,8,9,10]
print(bs(list,20))
<<< False
print(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) - 1
if 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 mid
if 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 False
else:
mid = len(arr)/2
if arr[mid] == ele:
return True
else:
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 = 0
high = len(list) - 1
if low <= high:
mid = low + high
guess = list[mid]
if guess == item:
return mid
if guess > item: # item must be in the first split
return recursive_binary_search(list[low:mid], item)
else: # check in second split otherwise
return recursive_binary_search(list[mid:high], item)
return None
def main():
print(recursive_binary_search([2,3,4,5,6,7,8], 3)) # will print 1
if __name__ == "__main__":
main()

Categories

Resources