i am coding binary search, I define a function ,and have 4 parameter, one of the parameter that number is the number you want to search ,but when i
input a big number which bigger than the last number of list ,the compiler will display the list index out of range, what is the connection between number and index?
list = [2, 3, 4, 6, 8, 9, 10, 11, 20]
mid = len(list) / 2
left = 0
right = len(list)
def searchNumber(left, right, number, mid):
while left <= right:
mid = (right - left) / 2 + left
if list[mid] == number:
print("the local is in %d" % (mid))
return mid
break
elif list[mid] > number:
right = mid - 1
else:
left = mid + 1
list = [2, 3, 4, 6, 8, 9, 10, 11, 20]
mid = len(list) / 2
left = 0
right = len(list)
def searchNumber(left, right, number, mid):
**while left < right:**
mid = (right - left) / 2 + left
if list[mid] == number:
print("the local is in %d" % (mid))
return mid
break
elif list[mid] > number:
right = mid - 1
else:
left = mid + 1
I ran this code,
list = [2, 3, 4, 6, 8, 9, 10, 11, 20]
mid = len(list) / 2
left = 0
right = len(list)
def searchNumber(left, right, number, mid):
while left <= right:
mid = (right - left) / 2 + left
if list[mid] == number:
print("the local is in %d" % (mid))
return mid
break
elif list[mid] > number:
right = mid - 1
else:
left = mid + 1
return None
a = searchNumber(0, len(list)-1, 40, 40)
print "a =" + str(a)
b = searchNumber(0, len(list)-1, 9, 5)
print "b =" + str(b)
I got correct output in both the cases, where the asked number is present and the asking number is larger than the largest number of the list.
$ python pyt.py
a = None
the local is in 5
b = 5
I suspect the Error you get is because you're passing number which is negative or bigger than length-1 of the array, I don't see any other cases where you'll get "index out of range" Error.
Related
This question already has answers here:
I found a mistake in the book "Grokking Algorithms"
(2 answers)
Closed last year.
Im starting to learn about Algorithms (using the grokkings algorithms book) and this is the binary search code that was in the book
def binary_search(list, item):
low = 0
high = len(list) - 1
while low <= high:
mid = round((low + high) )
guess = list[mid]
if guess == mid:
return mid
if guess > mid:
high = mid - 1
else:
low = mid + 1
return None
my_list = [1, 3, 5, 7, 9]
print(binary_search(my_list, 3))
print(binary_search(my_list, -1))
The first one is supposed to return 1 but it returns None twice, anyone know why?
Try comparing guess with item:
def binary_search(lst, item):
low = 0
high = len(lst) - 1
while low <= high:
mid = (low + high) // 2
guess = lst[mid]
if guess < item:
low = mid + 1
elif guess > item:
high = mid - 1
else:
return mid
return None
my_list = [1, 3, 5, 7, 9]
print(binary_search(my_list, 3))
print(binary_search(my_list, -1))
Output:
1
None
In the code is suppose to be mid = (low + high) // 2, where // is whole division.
I have a question about the Python version of recursive Merge Sort. I completed the basic version, which is only referred by the array, and am now working on the index version. I will sink into the endless loop, but I am not sure where I did wrong. Would you mind sharing some ideas? Thank you in advance.
The successful and non-index version:
def mergesort(x):
# The base case is when the array contains less than 1 observation.
length = len(x)
if length < 2:
return x
else:
# Recursive case:merge sort on the lower subarray, and the upper subarray.
mid = (length) // 2
lower = mergesort(x[:mid])
upper = mergesort(x[mid:])
# merge two subarrays.
x_sorted = merge(lower, upper)
return (x_sorted)
def merge(lower, upper):
nlower = len(lower)
nupper = len(upper)
i, j, k = 0, 0, 0
# create a temp array to store the sorted results
temp = [0] * (nlower + nupper)
# as the lower and upper are sorted, since the base case is the single observation.
# now we compare the smallest element in each sorted array, and store the smaller one to the temp array
# repeat this process until one array is completed moved to the temp array
# store the other array to the end of the temp array
while i < nlower and j < nupper:
if lower[i] <= upper[j]:
temp[k] = lower[i]
i += 1
k += 1
else:
temp[k] = upper[j]
j += 1
k += 1
if i == nlower:
temp[i+j:] = upper[j:]
else:
temp[i+j:] = lower[i:]
return temp
With expected results:
x = random.sample(range(0, 30), 15)
mergesort(x)
[0, 1, 3, 6, 9, 10, 11, 13, 14, 17, 18, 20, 25, 27, 29]
But I will stuck into the endless loop with the index version:
def ms(x, left, right):
# the base case: right == left as a single-element array
if left < right:
mid = (left + right) // 2
ms(x, left, mid)
ms(x, mid, right + 1)
m(x, left, mid, right)
return m
def m(x, left, mid, right):
nlower = mid - left
nupper = right - mid + 1
temp = [0] * (nlower + nupper)
ilower, iupper, k = left, mid, 0
while ilower < mid and iupper < right + 1:
if x[ilower] <= x[iupper]:
temp[k] = x[ilower]
ilower += 1
k += 1
else:
temp[k] = x[iupper]
iupper += 1
k += 1
if ilower == mid:
temp[k:] = x[iupper:right+1]
else:
temp[k:] = x[ilower:mid]
x[left:right+1] = temp
return x
The test data as:
x = random.sample(range(0, 30), 15)
ms(x, 0, 14)
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
<ipython-input-59-39859c9eae4a> in <module>
1 x = random.sample(range(0, 30), 15)
----> 2 ms(x, 0, 14)
... last 2 frames repeated, from the frame below ...
<ipython-input-57-854342dcdefb> in ms(x, left, right)
3 if left < right:
4 mid = (left + right)//2
----> 5 ms(x, left, mid)
6 ms(x, mid, right+1)
7 m(x, left, mid, right)
RecursionError: maximum recursion depth exceeded in comparison
Would you mind providing some insights? Thanks.
Your index version uses a confusing convention whereby left is the index of the first element in the slice and right is the index of the last element. This convention requires error-prone +1/-1 adjustments. Your problem is this: mid as computed is the index of the last element in the left half, but you consider mid to be the first element of the right half: a slice of 2 elements is split into one with 0 and one with 2, hence the infinite recursion. You can fix this problem by changing ms(x, mid, right+1) to ms(x, mid+1, right), etc.
Furthermore, retuning m from function ms makes no sense. You should return x if anything at all.
It is much less error prone for right to be the index one past the last element, just like range specifiers in Python. This way there are no confusing +1/-1 adjustments.
Here is modified version:
def ms(x, left, right):
# the base case: right - left as a single-element array
if right - left >= 2:
mid = (left + right) // 2 # index of the first element of the right half
ms(x, left, mid)
ms(x, mid, right)
m(x, left, mid, right)
return x
def m(x, left, mid, right):
nlower = mid - left
nupper = right - mid
temp = [0] * (nlower + nupper)
ilower, iupper, k = left, mid, 0
while ilower < mid and iupper < right:
if x[ilower] <= x[iupper]:
temp[k] = x[ilower]
ilower += 1
k += 1
else:
temp[k] = x[iupper]
iupper += 1
k += 1
if ilower == mid:
temp[k:] = x[iupper:right]
else:
temp[k:] = x[ilower:mid]
x[left:right] = temp
return x
You would invoke as:
x = random.sample(range(0, 30), 15)
ms(x, 0, len(x))
# 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.
I'm trying to write a function that returns the last position of an element in a sorted list, however I'm not quite sure of how binary search works. Can someone help me fix the problem in my code?
def last_entry(L, target):
low = 0
high = len(L) - 1
while low <= high:
mid = (low + high) // 2
if L[mid] < target:
low = mid + 1
elif L[mid] > target:
high = mid - 1
else:
if mid == len(L) - 1:
return mid
if target < L[mid + 1]:
return mid
return -1
The problem lies here:
else:
if mid == len(L) - 1:
return mid
if target < L[mid + 1]:
return mid
It's incomplete. If you use the input list [0, 0, 1, 3, 3, 3, 4, 8] and target 3, it will loop infinitely (I haven't tested it though). So you need to keep searching in the upper half for the target:
else:
if mid == len(L) - 1:
return mid
if target < L[mid + 1]:
return mid
low = mid + 1
Edit: I tested my solution and I think it works
You can separate the problems. First we do the binary search, then we verify if it's the latest occurrence in list.
lst = [1, 2, 2, 2, 3, 4, 4, 5, 6, 7, 7, 7, 8, 8, 9]
def search(lst, target):
min = 0
max = len(lst)-1
avg = (min+max)//2
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)
return avg
def find_latest(lst, index):
current = lst[index]
index += 1
while lst[index] == current:
current = lst[index]
index += 1
return index - 1
find_latest(lst ,search(lst, 4))
So I have this problem.
You are given a landscape in the form of a non-empty one-dimensional
array seq. The goal is to find an index i of a cell that is a pit. We
say seq[i] is a pit if seq[i] <= seq[i-1] and seq[i] <= seq[i+1]. For
example in the array [7, 6, 9, 7, 8], the indices 1 and 3 are pits.
The first or last elements are considered to be a pit if they are less
than or equal to their only neighbour. For example the last element of
[3, 2, 4, 4, 1] is a pit (and also index 1). Note that the definition
of a pit also includes equality; for example in [3, 2, 2, 2, 5, 6, 6,
8], the indices 1, 2, 3, and 6 are pits. As a special case, we also
define the only cell of an array of length one to be a pit as well.
I've formulated a solution using a binary search (kind of) to achieve O(logn) as the worst case time. But I've encountered an example which returns nothing or NONE.
def find_pit(seq):
first = 0
last = len(seq) - 1
origlast = last
mid = 0
if len(seq) == 1 :
return 0
else:
while first <= last & mid < last :
mid = (first + last) // 2
if seq[mid] <= seq[mid - 1] & seq[mid] <= seq[mid + 1]:
return mid
else:
if seq[mid] > seq[mid - 1]:
last = mid
else:
first = mid
if seq[0] <= seq[1]:
return 0
elif seq[origlast] <= seq[origlast-1]:
return (len(seq) - 1)
print(find_pit([0,1]))
print(find_pit([5, 4, 3, 6, 7]))
How do I fix this?
You need to change the
& (bitwise "and")
to
and (logical "and")
in your code:
def find_pit(seq):
first = 0
last = len(seq) - 1
origlast = last
mid = 0
if len(seq) == 1 :
return 0
else:
#change next line to use logical and
while first <= last and mid < last :
mid = (first + last) // 2
#change next line to use logical and
if seq[mid] <= seq[mid - 1] and seq[mid] <= seq[mid + 1]:
return mid
else:
if seq[mid] > seq[mid - 1]:
last = mid
else:
first = mid
if seq[0] <= seq[1]:
return 0
elif seq[origlast] <= seq[origlast-1]:
return (len(seq) - 1)
print(find_pit([0,1]))
print(find_pit([5, 4, 3, 6, 7]))
Running this with the above test cases will now give the result:
0 for the first list and 2 for the second.
seems to work at finding first pit in the given cases. I've tweaked the call to allow multiple functions to be checked.
#.... original find_pit left, but not pasted in
import sys
def find_pit2(seq):
left = sys.maxint
maxp = len(seq)
if maxp == 1 :
return 0
else:
for pos, current in enumerate(seq):
try:
right = seq[pos+1]
except IndexError:
#rightmost, count as right neighbor as bigger
right = sys.maxint
#pit - smaller or equal to neighbours
if left >= current and current <= right:
return pos
left = current
li_f = [find_pit, find_pit2]
for f in li_f:
print f.__name__
print(" ",f([0,1]))
print(" ",f([5, 4, 3, 6, 7]))
print(" ",f([7, 6, 9, 7, 8]))
print(" ",f([3, 2, 2, 2, 5, 6, 6, 8]))
giving
find_pit
(' ', 0)
(' ', 2)
(' ', None)
(' ', 3)
find_pit2
(' ', 0)
(' ', 2)
(' ', 1)
(' ', 1)