Skip to content

Commit 0d65561

Browse files
committed
Add refined ternary search (iterative & recursive) with enhanced tests
1 parent d1a9486 commit 0d65561

File tree

1 file changed

+80
-124
lines changed

1 file changed

+80
-124
lines changed

searches/ternary_search.py

Lines changed: 80 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,129 @@
11
"""
2-
This is a type of divide and conquer algorithm which divides the search space into
3-
3 parts and finds the target value based on the property of the array or list
4-
(usually monotonic property).
2+
Ternary Search Algorithm - Iterative and Recursive Implementations
3+
4+
Divides the search range into 3 parts instead of 2, and recursively or iteratively
5+
eliminates 2/3 of the array in each step.
56
67
Time Complexity : O(log3 N)
7-
Space Complexity : O(1)
8+
Space Complexity : O(1) for iterative, O(log3 N) for recursive
89
"""
910

1011
from __future__ import annotations
1112

12-
# This is the precision for this function which can be altered.
13-
# It is recommended for users to keep this number greater than or equal to 10.
14-
precision = 10
15-
16-
17-
# This is the linear search that will occur after the search space has become smaller.
18-
19-
20-
def lin_search(left: int, right: int, array: list[int], target: int) -> int:
21-
"""Perform linear search in list. Returns -1 if element is not found.
22-
23-
Parameters
24-
----------
25-
left : int
26-
left index bound.
27-
right : int
28-
right index bound.
29-
array : List[int]
30-
List of elements to be searched on
31-
target : int
32-
Element that is searched
3313

34-
Returns
35-
-------
36-
int
37-
index of element that is looked for.
14+
def linear_search(start: int, end: int, array: list[int | float | str], target) -> int:
15+
"""
16+
Fallback linear search when search window is small.
3817
39-
Examples
40-
--------
41-
>>> lin_search(0, 4, [4, 5, 6, 7], 7)
42-
3
43-
>>> lin_search(0, 3, [4, 5, 6, 7], 7)
44-
-1
45-
>>> lin_search(0, 2, [-18, 2], -18)
46-
0
47-
>>> lin_search(0, 1, [5], 5)
48-
0
49-
>>> lin_search(0, 3, ['a', 'c', 'd'], 'c')
50-
1
51-
>>> lin_search(0, 3, [.1, .4 , -.1], .1)
52-
0
53-
>>> lin_search(0, 3, [.1, .4 , -.1], -.1)
18+
>>> linear_search(0, 4, [1, 2, 3, 4], 3)
5419
2
20+
>>> linear_search(0, 2, ["a", "b", "c"], "b")
21+
1
22+
>>> linear_search(0, 3, [0.1, 0.2, 0.3], 0.4)
23+
-1
5524
"""
56-
for i in range(left, right):
25+
for i in range(start, end):
5726
if array[i] == target:
5827
return i
5928
return -1
6029

6130

62-
def ite_ternary_search(array: list[int], target: int) -> int:
63-
"""Iterative method of the ternary search algorithm.
64-
>>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42]
65-
>>> ite_ternary_search(test_list, 3)
66-
-1
67-
>>> ite_ternary_search(test_list, 13)
68-
4
69-
>>> ite_ternary_search([4, 5, 6, 7], 4)
70-
0
71-
>>> ite_ternary_search([4, 5, 6, 7], -10)
72-
-1
73-
>>> ite_ternary_search([-18, 2], -18)
74-
0
75-
>>> ite_ternary_search([5], 5)
76-
0
77-
>>> ite_ternary_search(['a', 'c', 'd'], 'c')
78-
1
79-
>>> ite_ternary_search(['a', 'c', 'd'], 'f')
31+
def ternary_search_iterative(array: list[int | float | str], target) -> int:
32+
"""
33+
Iterative ternary search algorithm for sorted arrays.
34+
35+
>>> ternary_search_iterative([1, 3, 5, 7, 9], 7)
36+
3
37+
>>> ternary_search_iterative([1, 3, 5, 7, 9], 2)
8038
-1
81-
>>> ite_ternary_search([], 1)
39+
>>> ternary_search_iterative([], 4)
8240
-1
83-
>>> ite_ternary_search([.1, .4 , -.1], .1)
84-
0
8541
"""
86-
8742
left = 0
88-
right = len(array)
43+
right = len(array) - 1
44+
threshold = 10
45+
8946
while left <= right:
90-
if right - left < precision:
91-
return lin_search(left, right, array, target)
47+
if right - left < threshold:
48+
return linear_search(left, right + 1, array, target)
9249

93-
one_third = (left + right) // 3 + 1
94-
two_third = 2 * (left + right) // 3 + 1
50+
one_third = left + (right - left) // 3
51+
two_third = right - (right - left) // 3
9552

9653
if array[one_third] == target:
9754
return one_third
9855
elif array[two_third] == target:
9956
return two_third
100-
10157
elif target < array[one_third]:
10258
right = one_third - 1
103-
elif array[two_third] < target:
59+
elif target > array[two_third]:
10460
left = two_third + 1
105-
10661
else:
10762
left = one_third + 1
10863
right = two_third - 1
64+
10965
return -1
11066

11167

112-
def rec_ternary_search(left: int, right: int, array: list[int], target: int) -> int:
113-
"""Recursive method of the ternary search algorithm.
68+
def ternary_search_recursive(
69+
array: list[int | float | str],
70+
target,
71+
left: int = 0,
72+
right: int | None = None,
73+
threshold: int = 10,
74+
) -> int:
75+
"""
76+
Recursive ternary search algorithm.
11477
115-
>>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42]
116-
>>> rec_ternary_search(0, len(test_list), test_list, 3)
117-
-1
118-
>>> rec_ternary_search(4, len(test_list), test_list, 42)
119-
8
120-
>>> rec_ternary_search(0, 2, [4, 5, 6, 7], 4)
121-
0
122-
>>> rec_ternary_search(0, 3, [4, 5, 6, 7], -10)
123-
-1
124-
>>> rec_ternary_search(0, 1, [-18, 2], -18)
125-
0
126-
>>> rec_ternary_search(0, 1, [5], 5)
127-
0
128-
>>> rec_ternary_search(0, 2, ['a', 'c', 'd'], 'c')
129-
1
130-
>>> rec_ternary_search(0, 2, ['a', 'c', 'd'], 'f')
131-
-1
132-
>>> rec_ternary_search(0, 0, [], 1)
78+
>>> ternary_search_recursive([1, 3, 5, 7, 9], 7)
79+
3
80+
>>> ternary_search_recursive(["a", "b", "c", "d"], "c")
81+
2
82+
>>> ternary_search_recursive([], 1)
13383
-1
134-
>>> rec_ternary_search(0, 3, [.1, .4 , -.1], .1)
135-
0
13684
"""
137-
if left < right:
138-
if right - left < precision:
139-
return lin_search(left, right, array, target)
140-
one_third = (left + right) // 3 + 1
141-
two_third = 2 * (left + right) // 3 + 1
85+
if right is None:
86+
right = len(array) - 1
14287

143-
if array[one_third] == target:
144-
return one_third
145-
elif array[two_third] == target:
146-
return two_third
88+
if left > right:
89+
return -1
14790

148-
elif target < array[one_third]:
149-
return rec_ternary_search(left, one_third - 1, array, target)
150-
elif array[two_third] < target:
151-
return rec_ternary_search(two_third + 1, right, array, target)
152-
else:
153-
return rec_ternary_search(one_third + 1, two_third - 1, array, target)
91+
if right - left < threshold:
92+
return linear_search(left, right + 1, array, target)
93+
94+
one_third = left + (right - left) // 3
95+
two_third = right - (right - left) // 3
96+
97+
if array[one_third] == target:
98+
return one_third
99+
elif array[two_third] == target:
100+
return two_third
101+
elif target < array[one_third]:
102+
return ternary_search_recursive(array, target, left, one_third - 1, threshold)
103+
elif target > array[two_third]:
104+
return ternary_search_recursive(array, target, two_third + 1, right, threshold)
154105
else:
155-
return -1
106+
return ternary_search_recursive(array, target, one_third + 1, two_third - 1, threshold)
156107

157108

158109
if __name__ == "__main__":
159110
import doctest
160111

161112
doctest.testmod()
162113

163-
user_input = input("Enter numbers separated by comma:\n").strip()
164-
collection = [int(item.strip()) for item in user_input.split(",")]
165-
assert collection == sorted(collection), f"List must be ordered.\n{collection}."
166-
target = int(input("Enter the number to be found in the list:\n").strip())
167-
result1 = ite_ternary_search(collection, target)
168-
result2 = rec_ternary_search(0, len(collection) - 1, collection, target)
169-
if result2 != -1:
170-
print(f"Iterative search: {target} found at positions: {result1}")
171-
print(f"Recursive search: {target} found at positions: {result2}")
172-
else:
173-
print("Not found")
114+
try:
115+
raw_input = input("\nEnter sorted numbers separated by commas: ").strip()
116+
collection = [int(x) for x in raw_input.split(",")]
117+
assert collection == sorted(collection), "Input must be sorted in ascending order."
118+
target = int(input("Enter the number to search: "))
119+
120+
result_iter = ternary_search_iterative(collection, target)
121+
result_rec = ternary_search_recursive(collection, target)
122+
123+
if result_iter != -1:
124+
print(f"Iterative Search: Found {target} at index {result_iter}")
125+
print(f"Recursive Search: Found {target} at index {result_rec}")
126+
else:
127+
print(f"{target} not found in the list.")
128+
except Exception as e:
129+
print(f"Error: {e}")

0 commit comments

Comments
 (0)