A while ago I wrote an explanation and implementation of the binary search algorithm in Python, but since I’ve been working a lot with JavaScript lately, I thought it would be fun to rewrite the algorithm using that language.
What is binary search?
Binary search is a search algorithm. As such, its job is to look through a sorted array of items to find a specific item. The algorithm should tell us where the item is in the array if the item is found, or that the item couldn’t be found if it isn’t in the array.
How does binary search work?
Let’s consider an example for a moment. Say you want to find your name in an alphabetized list of names. Now you could look through every name starting with the last names that begin with A, and if your last name begins with A, that is exactly where you’d start. But suppose your name begins with M instead. You’re more likely to begin your search nearer to the middle of the alphabet if that’s the case.
This approach is similar to what binary search does, in a formalized way.
First the algorithm sets an upper and lower bound to use in its search process — at the beginning of the search, these are just 0 (the beginning of the array) and whatever the length of the array is minus 1 (since arrays are zero indexed).
At each point in the search process, the algorithm divides the array to be searched through at the middle of the array.
If the item at the middle of the array matches the item being searched for, the algorithm returns the index of that item. But if not, it needs to keep searching. If the middle item is greater than the value of the item being searched for, a new upper bound is assigned, which is the middle minus 1. Similarly, if the middle item is less than the value of the item being searched for, a new lower bound is assigned, which is middle plus 1.
This search process continues, continually dividing up the array into smaller and smaller pieces, until either the item at the middle of the array matches the item being searched for, or the array being searched through runs out, in which case the algorithm can return
null
.
How can we write binary search in JavaScript?
We get two inputs for binary search: a sorted array of items to search through (called list
in the code example below) and an item that we are searching for (called, you guess it — item
!).
I set my lower and upper bounds using the variable names low
and high
respectively.
We want a way to tell our code to stop, or it will keep searching forever, so we will use a while
block based on the condition “while low is less than high.” This works because each time we don’t find the item, we either increase low
or decrease high
. If high
gets lower than low
or low
gets higher than high
it doesn’t make sense to keep searching, since at that point we will have run out of elements to look through.
Each time through the while
loop we are going to set a new med
(middle value), which is just the sum of low
and high
divided by 2.
Then it’s a matter of writing out our search logic, which I do via four if
conditions. If we find that the list
item at the middle is equal to our item
, we are done and can return med
, which is the index of that item. If not, we either decrease high
or increase low
to continue through our list, depending on whether the item at the middle is greater than or less than the item
we are searching for.
Finally, if we get through all those conditions and the item
is still not found, we return null
.
const binarySearch = (list, item) => {
let low = 0;
let high = list.length - 1;
while (low <= high) {
let med = Math.floor((low + high) / 2);
if (list[med] === item ) {
return med;
} else if (list[med] > item) {
high = med - 1;
} else if (list[med] < item) {
low = med + 1;
} else {
return null;
}
}
}
console.log(binarySearch([1, 2, 3, 4, 5, 6, 7], 4)) // returns 3 for index 3
In the console.log
example I have provided, we get a list
of seven elements and are looking for the item 4
. We expect this example to return 3
, which is the index of the value 4
in the array.
How fast is binary search?
Remember the example of looking for your name in an alphabetized list of names? What if you took the first approach and looked through each name, starting at A, to find your own — and what if your name began with Z! How many steps would it take to reach your name? Well, if the list was 100 names long, it could take roughly 100 steps for you to reach your own name.
What if instead you used binary search? How many steps would it take in that case? With a lower bound of A, and an upper bound of Z, you’d first divide the list at M. Your name is after M so you’d increase your lower bound to be M+1, or N. Your upper bound would stay the same, at Z. You’d divide your list again, finding the midpoint between N and Z, which google tells me is T. Your name is after T, so you’d continue for another step, finding the midpoint between U and Z next, or W. Then you’d go between X and Z to find Y and finally your next midpoint would be Z itself, which is what you were looking for. This whole process, took five steps, as opposed to 100!
In computer programming we have a notion of Big O, which describes how much an algorithm’s run time increases as we increase the size of the array it is running on.
In Big O we’d describe the first algorithm for finding your name (which is called linear search by the way) as having O(n) time. This means that as the amount of elements in the array being searched increase, the amount of steps to complete the search also increases linearly.
In the graph below the blue line describes linear time, which shows us that as elements increase, operations also increase at the same rate.
In contrast, in Big O, binary search has logarithmic time, or O(logn) time. While the amount of elements in the array being searched may increase drastically, the amount of steps needed to complete the search only increase a little bit.
In the graph below the blue line describes logarithmic time, where increasing the number of elements increases the operations quickly at first, but much more slowly as elements become greater and greater.
And that’s it on binary search! I hope you enjoyed this miniature glimpse into a popular search algorithm. If you have any questions, please feel free to post them in the comments.
Resources
A book I am enjoying so far for studying algorithms is Grokking Algorithms by Aditya Y. Bhargava. It introduces some common, interesting, and fast algorithms in an approachable format with practical examples and entertaining illustrations. Find it on the publisher’s website, here.
Here is an article to check out from Khan Academy that details binary search with visual examples.