mirror of
https://hub.njuu.cf/TheAlgorithms/Python.git
synced 2023-10-11 13:06:12 +08:00
Interpolation search - fix endless loop bug, divide 0 bug and update description (#793)
* fix endless loop bug, divide 0 bug and update description fix an endless bug, for example, if collection = [10,30,40,45,50,66,77,93], item = 67. fix divide 0 bug, when right=left it is not OK to point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left]) update 'sorted' to 'ascending sorted' in description to avoid confusion * delete swap files * delete 'address' and add input validation
This commit is contained in:
parent
f3608acfd5
commit
b6c3fa8992
@ -11,9 +11,9 @@ except NameError:
|
|||||||
|
|
||||||
def interpolation_search(sorted_collection, item):
|
def interpolation_search(sorted_collection, item):
|
||||||
"""Pure implementation of interpolation search algorithm in Python
|
"""Pure implementation of interpolation search algorithm in Python
|
||||||
Be careful collection must be sorted, otherwise result will be
|
Be careful collection must be ascending sorted, otherwise result will be
|
||||||
unpredictable
|
unpredictable
|
||||||
:param sorted_collection: some sorted collection with comparable items
|
:param sorted_collection: some ascending sorted collection with comparable items
|
||||||
:param item: item value to search
|
:param item: item value to search
|
||||||
:return: index of found item or None if item is not found
|
:return: index of found item or None if item is not found
|
||||||
"""
|
"""
|
||||||
@ -21,6 +21,13 @@ def interpolation_search(sorted_collection, item):
|
|||||||
right = len(sorted_collection) - 1
|
right = len(sorted_collection) - 1
|
||||||
|
|
||||||
while left <= right:
|
while left <= right:
|
||||||
|
#avoid devided by 0 during interpolation
|
||||||
|
if sorted_collection[left]==sorted_collection[right]:
|
||||||
|
if sorted_collection[left]==item:
|
||||||
|
return left
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left])
|
point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left])
|
||||||
|
|
||||||
#out of range check
|
#out of range check
|
||||||
@ -31,23 +38,37 @@ def interpolation_search(sorted_collection, item):
|
|||||||
if current_item == item:
|
if current_item == item:
|
||||||
return point
|
return point
|
||||||
else:
|
else:
|
||||||
if item < current_item:
|
if point<left:
|
||||||
right = point - 1
|
right = left
|
||||||
|
left = point
|
||||||
|
elif point>right:
|
||||||
|
left = right
|
||||||
|
right = point
|
||||||
else:
|
else:
|
||||||
left = point + 1
|
if item < current_item:
|
||||||
|
right = point - 1
|
||||||
|
else:
|
||||||
|
left = point + 1
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def interpolation_search_by_recursion(sorted_collection, item, left, right):
|
def interpolation_search_by_recursion(sorted_collection, item, left, right):
|
||||||
|
|
||||||
"""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 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 sorted collection with comparable items
|
:param sorted_collection: some ascending sorted collection with comparable items
|
||||||
:param item: item value to search
|
:param item: item value to search
|
||||||
:return: index of found item or None if item is not found
|
:return: index of found item or None if item is not found
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
#avoid devided by 0 during interpolation
|
||||||
|
if sorted_collection[left]==sorted_collection[right]:
|
||||||
|
if sorted_collection[left]==item:
|
||||||
|
return left
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left])
|
point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left])
|
||||||
|
|
||||||
#out of range check
|
#out of range check
|
||||||
@ -56,41 +77,58 @@ 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 sorted_collection[point] > item:
|
elif point<left:
|
||||||
return interpolation_search_by_recursion(sorted_collection, item, left, point-1)
|
return interpolation_search_by_recursion(sorted_collection, item, point, left)
|
||||||
|
elif point>right:
|
||||||
|
return interpolation_search_by_recursion(sorted_collection, item, right, left)
|
||||||
else:
|
else:
|
||||||
return interpolation_search_by_recursion(sorted_collection, item, point+1, right)
|
if sorted_collection[point] > item:
|
||||||
|
return interpolation_search_by_recursion(sorted_collection, item, left, point-1)
|
||||||
|
else:
|
||||||
|
return interpolation_search_by_recursion(sorted_collection, item, point+1, right)
|
||||||
|
|
||||||
def __assert_sorted(collection):
|
def __assert_sorted(collection):
|
||||||
"""Check if collection is sorted, if not - raises :py:class:`ValueError`
|
"""Check if collection is ascending sorted, if not - raises :py:class:`ValueError`
|
||||||
:param collection: collection
|
:param collection: collection
|
||||||
:return: True if collection is sorted
|
:return: True if collection is ascending sorted
|
||||||
:raise: :py:class:`ValueError` if collection is not sorted
|
:raise: :py:class:`ValueError` if collection is not ascending sorted
|
||||||
Examples:
|
Examples:
|
||||||
>>> __assert_sorted([0, 1, 2, 4])
|
>>> __assert_sorted([0, 1, 2, 4])
|
||||||
True
|
True
|
||||||
>>> __assert_sorted([10, -1, 5])
|
>>> __assert_sorted([10, -1, 5])
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValueError: Collection must be sorted
|
ValueError: Collection must be ascending sorted
|
||||||
"""
|
"""
|
||||||
if collection != sorted(collection):
|
if collection != sorted(collection):
|
||||||
raise ValueError('Collection must be sorted')
|
raise ValueError('Collection must be ascending sorted')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
user_input = raw_input('Enter numbers separated by comma:\n').strip()
|
"""
|
||||||
|
user_input = raw_input('Enter numbers separated by comma:\n').strip()
|
||||||
collection = [int(item) for item in user_input.split(',')]
|
collection = [int(item) for item in user_input.split(',')]
|
||||||
try:
|
try:
|
||||||
__assert_sorted(collection)
|
__assert_sorted(collection)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
sys.exit('Sequence must be sorted to apply interpolation search')
|
sys.exit('Sequence must be ascending sorted to apply interpolation search')
|
||||||
|
|
||||||
target_input = raw_input('Enter a single number to be found in the list:\n')
|
target_input = raw_input('Enter a single number to be found in the list:\n')
|
||||||
target = int(target_input)
|
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)
|
result = interpolation_search(collection, target)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
print('{} found at positions: {}'.format(target, result))
|
print('{} found at positions: {}'.format(target, result))
|
||||||
|
@ -14,9 +14,9 @@ def _partition(data, pivot):
|
|||||||
"""
|
"""
|
||||||
less, equal, greater = [], [], []
|
less, equal, greater = [], [], []
|
||||||
for element in data:
|
for element in data:
|
||||||
if element.address < pivot.address:
|
if element < pivot:
|
||||||
less.append(element)
|
less.append(element)
|
||||||
elif element.address > pivot.address:
|
elif element > pivot:
|
||||||
greater.append(element)
|
greater.append(element)
|
||||||
else:
|
else:
|
||||||
equal.append(element)
|
equal.append(element)
|
||||||
@ -24,6 +24,11 @@ def _partition(data, pivot):
|
|||||||
|
|
||||||
def quickSelect(list, k):
|
def quickSelect(list, k):
|
||||||
#k = len(list) // 2 when trying to find the median (index that value would be when list is sorted)
|
#k = len(list) // 2 when trying to find the median (index that value would be when list is sorted)
|
||||||
|
|
||||||
|
#invalid input
|
||||||
|
if k>=len(list) or k<0:
|
||||||
|
return None
|
||||||
|
|
||||||
smaller = []
|
smaller = []
|
||||||
larger = []
|
larger = []
|
||||||
pivot = random.randint(0, len(list) - 1)
|
pivot = random.randint(0, len(list) - 1)
|
||||||
|
93
searches/test_interpolation_search.py
Normal file
93
searches/test_interpolation_search.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import unittest
|
||||||
|
from interpolation_search import interpolation_search, interpolation_search_by_recursion
|
||||||
|
|
||||||
|
class Test_interpolation_search(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
# un-sorted case
|
||||||
|
self.collection1 = [5,3,4,6,7]
|
||||||
|
self.item1 = 4
|
||||||
|
# sorted case, result exists
|
||||||
|
self.collection2 = [10,30,40,45,50,66,77,93]
|
||||||
|
self.item2 = 66
|
||||||
|
# sorted case, result doesn't exist
|
||||||
|
self.collection3 = [10,30,40,45,50,66,77,93]
|
||||||
|
self.item3 = 67
|
||||||
|
# equal elements case, result exists
|
||||||
|
self.collection4 = [10,10,10,10,10]
|
||||||
|
self.item4 = 10
|
||||||
|
# equal elements case, result doesn't exist
|
||||||
|
self.collection5 = [10,10,10,10,10]
|
||||||
|
self.item5 = 3
|
||||||
|
# 1 element case, result exists
|
||||||
|
self.collection6 = [10]
|
||||||
|
self.item6 = 10
|
||||||
|
# 1 element case, result doesn't exists
|
||||||
|
self.collection7 = [10]
|
||||||
|
self.item7 = 1
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_interpolation_search(self):
|
||||||
|
self.assertEqual(interpolation_search(self.collection1, self.item1), None)
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search(self.collection2, self.item2), self.collection2.index(self.item2))
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search(self.collection3, self.item3), None)
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search(self.collection4, self.item4), self.collection4.index(self.item4))
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search(self.collection5, self.item5), None)
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search(self.collection6, self.item6), self.collection6.index(self.item6))
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search(self.collection7, self.item7), None)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Test_interpolation_search_by_recursion(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
# un-sorted case
|
||||||
|
self.collection1 = [5,3,4,6,7]
|
||||||
|
self.item1 = 4
|
||||||
|
# sorted case, result exists
|
||||||
|
self.collection2 = [10,30,40,45,50,66,77,93]
|
||||||
|
self.item2 = 66
|
||||||
|
# sorted case, result doesn't exist
|
||||||
|
self.collection3 = [10,30,40,45,50,66,77,93]
|
||||||
|
self.item3 = 67
|
||||||
|
# equal elements case, result exists
|
||||||
|
self.collection4 = [10,10,10,10,10]
|
||||||
|
self.item4 = 10
|
||||||
|
# equal elements case, result doesn't exist
|
||||||
|
self.collection5 = [10,10,10,10,10]
|
||||||
|
self.item5 = 3
|
||||||
|
# 1 element case, result exists
|
||||||
|
self.collection6 = [10]
|
||||||
|
self.item6 = 10
|
||||||
|
# 1 element case, result doesn't exists
|
||||||
|
self.collection7 = [10]
|
||||||
|
self.item7 = 1
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_interpolation_search_by_recursion(self):
|
||||||
|
self.assertEqual(interpolation_search_by_recursion(self.collection1, self.item1, 0, len(self.collection1)-1), None)
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search_by_recursion(self.collection2, self.item2, 0, len(self.collection2)-1), self.collection2.index(self.item2))
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search_by_recursion(self.collection3, self.item3, 0, len(self.collection3)-1), None)
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search_by_recursion(self.collection4, self.item4, 0, len(self.collection4)-1), self.collection4.index(self.item4))
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search_by_recursion(self.collection5, self.item5, 0, len(self.collection5)-1), None)
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search_by_recursion(self.collection6, self.item6, 0, len(self.collection6)-1), self.collection6.index(self.item6))
|
||||||
|
|
||||||
|
self.assertEqual(interpolation_search_by_recursion(self.collection7, self.item7, 0, len(self.collection7)-1), None)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user