Skip to content

Commit 1c85a5b

Browse files
fix(searches): correct ternary search pivots and exclusive bounds
1 parent f5988cc commit 1c85a5b

1 file changed

Lines changed: 29 additions & 12 deletions

File tree

searches/ternary_search.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def lin_search(left: int, right: int, array: list[int], target: int) -> int:
2323
Parameters
2424
----------
2525
left : int
26-
left index bound.
26+
left index bound (inclusive).
2727
right : int
28-
right index bound.
28+
right index bound (exclusive).
2929
array : List[int]
3030
List of elements to be searched on
3131
target : int
@@ -82,30 +82,38 @@ def ite_ternary_search(array: list[int], target: int) -> int:
8282
-1
8383
>>> ite_ternary_search([.1, .4 , -.1], .1)
8484
0
85+
>>> large_list = list(range(100))
86+
>>> all(ite_ternary_search(large_list, n) == n for n in large_list)
87+
True
88+
>>> ite_ternary_search(large_list, 100)
89+
-1
8590
"""
8691

8792
left = 0
8893
right = len(array)
89-
while left <= right:
94+
while left < right:
9095
if right - left < precision:
9196
return lin_search(left, right, array, target)
9297

93-
one_third = (left + right) // 3 + 1
94-
two_third = 2 * (left + right) // 3 + 1
98+
# The search space is array[left:right], so both pivots have to stay
99+
# inside that half-open range.
100+
third = (right - left) // 3
101+
one_third = left + third
102+
two_third = left + 2 * third
95103

96104
if array[one_third] == target:
97105
return one_third
98106
elif array[two_third] == target:
99107
return two_third
100108

101109
elif target < array[one_third]:
102-
right = one_third - 1
110+
right = one_third
103111
elif array[two_third] < target:
104112
left = two_third + 1
105113

106114
else:
107115
left = one_third + 1
108-
right = two_third - 1
116+
right = two_third
109117
return -1
110118

111119

@@ -133,24 +141,33 @@ def rec_ternary_search(left: int, right: int, array: list[int], target: int) ->
133141
-1
134142
>>> rec_ternary_search(0, 3, [.1, .4 , -.1], .1)
135143
0
144+
>>> large_list = list(range(100))
145+
>>> all(rec_ternary_search(0, 100, large_list, n) == n for n in large_list)
146+
True
147+
>>> rec_ternary_search(0, 100, large_list, 100)
148+
-1
136149
"""
137150
if left < right:
138151
if right - left < precision:
139152
return lin_search(left, right, array, target)
140-
one_third = (left + right) // 3 + 1
141-
two_third = 2 * (left + right) // 3 + 1
153+
154+
# The search space is array[left:right], so both pivots have to stay
155+
# inside that half-open range.
156+
third = (right - left) // 3
157+
one_third = left + third
158+
two_third = left + 2 * third
142159

143160
if array[one_third] == target:
144161
return one_third
145162
elif array[two_third] == target:
146163
return two_third
147164

148165
elif target < array[one_third]:
149-
return rec_ternary_search(left, one_third - 1, array, target)
166+
return rec_ternary_search(left, one_third, array, target)
150167
elif array[two_third] < target:
151168
return rec_ternary_search(two_third + 1, right, array, target)
152169
else:
153-
return rec_ternary_search(one_third + 1, two_third - 1, array, target)
170+
return rec_ternary_search(one_third + 1, two_third, array, target)
154171
else:
155172
return -1
156173

@@ -165,7 +182,7 @@ def rec_ternary_search(left: int, right: int, array: list[int], target: int) ->
165182
assert collection == sorted(collection), f"List must be ordered.\n{collection}."
166183
target = int(input("Enter the number to be found in the list:\n").strip())
167184
result1 = ite_ternary_search(collection, target)
168-
result2 = rec_ternary_search(0, len(collection) - 1, collection, target)
185+
result2 = rec_ternary_search(0, len(collection), collection, target)
169186
if result2 != -1:
170187
print(f"Iterative search: {target} found at positions: {result1}")
171188
print(f"Recursive search: {target} found at positions: {result2}")

0 commit comments

Comments
 (0)