Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ee8fb8d

Browse files
committed
Add a Python iterative binary search algorithm example.
1 parent 097c345 commit ee8fb8d

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

‎binary_search/README.markdown‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Binary search
2+
3+
The binary search algorithm is a method to quickly find a given item in a list (called a "search space") that has already been sorted. The word "binary" in its name can be misleading because it refers to halving the search space (dividing the search space by two) at each attempt to find the thing you're looking for. You don't need to know anything about binary math to use it!
4+
5+
In order to be useful, the list or search space you're looking through must already be sorted. Some examples of things that are sorted include number lines (because `1` always comes before `2`, and so on) or alphabets (because `A` always comes before `B`, and so on). For instance, the dictionary is a *sorted* list of words; it's sorted because it's alphabetized and you are certain to find "Aardvark" well before you encounter the word "Zebra" if you simply read it from beginning to end (i.e., if you read the dictionary linearly).
6+
7+
When you perform a binary search, you start in the middle of the search space instead of at its beginning or its end. If the item you're looking for is not the item in the exact middle, you check to see if it's supposed to be listed before or after that middle item. This is why it's so important for the list to be sorted before you try to do a binary search in it. If you try to apply the binary search algorithm to a search space that is not sorted, it won't work because you won't know which half of the list to keep looking in.
8+
9+
Here's a simple visualization showing how halving the search space works. If there are eight items in the search space, and they're sorted, then you only need up to three guesses to find any item (and then one more "guess" to actually pick it out):
10+
11+
```
12+
Search space: |__1__|__2__|__3__|__4__|__5__|__6__|__7__|_*8__| "Guess a number from 1 to 8." (It's 8.)
13+
Before first guess: |_______________________________________________|
14+
After first guess: |xxxxxxxxxxxxxxxxxxxxxxx|_______________________| "If it's not four, is it bigger or smaller than four?"
15+
After second guess: |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|___________| "If it's not six, is it bigger or smaller than six?"
16+
After third guess: |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|_____| "If it's not seven, is it bigger or smaller than seven?"
17+
Fourth "guess": |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|FOUND| "It's eight!"
18+
```
19+
20+
Here's another example:
21+
22+
```
23+
Search space: |__1__|__2__|_*3__|__4__|__5__|__6__|__7__|__8__| "Guess a number from 1 to 8." (It's 3.)
24+
Before first guess: |_______________________________________________|
25+
After first guess: |_______________________|xxxxxxxxxxxxxxxxxxxxxxx| "If it's not four, is it bigger or smaller than four?"
26+
After second guess: |xxxxx|_____|_____|xxxxxxxxxxxxxxxxxxxxxxxxxxxxx| "If it's not two, is it bigger or smaller than two?"
27+
After third guess: |xxxxxxxxxxx|_____|xxxxxxxxxxxxxxxxxxxxxxxxxxxxx| "It's bigger than two but smaller than four, so..."
28+
Fourth "guess": |xxxxxxxxxxx|FOUND|xxxxxxxxxxxxxxxxxxxxxxxxxxxxx| "that means it must be three!"
29+
```
30+
31+
Notice that the search space shrinks by half after each guess. If you guess `4` but the answer is `8`, then you can safely discard `1`, `2`, and `3`, because these are even lower than `4`, which you're told is too low and is what you guessed first. Rather than guessing `5` next, find the middle of the remaining search space and guess that item (`6`). Then check if your guess is correct, or if it's too high or too low. Keep guessing in the middle of the remaining search space until there's only one possibility left. Now you can see why a *sorted* input is so important for binary search to work!
32+
33+
The important pattern to notice is that the number of possible correct answers (the "search space") is reduced by half after each guess:
34+
35+
* 8 possible answers *before* the first guess.
36+
* 4 possible answers *after* the first guess.
37+
* 2 possible answers after the second guess.
38+
* 1 possible answer after the third guess.
39+
40+
Notice that in the second example, however, we didn't even need to use a third guess, because there was only one possible answer after the second guess. Three guesses is the *slowest* it would take to find the answer in a set of eight items, not the fastest. This is still potentially much faster than a worst-case scenario if we used a *linear* search instead of a *binary* search. If we used a linear search, it would have taken us 8 guesses to guess the number 8 in the first example if we started guessing at 1, because our next guess would have been 2, then 3, and so on.
41+
42+
Binary search is also sometimes called *logarithmic search* because the search speed is calculatable by taking a logarithm of the length of the list. A logarithm is the opposite of an exponent. 2 raised to the power of 3 (that is, 2 multiplied by itself 3 times) equals eight (2<sup>3</sup> = 8). We can retrieve the exponent (the 3, which is the most guesses we'd need to search an 8-item list) by applying the logarithm function to the number 8 (the size of our search space) with a base of 2 (because we're halving the space at each guess): log<sub>2</sub>8 = 3.
43+
44+
Using logarithmic math, you can easily find out how many guesses it would take you to find a given item in an arbitrarily large search space. For instance, if you had to guess a number between 1 and 100, it would take you at most log<sub>2</sub>100 guesses if you always halved the search space at each guess (i.e., if you "used binary search").
45+
46+
## Further reading
47+
48+
1. [Khan Academy](https://www.khanacademy.org/computing/computer-science/algorithms/binary-search/a/binary-search)
49+
1. [RosettaCode](http://rosettacode.org/wiki/Binary_search)
50+
1. [Working with Exponents and Logarithms](https://www.mathsisfun.com/algebra/exponents-logarithms.html)
51+
1. [Binary Search - Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm)
52+
1. [Logarithm - Wikipedia](https://en.wikipedia.org/wiki/Logarithm)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""
2+
Binary search algorithm, iterative implementation.
3+
4+
A binary search is a method to quickly find a given item in a sorted
5+
list. It's important the input list is sorted, or the binary search
6+
algorithm won't be useful at all. Sorted lists are things like
7+
alphabets (because "A" is always before "B," and so on), or number
8+
lines (because "1" is always before "2," and so on).
9+
"""
10+
11+
def binary_search_iterative(stuff, item):
12+
"""
13+
Return the index of ``item`` in ``list`` using binary search.
14+
15+
Args:
16+
stuff (list): A Python list that has already been sorted.
17+
item: The value of the item to search for (not its index).
18+
19+
Returns:
20+
The index of ``item`` or ``None`` if ``item`` is not found.
21+
22+
>>> binary_search_iterative([1, 2, 3, 4, 5, 6, 7, 8], 8)
23+
Guess number 1 is 4
24+
Guess number 2 is 6
25+
Guess number 3 is 7
26+
Guess number 4 is 8
27+
7
28+
29+
Notice that the final return value is 7, not 8, because Python
30+
list indexes start counting from position number 0, not number 1.
31+
"""
32+
33+
# We will be keeping track of a range of positions instead of
34+
# looking at position 0 and then looking at position 1, so we need
35+
# to keep track of the lowest and highest positions of that range,
36+
# not just the current spot in the list of stuff we're looking at.
37+
38+
# The low position always starts at 0.
39+
low = 0
40+
41+
# The high position is however much stuff we're looking through.
42+
high = len(stuff) - 1
43+
44+
# We also keep track of how many guesses we're making to find it.
45+
guess_number = 0 # (This is just for our own edification.)
46+
47+
# Eventually, `low` and `high` will converge, because we'll keep
48+
# shrinking the range by half (hence, "*binary* search") until we
49+
# find the item we're looking for. After each guess, we'll loop
50+
# (that is, we'll iterate) over the same list in a narrower range.
51+
while low <= high:
52+
# The middle spot of our range is always going to be the
53+
# current value of low plus high, divided by two.
54+
mid = (low + high) / 2
55+
56+
guess = stuff[mid] # That middle spot will be our next guess,
57+
guess_number = guess_number + 1 # so let's count our guesses.
58+
59+
# How many guesses have we made so far?
60+
print("Guess number " + str(guess_number) + " is " + str(guess))
61+
62+
if guess == item: # If this is the correct guess,
63+
return mid # then we've found the item! Yay! :)
64+
65+
# If we haven't found the item yet, then our guess was either
66+
# too low or too high. Thankfully, our list of stuff is sorted
67+
# so, if the guess was too high
68+
if guess > item:
69+
# then we know the item we're looking for is in the lower
70+
# half of our range. This means we can set the high end of
71+
# our range to the middle position of our last guess. We
72+
# also subtract 1 since we know our last guess was wrong.
73+
high = mid - 1
74+
else:
75+
# On the other hand, if the guess was too low, then we
76+
# know the item is in the higher half of our range, so we
77+
# set the low end of our range to the middle position of
78+
# our last guess, instead.
79+
low = mid + 1
80+
81+
# If we still haven't found the item, then it's not in the list!
82+
return None
83+
84+
if __name__ == "__main__":
85+
num = int(raw_input('Enter a number between 1 and 100: '))
86+
binary_search_iterative(range(1, 101), num)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /