python: unit tests for binary search
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -40,3 +40,5 @@ highlights/package-lock.json
|
|||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
/.env
|
/.env
|
||||||
atlassian-ide-plugin.xml
|
atlassian-ide-plugin.xml
|
||||||
|
__pycache__
|
||||||
|
.vscode
|
||||||
@@ -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