python: unit tests for binary search
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
def binary_search(list, item):
|
||||
# low and high keep track of which part of the list you'll search in.
|
||||
low = 0
|
||||
high = len(list) - 1
|
||||
|
||||
# While you haven't narrowed it down to one element ...
|
||||
while low <= high:
|
||||
# ... check the middle element
|
||||
mid = (low + high) // 2
|
||||
guess = list[mid]
|
||||
# Found the item.
|
||||
if guess == item:
|
||||
return mid
|
||||
# The guess was too high.
|
||||
if guess > item:
|
||||
high = mid - 1
|
||||
# The guess was too low.
|
||||
else:
|
||||
low = mid + 1
|
||||
|
||||
# Item doesn't exist
|
||||
return None
|
||||
|
||||
my_list = [1, 3, 5, 7, 9]
|
||||
print(binary_search(my_list, 3)) # => 1
|
||||
|
||||
# 'None' means nil in Python. We use to indicate that the item wasn't found.
|
||||
print(binary_search(my_list, -1)) # => None
|
||||
58
01_introduction_to_algorithms/python/binary_search.py
Normal file
58
01_introduction_to_algorithms/python/binary_search.py
Normal file
@@ -0,0 +1,58 @@
|
||||
class BinarySearch():
|
||||
|
||||
def search_iterative(self, list, item):
|
||||
# low and high keep track of which part of the list you'll search in.
|
||||
low = 0
|
||||
high = len(list) - 1
|
||||
|
||||
# While you haven't narrowed it down to one element ...
|
||||
while low <= high:
|
||||
# ... check the middle element
|
||||
mid = (low + high) // 2
|
||||
guess = list[mid]
|
||||
# Found the item.
|
||||
if guess == item:
|
||||
return mid
|
||||
# The guess was too high.
|
||||
if guess > item:
|
||||
high = mid - 1
|
||||
# The guess was too low.
|
||||
else:
|
||||
low = mid + 1
|
||||
|
||||
# Item doesn't exist
|
||||
return None
|
||||
|
||||
def search_recursive(self, list, low, high, item):
|
||||
# Check base case
|
||||
if high >= low:
|
||||
|
||||
mid = (high + low) // 2
|
||||
guess = list[mid]
|
||||
|
||||
# If element is present at the middle itself
|
||||
if guess == item:
|
||||
return mid
|
||||
|
||||
# If element is smaller than mid, then it can only
|
||||
# be present in left subarray
|
||||
elif guess > item:
|
||||
return self.search_recursive(list, low, mid - 1, item)
|
||||
|
||||
# Else the element can only be present in right subarray
|
||||
else:
|
||||
return self.search_recursive(list, mid + 1, high, item)
|
||||
|
||||
else:
|
||||
# Element is not present in the array
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
# We must initialize the class to use the methods of this class
|
||||
bs = BinarySearch()
|
||||
my_list = [1, 3, 5, 7, 9]
|
||||
|
||||
print(bs.search_iterative(my_list, 3)) # => 1
|
||||
|
||||
# 'None' means nil in Python. We use to indicate that the item wasn't found.
|
||||
print(bs.search_iterative(my_list, -1)) # => None
|
||||
6
01_introduction_to_algorithms/python/items.json
Normal file
6
01_introduction_to_algorithms/python/items.json
Normal file
File diff suppressed because one or more lines are too long
107
01_introduction_to_algorithms/python/test_binary_search.py
Normal file
107
01_introduction_to_algorithms/python/test_binary_search.py
Normal file
@@ -0,0 +1,107 @@
|
||||
from binary_search import BinarySearch
|
||||
import unittest
|
||||
import json
|
||||
import time
|
||||
|
||||
bs = BinarySearch()
|
||||
|
||||
# Unloading all lists from a file
|
||||
with open("items.json", "r") as file:
|
||||
data = json.load(file)
|
||||
|
||||
# Setting values to created variables
|
||||
simple_list = data["simple_list"]
|
||||
list_with_10_items = data["list_with_10_items"]
|
||||
list_with_100_items = data["list_with_100_items"]
|
||||
list_with_1000_items = data["list_with_1000_items"]
|
||||
|
||||
|
||||
# Test cases to test Binary Search algorithm
|
||||
class TestBinarySearch(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
print (".......... %s" % self._testMethodName)
|
||||
|
||||
# Checking the implementation of iterative binary search
|
||||
def test_iterative_binary_search_with_simple_list(self):
|
||||
# ARRANGE
|
||||
# You can check the index of each item in the items.json file
|
||||
item, expected_index = 3, 1
|
||||
|
||||
# ACT
|
||||
# Run the method we created and get the index of the item we were looking for
|
||||
index = bs.search_iterative(simple_list, item) # => 1
|
||||
|
||||
# ASSERT
|
||||
# Compare the resulting index with the expected index
|
||||
self.assertEqual(expected_index, index) # => 1 == 1
|
||||
|
||||
def test_recoursive_binary_search_with_simple_list(self):
|
||||
item, expected_index = 3, 1
|
||||
# To run recursive search for an item,
|
||||
# we need to determine the minimum and maximum indexes of the list
|
||||
low, high = 0, len(simple_list) - 1
|
||||
|
||||
index = bs.search_recursive(simple_list, low, high, item)
|
||||
|
||||
self.assertEqual(expected_index, index)
|
||||
|
||||
def test_search_for_nonexistent_item(self):
|
||||
# Specifically set a number that is not in the list
|
||||
item, expected_result = 100, None
|
||||
|
||||
# Trying to find an item that doesn't exist
|
||||
index = bs.search_iterative(simple_list, item) # => None
|
||||
|
||||
self.assertEqual(expected_result, index)
|
||||
|
||||
def test_binary_search_and_linear_search_execution_time(self):
|
||||
item, expected_index = 9887, 990
|
||||
|
||||
# Time required to search
|
||||
start_time = time.time()
|
||||
binary_search_index = bs.search_iterative(list_with_1000_items, item) # => None
|
||||
bs_time = time.time() - start_time
|
||||
|
||||
# list.index(x) return the index in the list of the first item whose value is x.
|
||||
# It is an error if there is no such item.
|
||||
# Complexity of list.index(x) is O(n)
|
||||
start_time = time.time()
|
||||
linear_search_index = list_with_1000_items.index(item)
|
||||
ls_time = time.time() - start_time
|
||||
|
||||
self.assertEqual(expected_index, binary_search_index)
|
||||
self.assertEqual(expected_index, linear_search_index)
|
||||
self.assertTrue(bs_time < ls_time)
|
||||
|
||||
# print("--- Time required to search item at the ending ---")
|
||||
# print("--- Linear Search %f seconds ---" % (ls_time))
|
||||
# print("--- Binary Search %f seconds ---" % (bs_time))
|
||||
|
||||
def test_execution_time_for_item_at_the_beginning(self):
|
||||
item, expected_index = 55, 10
|
||||
|
||||
# Binary search - time required to search
|
||||
start_time = time.time()
|
||||
binary_search_index = bs.search_iterative(list_with_1000_items, item) # => None
|
||||
bs_time = time.time() - start_time
|
||||
|
||||
# Linear search - time required to search
|
||||
start_time = time.time()
|
||||
linear_search_index = list_with_1000_items.index(item)
|
||||
ls_time = time.time() - start_time
|
||||
|
||||
self.assertEqual(expected_index, binary_search_index)
|
||||
self.assertEqual(expected_index, linear_search_index)
|
||||
|
||||
# linear search will be faster, since the item we are looking for
|
||||
# is at the beginning of the list
|
||||
self.assertTrue(bs_time > ls_time)
|
||||
|
||||
# print("--- Time required to search item at the beginning ---")
|
||||
# print("--- Linear Search %f seconds ---" % (ls_time))
|
||||
# print("--- Binary Search %f seconds ---" % (bs_time))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user