Skip to content

Add type hints and tests. #2461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Nov 14, 2020
9 changes: 9 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@
* [Heaps Algorithm](https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/heaps_algorithm.py)
* [Heaps Algorithm Iterative](https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/heaps_algorithm_iterative.py)
* [Inversions](https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/inversions.py)
* [Kth Order Statistic](https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/kth_order_statistic.py)
* [Max Subarray Sum](https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/max_subarray_sum.py)
* [Mergesort](https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/mergesort.py)
* [Power](https://github.com/TheAlgorithms/Python/blob/master/divide_and_conquer/power.py)
Expand Down Expand Up @@ -389,6 +390,7 @@
* [Chudnovsky Algorithm](https://github.com/TheAlgorithms/Python/blob/master/maths/chudnovsky_algorithm.py)
* [Collatz Sequence](https://github.com/TheAlgorithms/Python/blob/master/maths/collatz_sequence.py)
* [Combinations](https://github.com/TheAlgorithms/Python/blob/master/maths/combinations.py)
* [Decimal Isolate](https://github.com/TheAlgorithms/Python/blob/master/maths/decimal_isolate.py)
* [Entropy](https://github.com/TheAlgorithms/Python/blob/master/maths/entropy.py)
* [Eulers Totient](https://github.com/TheAlgorithms/Python/blob/master/maths/eulers_totient.py)
* [Explicit Euler](https://github.com/TheAlgorithms/Python/blob/master/maths/explicit_euler.py)
Expand Down Expand Up @@ -680,6 +682,8 @@
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_062/sol1.py)
* Problem 063
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_063/sol1.py)
* Problem 064
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_064/sol1.py)
* Problem 065
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_065/sol1.py)
* Problem 067
Expand All @@ -693,6 +697,7 @@
* [Sol2](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_072/sol2.py)
* Problem 074
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_074/sol1.py)
* [Sol2](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_074/sol2.py)
* Problem 075
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_075/sol1.py)
* Problem 076
Expand Down Expand Up @@ -725,12 +730,16 @@
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_174/sol1.py)
* Problem 191
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_191/sol1.py)
* Problem 203
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_203/sol1.py)
* Problem 206
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_206/sol1.py)
* Problem 207
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_207/sol1.py)
* Problem 234
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_234/sol1.py)
* Problem 301
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_301/sol1.py)
* Problem 551
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_551/sol1.py)

Expand Down
199 changes: 132 additions & 67 deletions searches/ternary_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
Time Complexity : O(log3 N)
Space Complexity : O(1)
"""
import sys
from typing import List

# This is the precision for this function which can be altered.
Expand All @@ -15,90 +14,156 @@


# This is the linear search that will occur after the search space has become smaller.
def lin_search(left: int, right: int, A: List[int], target: int):
for i in range(left, right + 1):
if A[i] == target:
return i


# This is the iterative method of the ternary search algorithm.
def ite_ternary_search(A: List[int], target: int):
left = 0
right = len(A) - 1
while True:
if left < right:
def lin_search(left: int, right: int, array: List[int], target: int) -> int:
"""Perform linear search in list. Returns -1 if element is not found.

Parameters
----------
left : int
left index bound.
right : int
right index bound.
array : List[int]
List of elements to be searched on
target : int
Element that is searched

Returns
-------
int
index of element that is looked for.

Examples
--------
>>> lin_search(0, 4, [4, 5, 6, 7], 7)
3
>>> lin_search(0, 3, [4, 5, 6, 7], 7)
-1
>>> lin_search(0, 2, [-18, 2], -18)
0
>>> lin_search(0, 1, [5], 5)
0
>>> lin_search(0, 3, ['a', 'c', 'd'], 'c')
1
>>> lin_search(0, 3, [.1, .4 , -.1], .1)
0
>>> lin_search(0, 3, [.1, .4 , -.1], -.1)
2
"""
for i in range(left, right):
if array[i] == target:
return i
return -1


def ite_ternary_search(array: List[int], target: int) -> int:
"""Iterative method of the ternary search algorithm.
>>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42]
>>> ite_ternary_search(test_list, 3)
-1
>>> ite_ternary_search(test_list, 13)
4
>>> ite_ternary_search([4, 5, 6, 7], 4)
0
>>> ite_ternary_search([4, 5, 6, 7], -10)
-1
>>> ite_ternary_search([-18, 2], -18)
0
>>> ite_ternary_search([5], 5)
0
>>> ite_ternary_search(['a', 'c', 'd'], 'c')
1
>>> ite_ternary_search(['a', 'c', 'd'], 'f')
-1
>>> ite_ternary_search([], 1)
-1
>>> ite_ternary_search([.1, .4 , -.1], .1)
0
"""

if right - left < precision:
return lin_search(left, right, A, target)
left = 0
right = len(array)
while left <= right:
if right - left < precision:
return lin_search(left, right, array, target)

oneThird = (left + right) / 3 + 1
twoThird = 2 * (left + right) / 3 + 1
one_third = (left + right) / 3 + 1
two_third = 2 * (left + right) / 3 + 1

if A[oneThird] == target:
return oneThird
elif A[twoThird] == target:
return twoThird
if array[one_third] == target:
return one_third
elif array[two_third] == target:
return two_third

elif target < A[oneThird]:
right = oneThird - 1
elif A[twoThird] < target:
left = twoThird + 1
elif target < array[one_third]:
right = one_third - 1
elif array[two_third] < target:
left = two_third + 1

else:
left = oneThird + 1
right = twoThird - 1
else:
return None


# This is the recursive method of the ternary search algorithm.
def rec_ternary_search(left: int, right: int, A: List[int], target: int):
left = one_third + 1
right = two_third - 1
else:
return -1


def rec_ternary_search(left: int, right: int, array: List[int], target: int) -> int:
"""Recursive method of the ternary search algorithm.

>>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42]
>>> rec_ternary_search(0, len(test_list), test_list, 3)
-1
>>> rec_ternary_search(4, len(test_list), test_list, 42)
8
>>> rec_ternary_search(0, 2, [4, 5, 6, 7], 4)
0
>>> rec_ternary_search(0, 3, [4, 5, 6, 7], -10)
-1
>>> rec_ternary_search(0, 1, [-18, 2], -18)
0
>>> rec_ternary_search(0, 1, [5], 5)
0
>>> rec_ternary_search(0, 2, ['a', 'c', 'd'], 'c')
1
>>> rec_ternary_search(0, 2, ['a', 'c', 'd'], 'f')
-1
>>> rec_ternary_search(0, 0, [], 1)
-1
>>> rec_ternary_search(0, 3, [.1, .4 , -.1], .1)
0
"""
if left < right:

if right - left < precision:
return lin_search(left, right, A, target)

oneThird = (left + right) / 3 + 1
twoThird = 2 * (left + right) / 3 + 1

if A[oneThird] == target:
return oneThird
elif A[twoThird] == target:
return twoThird

elif target < A[oneThird]:
return rec_ternary_search(left, oneThird - 1, A, target)
elif A[twoThird] < target:
return rec_ternary_search(twoThird + 1, right, A, target)

return lin_search(left, right, array, target)
one_third = (left + right) / 3 + 1
two_third = 2 * (left + right) / 3 + 1

if array[one_third] == target:
return one_third
elif array[two_third] == target:
return two_third

elif target < array[one_third]:
return rec_ternary_search(left, one_third - 1, array, target)
elif array[two_third] < target:
return rec_ternary_search(two_third + 1, right, array, target)
else:
return rec_ternary_search(oneThird + 1, twoThird - 1, A, target)
return rec_ternary_search(one_third + 1, two_third - 1, array, target)
else:
return None


# This function is to check if the array is sorted.
def __assert_sorted(collection: List[int]) -> bool:
if collection != sorted(collection):
raise ValueError("Collection must be sorted")
return True
return -1


if __name__ == "__main__":
user_input = input("Enter numbers separated by coma:\n").strip()
collection = [int(item) for item in user_input.split(",")]

try:
__assert_sorted(collection)
except ValueError:
sys.exit("Sequence must be sorted to apply the ternary search")

target_input = input("Enter a single number to be found in the list:\n")
target = int(target_input)
user_input = input("Enter numbers separated by comma:\n").strip()
collection = [int(item.strip()) for item in user_input.split(",")]
assert collection == sorted(collection), f"List must be ordered.\n{collection}."
target = int(input("Enter the number to be found in the list:\n").strip())
result1 = ite_ternary_search(collection, target)
result2 = rec_ternary_search(0, len(collection) - 1, collection, target)

if result2 is not None:
if result2 != -1:
print(f"Iterative search: {target} found at positions: {result1}")
print(f"Recursive search: {target} found at positions: {result2}")
Comment on lines 167 to 168
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this provide the right answer if the user inputs an out-of-order list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not, I think it is better to return to the assert_sorted logic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK but let's do it inline. We don't need a separate function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess my error could be avoided by testing that part of the code, however the use of inputs make it hard to test. Do you know any way that the main could be tested ?

Copy link
Member

@cclauss cclauss Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

def perform_searches(collection: List[int], target: int) -> None:
    # put lines 159, 160, and 162-168 under this function and
    # then you can test `perform_searches()` all day long.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I guess thats the same than testing each one of the two searches functions.
I meant something to try to test different user inputs via the input function, not when the collection is already defined.

else:
Expand Down