Skip to content

Commit 37afac6

Browse files
committed
Improve simple binary search according to the standard binary search definition
1 parent c0db072 commit 37afac6

4 files changed

Lines changed: 62 additions & 25 deletions

File tree

searches/simple_binary_search.py

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,50 +11,61 @@
1111
from __future__ import annotations
1212

1313

14-
def binary_search(a_list: list[int], item: int) -> bool:
14+
def binary_search(a_list: list[int], item: int) -> int:
1515
"""
16+
Returns the leftmost index of `item` in `a_list` if found,
17+
otherwise returns -1.
18+
1619
>>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42]
1720
>>> binary_search(test_list, 3)
18-
False
21+
-1
1922
>>> binary_search(test_list, 13)
20-
True
23+
4
2124
>>> binary_search([4, 4, 5, 6, 7], 4)
22-
True
25+
0
2326
>>> binary_search([4, 4, 5, 6, 7], -10)
24-
False
27+
-1
2528
>>> binary_search([-18, 2], -18)
26-
True
29+
0
2730
>>> binary_search([5], 5)
28-
True
31+
0
2932
>>> binary_search(['a', 'c', 'd'], 'c')
30-
True
33+
1
3134
>>> binary_search(['a', 'c', 'd'], 'f')
32-
False
35+
-1
3336
>>> binary_search([], 1)
34-
False
37+
-1
3538
>>> binary_search([-.1, .1 , .8], .1)
36-
True
39+
1
3740
>>> binary_search(range(-5000, 5000, 10), 80)
38-
True
41+
508
3942
>>> binary_search(range(-5000, 5000, 10), 1255)
40-
False
43+
-1
4144
>>> binary_search(range(0, 10000, 5), 2)
42-
False
45+
-1
4346
"""
44-
if len(a_list) == 0:
45-
return False
46-
midpoint = len(a_list) // 2
47-
if a_list[midpoint] == item:
48-
return True
49-
if item < a_list[midpoint]:
50-
return binary_search(a_list[:midpoint], item)
51-
else:
52-
return binary_search(a_list[midpoint + 1 :], item)
47+
low, high = 0, len(a_list) - 1
48+
result = -1
49+
50+
while low <= high:
51+
mid = (low + high) // 2
52+
if a_list[mid] == item:
53+
result = mid
54+
high = mid - 1 # keep searching left for duplicates
55+
elif item < a_list[mid]:
56+
high = mid - 1
57+
else:
58+
low = mid + 1
59+
60+
return result
5361

5462

5563
if __name__ == "__main__":
5664
user_input = input("Enter numbers separated by comma:\n").strip()
5765
sequence = [int(item.strip()) for item in user_input.split(",")]
5866
target = int(input("Enter the number to be found in the list:\n").strip())
59-
not_str = "" if binary_search(sequence, target) else "not "
60-
print(f"{target} was {not_str}found in {sequence}")
67+
index = binary_search(sequence, target)
68+
if index != -1:
69+
print(f"{target} found at index {index} in {sequence}")
70+
else:
71+
print(f"{target} was not found in {sequence}")

test.patch

1.98 KB
Binary file not shown.

test.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
set -uo pipefail
3+
cd /app
4+
5+
MODE="${1:-new}"
6+
7+
case "$MODE" in
8+
base)
9+
pytest tests # run existing repo tests
10+
;;
11+
new)
12+
pytest tests/test_binary_search_duplicates.py
13+
;;
14+
*)
15+
echo "unknown mode: $MODE (expected base or new)" >&2
16+
exit 2
17+
;;
18+
esac
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
def test_binary_search_leftmost_duplicate():
2+
assert binary_search([1, 2, 2, 2, 3], 2) == 1
3+
4+
def test_binary_search_all_duplicates():
5+
assert binary_search([1, 1, 1, 1], 1) == 0
6+
7+
def test_binary_search_not_found():
8+
assert binary_search([1, 2, 3], 4) == -1

0 commit comments

Comments
 (0)