Unable to properly compare Binary vs. Linear search
Question:
def linear_search(a_list, key):
steps = 0
for i, item in enumerate(a_list):
steps += 1
if item == key:
break
return steps
def binary_search(a_list, key):
a_list.sort()
steps = 1
left = 0
right = len(a_list) - 1
while left <= right:
steps += 1
middle = (left + right) // 2
if a_list[middle] == key:
break
if a_list[middle] > key:
right = middle - 1
if a_list[middle] < key:
left = middle + 1
return steps
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if linear_search(a_list, key) < binary_search(a_list, key):
results += "Best Search is Linear."
elif binary_search(a_list, key) < linear_search(a_list, key):
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
Test
print(best_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1))
print(best_search([10, 2, 9, 1, 7, 5, 3, 4, 6, 8], 1))
print(best_search([10, 9, 8, 7, 6, 5, 4, 3, 2, 1], 7))
print(best_search([1, 3, 5, 7, 9, 10, 2, 4, 6, 8], 10))
print(best_search([5, 1, 8, 2, 4, 10, 7, 6, 3, 9], 11))
I have debugged this code and can’t figure out why it will not tie. It does count the steps right but doesn’t properly decide which one is better.
Answers:
So there are a couple of problems with your code:
-
As @Samwise said, you aren’t calling your search functions in best_search
. That should be updated:
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
...
-
However, once you do that, another problem arises after you run the code:
Linear: -1 steps, Binary: 0 steps. Best Search is Linear.
Linear: -1 steps, Binary: 0 steps. Best Search is Linear.
Linear: -1 steps, Binary: 6 steps. Best Search is Linear.
Linear: -1 steps, Binary: 9 steps. Best Search is Linear.
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
These obviously aren’t the desired outputs. Why is linear_search
always returning -1? It is always returning -1 because that’s what you specify it to always return:
def linear_search(a_list, key):
# Returns the number of steps to determine if key is in the list
# Initialize the counter of steps
steps = 0
for i, item in enumerate(a_list):
steps += 1
if item == key:
break
return -1 # <--- this is your only return statement!!
But you want to return the number of steps it take to perform the search—so return that. Instead of breaking the loop when (if) you find the key, just return it, since returning the steps will end the function:
if item == key:
return steps
Output:
Linear: 1 steps, Binary: 0 steps. Best Search is Binary.
Linear: 4 steps, Binary: 0 steps. Best Search is Binary.
Linear: 4 steps, Binary: 6 steps. Best Search is Linear.
Linear: 6 steps, Binary: 9 steps. Best Search is Linear.
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
Already looking better . linear_search
returns the desired output for all but the last test, which I’ll get to later.
-
The function binary_steps
, though, isn’t returning the desired outputs. Why? Well, for starters, you never actually return steps
:
def binary_search(a_list, key):
# Returns the number of steps to determine if key is in the list
# List must be sorted:
a_list.sort()
# The Sort was 1 step, so initialize the counter of steps to 1
steps = 1
left = 0
right = len(a_list) - 1
while left <= right:
middle = (left + right) // 2
if a_list[middle] == key:
return middle # you return `middle`
if a_list[middle] > key:
right = middle - 1
if a_list[middle] < key:
left = middle + 1
return -1 # or -1, but not `steps`
Instead, you return middle
when a match is found. So replace that with return steps
:
if a_list[middle] == key:
return steps
But now you get this:
Linear: 1 steps, Binary: 1 steps. Result is a Tie.
Linear: 4 steps, Binary: 1 steps. Best Search is Binary.
Linear: 4 steps, Binary: 1 steps. Best Search is Binary.
Linear: 6 steps, Binary: 1 steps. Best Search is Binary.
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
That’s still not your desired output. Why isn’t binary_search
returning the desired output? Because you are not incrementing steps
for each iteration of the loop, so steps
will always be 1! Increment steps
at each loop iteration:
while left <= right:
steps += 1
middle = (left + right) // 2
...
…and look what we’ve got:
Linear: 1 steps, Binary: 4 steps. Best Search is Linear.
Linear: 4 steps, Binary: 4 steps. Result is a Tie.
Linear: 4 steps, Binary: 5 steps. Best Search is Linear.
Linear: 6 steps, Binary: 5 steps. Best Search is Binary.
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
-
Everything but the last test returns your desired output. But what’s up with that last test? Let’s check it out:
print(best_search([5, 1, 8, 2, 4, 10, 7, 6, 3, 9], 11))
# Should be: Linear: 10 steps, Binary: 5 steps. Best Search is Binary.
Well, it’s clear to see that you won’t find 11 in a list without 11, so you can never get your desired output here. You’d either have to change the key, or modify the input list and and an 11 to it.
Here’s the final code:
def linear_search(a_list, key):
# Returns the number of steps to determine if key is in the list
# Initialize the counter of steps
steps = 0
for i, item in enumerate(a_list):
steps += 1
if item == key:
return steps
return -1
def binary_search(a_list, key):
# Returns the number of steps to determine if key is in the list
# List must be sorted:
a_list.sort()
# The Sort was 1 step, so initialize the counter of steps to 1
steps = 1
left = 0
right = len(a_list) - 1
while left <= right:
steps += 1
middle = (left + right) // 2
if a_list[middle] == key:
return steps
if a_list[middle] > key:
right = middle - 1
if a_list[middle] < key:
left = middle + 1
return -1
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if steps_linear < steps_binary:
results += "Best Search is Linear."
elif steps_binary < steps_linear:
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
print(best_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1))
# Should be: Linear: 1 steps, Binary: 4 steps. Best Search is Linear.
print(best_search([10, 2, 9, 1, 7, 5, 3, 4, 6, 8], 1))
# Should be: Linear: 4 steps, Binary: 4 steps. Result is a Tie.
print(best_search([10, 9, 8, 7, 6, 5, 4, 3, 2, 1], 7))
# Should be: Linear: 4 steps, Binary: 5 steps. Best Search is Linear.
print(best_search([1, 3, 5, 7, 9, 10, 2, 4, 6, 8], 10))
# Should be: Linear: 6 steps, Binary: 5 steps. Best Search is Binary.
print(best_search([5, 1, 8, 2, 4, 10, 7, 6, 3, 9], 11))
# Should be: Linear: 10 steps, Binary: 5 steps. Best Search is Binary.
This should work for you now.
As for your other problem (seen after editing the question), the problem is that you have the lines:
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
…in best_search
, but you’re calling linear_search
and best_search
again to compare them:
if linear_search(a_list, key) < binary_search(a_list, key):
results += "Best Search is Linear."
elif binary_search(a_list, key) < linear_search(a_list, key):
results += "Best Search is Binary."
Not only is this not needed, it actually messes up the test. If you look at a_list
as it progresses through best_search
, you’ll notice something:
a_list, before calling any searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 1 steps, Binary: 4 steps. Best Search is Linear.
a_list, before calling any searches: [10, 2, 9, 1, 7, 5, 3, 4, 6, 8]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 4 steps, Binary: 4 steps. Best Search is Linear.
a_list, before calling any searches: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 4 steps, Binary: 5 steps. Best Search is Binary.
a_list, before calling any searches: [1, 3, 5, 7, 9, 10, 2, 4, 6, 8]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 6 steps, Binary: 5 steps. Best Search is Binary.
a_list, before calling any searches: [5, 1, 8, 2, 4, 10, 7, 6, 3, 9]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
After every search, a_list
ends up sorted. Why? Because whenever you call binary_search
, this is the first thing run:
a_list.sort()
Python’s .sort()
modifies the list itself; it does not return a new list. So let’s take a look at best_search
again (notice the comments):
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key) # <-- you call binary_search for the first time, so a_list is sorted
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if linear_search(a_list, key) < binary_search(a_list, key): # <-- you call linear_serch and binary_search with the sorted list
results += "Best Search is Linear."
elif binary_search(a_list, key) < linear_search(a_list, key):
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
So basically your tests end up to be the same, because you are sorting the list before searching, each time. To fix this, just compare steps_linear
to steps_binary
without calling the functions again; that’s redundant. Like so:
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if steps_linear < steps_binary:
results += "Best Search is Linear."
elif steps_binary < steps_linear:
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
Output:
Linear: 1 steps, Binary: 4 steps. Best Search is Linear.
Linear: 4 steps, Binary: 4 steps. Result is a Tie.
Linear: 4 steps, Binary: 5 steps. Best Search is Linear.
Linear: 6 steps, Binary: 5 steps. Best Search is Binary.
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
Now the comparison works.
to fix below
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
we need to replace "return -1" to "return steps"
Although these answers are correct, it wasn’t running for me until I replaced return -1
with return steps
. Replace return -1
with return steps
, and it will not reveal the same answer every time.
def linear_search(a_list, key):
steps = 0
for i, item in enumerate(a_list):
steps += 1
if item == key:
break
return steps
def binary_search(a_list, key):
a_list.sort()
steps = 1
left = 0
right = len(a_list) - 1
while left <= right:
steps += 1
middle = (left + right) // 2
if a_list[middle] == key:
break
if a_list[middle] > key:
right = middle - 1
if a_list[middle] < key:
left = middle + 1
return steps
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if linear_search(a_list, key) < binary_search(a_list, key):
results += "Best Search is Linear."
elif binary_search(a_list, key) < linear_search(a_list, key):
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
Test
print(best_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1))
print(best_search([10, 2, 9, 1, 7, 5, 3, 4, 6, 8], 1))
print(best_search([10, 9, 8, 7, 6, 5, 4, 3, 2, 1], 7))
print(best_search([1, 3, 5, 7, 9, 10, 2, 4, 6, 8], 10))
print(best_search([5, 1, 8, 2, 4, 10, 7, 6, 3, 9], 11))
I have debugged this code and can’t figure out why it will not tie. It does count the steps right but doesn’t properly decide which one is better.
So there are a couple of problems with your code:
-
As @Samwise said, you aren’t calling your search functions in
best_search
. That should be updated:steps_linear = linear_search(a_list, key) steps_binary = binary_search(a_list, key) ...
-
However, once you do that, another problem arises after you run the code:
Linear: -1 steps, Binary: 0 steps. Best Search is Linear. Linear: -1 steps, Binary: 0 steps. Best Search is Linear. Linear: -1 steps, Binary: 6 steps. Best Search is Linear. Linear: -1 steps, Binary: 9 steps. Best Search is Linear. Linear: -1 steps, Binary: -1 steps. Result is a Tie.
These obviously aren’t the desired outputs. Why is
linear_search
always returning -1? It is always returning -1 because that’s what you specify it to always return:def linear_search(a_list, key): # Returns the number of steps to determine if key is in the list # Initialize the counter of steps steps = 0 for i, item in enumerate(a_list): steps += 1 if item == key: break return -1 # <--- this is your only return statement!!
But you want to return the number of steps it take to perform the search—so return that. Instead of breaking the loop when (if) you find the key, just return it, since returning the steps will end the function:
if item == key: return steps
Output:
Linear: 1 steps, Binary: 0 steps. Best Search is Binary. Linear: 4 steps, Binary: 0 steps. Best Search is Binary. Linear: 4 steps, Binary: 6 steps. Best Search is Linear. Linear: 6 steps, Binary: 9 steps. Best Search is Linear. Linear: -1 steps, Binary: -1 steps. Result is a Tie.
Already looking better .
linear_search
returns the desired output for all but the last test, which I’ll get to later. -
The function
binary_steps
, though, isn’t returning the desired outputs. Why? Well, for starters, you never actually returnsteps
:def binary_search(a_list, key): # Returns the number of steps to determine if key is in the list # List must be sorted: a_list.sort() # The Sort was 1 step, so initialize the counter of steps to 1 steps = 1 left = 0 right = len(a_list) - 1 while left <= right: middle = (left + right) // 2 if a_list[middle] == key: return middle # you return `middle` if a_list[middle] > key: right = middle - 1 if a_list[middle] < key: left = middle + 1 return -1 # or -1, but not `steps`
Instead, you return
middle
when a match is found. So replace that withreturn steps
:if a_list[middle] == key: return steps
But now you get this:
Linear: 1 steps, Binary: 1 steps. Result is a Tie. Linear: 4 steps, Binary: 1 steps. Best Search is Binary. Linear: 4 steps, Binary: 1 steps. Best Search is Binary. Linear: 6 steps, Binary: 1 steps. Best Search is Binary. Linear: -1 steps, Binary: -1 steps. Result is a Tie.
That’s still not your desired output. Why isn’t
binary_search
returning the desired output? Because you are not incrementingsteps
for each iteration of the loop, sosteps
will always be 1! Incrementsteps
at each loop iteration:while left <= right: steps += 1 middle = (left + right) // 2 ...
…and look what we’ve got:
Linear: 1 steps, Binary: 4 steps. Best Search is Linear. Linear: 4 steps, Binary: 4 steps. Result is a Tie. Linear: 4 steps, Binary: 5 steps. Best Search is Linear. Linear: 6 steps, Binary: 5 steps. Best Search is Binary. Linear: -1 steps, Binary: -1 steps. Result is a Tie.
-
Everything but the last test returns your desired output. But what’s up with that last test? Let’s check it out:
print(best_search([5, 1, 8, 2, 4, 10, 7, 6, 3, 9], 11)) # Should be: Linear: 10 steps, Binary: 5 steps. Best Search is Binary.
Well, it’s clear to see that you won’t find 11 in a list without 11, so you can never get your desired output here. You’d either have to change the key, or modify the input list and and an 11 to it.
Here’s the final code:
def linear_search(a_list, key):
# Returns the number of steps to determine if key is in the list
# Initialize the counter of steps
steps = 0
for i, item in enumerate(a_list):
steps += 1
if item == key:
return steps
return -1
def binary_search(a_list, key):
# Returns the number of steps to determine if key is in the list
# List must be sorted:
a_list.sort()
# The Sort was 1 step, so initialize the counter of steps to 1
steps = 1
left = 0
right = len(a_list) - 1
while left <= right:
steps += 1
middle = (left + right) // 2
if a_list[middle] == key:
return steps
if a_list[middle] > key:
right = middle - 1
if a_list[middle] < key:
left = middle + 1
return -1
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if steps_linear < steps_binary:
results += "Best Search is Linear."
elif steps_binary < steps_linear:
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
print(best_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1))
# Should be: Linear: 1 steps, Binary: 4 steps. Best Search is Linear.
print(best_search([10, 2, 9, 1, 7, 5, 3, 4, 6, 8], 1))
# Should be: Linear: 4 steps, Binary: 4 steps. Result is a Tie.
print(best_search([10, 9, 8, 7, 6, 5, 4, 3, 2, 1], 7))
# Should be: Linear: 4 steps, Binary: 5 steps. Best Search is Linear.
print(best_search([1, 3, 5, 7, 9, 10, 2, 4, 6, 8], 10))
# Should be: Linear: 6 steps, Binary: 5 steps. Best Search is Binary.
print(best_search([5, 1, 8, 2, 4, 10, 7, 6, 3, 9], 11))
# Should be: Linear: 10 steps, Binary: 5 steps. Best Search is Binary.
This should work for you now.
As for your other problem (seen after editing the question), the problem is that you have the lines:
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
…in best_search
, but you’re calling linear_search
and best_search
again to compare them:
if linear_search(a_list, key) < binary_search(a_list, key):
results += "Best Search is Linear."
elif binary_search(a_list, key) < linear_search(a_list, key):
results += "Best Search is Binary."
Not only is this not needed, it actually messes up the test. If you look at a_list
as it progresses through best_search
, you’ll notice something:
a_list, before calling any searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 1 steps, Binary: 4 steps. Best Search is Linear.
a_list, before calling any searches: [10, 2, 9, 1, 7, 5, 3, 4, 6, 8]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 4 steps, Binary: 4 steps. Best Search is Linear.
a_list, before calling any searches: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 4 steps, Binary: 5 steps. Best Search is Binary.
a_list, before calling any searches: [1, 3, 5, 7, 9, 10, 2, 4, 6, 8]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: 6 steps, Binary: 5 steps. Best Search is Binary.
a_list, before calling any searches: [5, 1, 8, 2, 4, 10, 7, 6, 3, 9]
a_list, after calling all searches: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
After every search, a_list
ends up sorted. Why? Because whenever you call binary_search
, this is the first thing run:
a_list.sort()
Python’s .sort()
modifies the list itself; it does not return a new list. So let’s take a look at best_search
again (notice the comments):
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key) # <-- you call binary_search for the first time, so a_list is sorted
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if linear_search(a_list, key) < binary_search(a_list, key): # <-- you call linear_serch and binary_search with the sorted list
results += "Best Search is Linear."
elif binary_search(a_list, key) < linear_search(a_list, key):
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
So basically your tests end up to be the same, because you are sorting the list before searching, each time. To fix this, just compare steps_linear
to steps_binary
without calling the functions again; that’s redundant. Like so:
def best_search(a_list, key):
steps_linear = linear_search(a_list, key)
steps_binary = binary_search(a_list, key)
results = "Linear: " + str(steps_linear) + " steps, "
results += "Binary: " + str(steps_binary) + " steps. "
if steps_linear < steps_binary:
results += "Best Search is Linear."
elif steps_binary < steps_linear:
results += "Best Search is Binary."
else:
results += "Result is a Tie."
return results
Output:
Linear: 1 steps, Binary: 4 steps. Best Search is Linear.
Linear: 4 steps, Binary: 4 steps. Result is a Tie.
Linear: 4 steps, Binary: 5 steps. Best Search is Linear.
Linear: 6 steps, Binary: 5 steps. Best Search is Binary.
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
Now the comparison works.
to fix below
Linear: -1 steps, Binary: -1 steps. Result is a Tie.
we need to replace "return -1" to "return steps"
Although these answers are correct, it wasn’t running for me until I replaced return -1
with return steps
. Replace return -1
with return steps
, and it will not reveal the same answer every time.