-
-
Notifications
You must be signed in to change notification settings - Fork 45.9k
/
ternary_search.py
173 lines (147 loc) · 4.86 KB
/
ternary_search.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
"""
This is a type of divide and conquer algorithm which divides the search space into
3 parts and finds the target value based on the property of the array or list
(usually monotonic property).
Time Complexity : O(log3 N)
Space Complexity : O(1)
"""
from __future__ import annotations
# This is the precision for this function which can be altered.
# It is recommended for users to keep this number greater than or equal to 10.
precision = 10
# This is the linear search that will occur after the search space has become smaller.
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
"""
left = 0
right = len(array)
while left <= right:
if right - left < precision:
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]:
right = one_third - 1
elif array[two_third] < target:
left = two_third + 1
else:
left = one_third + 1
right = two_third - 1
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, 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(one_third + 1, two_third - 1, array, target)
else:
return -1
if __name__ == "__main__":
import doctest
doctest.testmod()
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 != -1:
print(f"Iterative search: {target} found at positions: {result1}")
print(f"Recursive search: {target} found at positions: {result2}")
else:
print("Not found")