Add doctests to interpolation_search.py (#11492)

* Add doctests to interpolation_search.py

* update docs

* update tests

* update tests 2

* clean code
This commit is contained in:
Ihor Pryyma 2024-07-25 18:56:31 +03:00 committed by GitHub
parent d9ded0727a
commit 146800307c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -3,13 +3,41 @@ This is pure Python implementation of interpolation search algorithm
""" """
def interpolation_search(sorted_collection, item): def interpolation_search(sorted_collection: list[int], item: int) -> int | None:
"""Pure implementation of interpolation search algorithm in Python """
Be careful collection must be ascending sorted, otherwise result will be Searches for an item in a sorted collection by interpolation search algorithm.
unpredictable
:param sorted_collection: some ascending sorted collection with comparable items Args:
:param item: item value to search sorted_collection: sorted list of integers
:return: index of found item or None if item is not found item: item value to search
Returns:
int: The index of the found item, or None if the item is not found.
Examples:
>>> interpolation_search([1, 2, 3, 4, 5], 2)
1
>>> interpolation_search([1, 2, 3, 4, 5], 4)
3
>>> interpolation_search([1, 2, 3, 4, 5], 6) is None
True
>>> interpolation_search([], 1) is None
True
>>> interpolation_search([100], 100)
0
>>> interpolation_search([1, 2, 3, 4, 5], 0) is None
True
>>> interpolation_search([1, 2, 3, 4, 5], 7) is None
True
>>> interpolation_search([1, 2, 3, 4, 5], 2)
1
>>> interpolation_search([1, 2, 3, 4, 5], 0) is None
True
>>> interpolation_search([1, 2, 3, 4, 5], 7) is None
True
>>> interpolation_search([1, 2, 3, 4, 5], 2)
1
>>> interpolation_search([5, 5, 5, 5, 5], 3) is None
True
""" """
left = 0 left = 0
right = len(sorted_collection) - 1 right = len(sorted_collection) - 1
@ -19,7 +47,6 @@ def interpolation_search(sorted_collection, item):
if sorted_collection[left] == sorted_collection[right]: if sorted_collection[left] == sorted_collection[right]:
if sorted_collection[left] == item: if sorted_collection[left] == item:
return left return left
else:
return None return None
point = left + ((item - sorted_collection[left]) * (right - left)) // ( point = left + ((item - sorted_collection[left]) * (right - left)) // (
@ -33,7 +60,7 @@ def interpolation_search(sorted_collection, item):
current_item = sorted_collection[point] current_item = sorted_collection[point]
if current_item == item: if current_item == item:
return point return point
elif point < left: if point < left:
right = left right = left
left = point left = point
elif point > right: elif point > right:
@ -46,21 +73,41 @@ def interpolation_search(sorted_collection, item):
return None return None
def interpolation_search_by_recursion(sorted_collection, item, left, right): def interpolation_search_by_recursion(
sorted_collection: list[int], item: int, left: int = 0, right: int | None = None
) -> int | None:
"""Pure implementation of interpolation search algorithm in Python by recursion """Pure implementation of interpolation search algorithm in Python by recursion
Be careful collection must be ascending sorted, otherwise result will be Be careful collection must be ascending sorted, otherwise result will be
unpredictable unpredictable
First recursion should be started with left=0 and right=(len(sorted_collection)-1) First recursion should be started with left=0 and right=(len(sorted_collection)-1)
:param sorted_collection: some ascending sorted collection with comparable items
:param item: item value to search
:return: index of found item or None if item is not found
"""
Args:
sorted_collection: some sorted collection with comparable items
item: item value to search
left: left index in collection
right: right index in collection
Returns:
index of item in collection or None if item is not present
Examples:
>>> interpolation_search_by_recursion([0, 5, 7, 10, 15], 0)
0
>>> interpolation_search_by_recursion([0, 5, 7, 10, 15], 15)
4
>>> interpolation_search_by_recursion([0, 5, 7, 10, 15], 5)
1
>>> interpolation_search_by_recursion([0, 5, 7, 10, 15], 100) is None
True
>>> interpolation_search_by_recursion([5, 5, 5, 5, 5], 3) is None
True
"""
if right is None:
right = len(sorted_collection) - 1
# avoid divided by 0 during interpolation # avoid divided by 0 during interpolation
if sorted_collection[left] == sorted_collection[right]: if sorted_collection[left] == sorted_collection[right]:
if sorted_collection[left] == item: if sorted_collection[left] == item:
return left return left
else:
return None return None
point = left + ((item - sorted_collection[left]) * (right - left)) // ( point = left + ((item - sorted_collection[left]) * (right - left)) // (
@ -73,64 +120,18 @@ def interpolation_search_by_recursion(sorted_collection, item, left, right):
if sorted_collection[point] == item: if sorted_collection[point] == item:
return point return point
elif point < left: if point < left:
return interpolation_search_by_recursion(sorted_collection, item, point, left) return interpolation_search_by_recursion(sorted_collection, item, point, left)
elif point > right: if point > right:
return interpolation_search_by_recursion(sorted_collection, item, right, left) return interpolation_search_by_recursion(sorted_collection, item, right, left)
elif sorted_collection[point] > item: if sorted_collection[point] > item:
return interpolation_search_by_recursion( return interpolation_search_by_recursion(
sorted_collection, item, left, point - 1 sorted_collection, item, left, point - 1
) )
else: return interpolation_search_by_recursion(sorted_collection, item, point + 1, right)
return interpolation_search_by_recursion(
sorted_collection, item, point + 1, right
)
def __assert_sorted(collection):
"""Check if collection is ascending sorted, if not - raises :py:class:`ValueError`
:param collection: collection
:return: True if collection is ascending sorted
:raise: :py:class:`ValueError` if collection is not ascending sorted
Examples:
>>> __assert_sorted([0, 1, 2, 4])
True
>>> __assert_sorted([10, -1, 5])
Traceback (most recent call last):
...
ValueError: Collection must be ascending sorted
"""
if collection != sorted(collection):
raise ValueError("Collection must be ascending sorted")
return True
if __name__ == "__main__": if __name__ == "__main__":
import sys import doctest
""" doctest.testmod()
user_input = input('Enter numbers separated by comma:\n').strip()
collection = [int(item) for item in user_input.split(',')]
try:
__assert_sorted(collection)
except ValueError:
sys.exit('Sequence must be ascending sorted to apply interpolation search')
target_input = input('Enter a single number to be found in the list:\n')
target = int(target_input)
"""
debug = 0
if debug == 1:
collection = [10, 30, 40, 45, 50, 66, 77, 93]
try:
__assert_sorted(collection)
except ValueError:
sys.exit("Sequence must be ascending sorted to apply interpolation search")
target = 67
result = interpolation_search(collection, target)
if result is not None:
print(f"{target} found at positions: {result}")
else:
print("Not found")