Binary Search in JavaScript
Binary Search in JavaScript
A
practical Example
Learn what a binary search is with the help of
terribly drawn pictures and a code example
If it’s less than, we can remove the right half of the array.
If it’s more than, we can remove the left half of the array.
If it’s equal to, we return the value
The catch here is that the array must be sorted — i.e. the values
must be in order for a binary search to work.
When working with large chunks of data, it is much faster to use a
binary search because with each iteration you remove 1/2 of the
array’s wrong values, instead of just one wrong value.
The Project.
Recently, I published an article on How I built an Interactive 30-
Day Bitcoin Price Graph with React and an API.
One of the most important aspects of the chart is the Tool Tip that
displays
relevant data as you hover over the chart. As you move your
mouse, the chart updates with the data from the closest data point.
Here’s a gif example:
How does this work?
I have an array of all of the data point coordinates. The
coordinates are within an object, and each object has an svgX key.
It looks something like this:
svgData = [
{svgX: 1367.844, data...},
{svgX: 1684.478, data...},
{svgX: 1168.474, data...},
{svgX: 1344.854, data...},
// etc.
]
Originally I was using a simple for loop to compare the
current X location of the mouse with all of the svgX values in my
dataset.
For loop.
Here’s what the for loop code looks like. Whichever object has
an svgXvalue that is closest to the X location of the mouse — is the
data we want to highlight.
Binary Search
Here’s the binary search code to find the closest data point:
As you can see in the code above on line 9, when we start our
binary search we pass in our entire data array, with the mouse
target, a starting point of 0, and an ending point equal to the full
size of the array:
Searching the full array
Once we have our data, the middle of the array is found by adding
the starting location and the ending location together then
dividing by two. To ensure there are no fractions, the resulting
number is rounded down:
if (e — 1 === s) {
return
Math.abs(d[s].svgX — t) > Math.abs(d[e].svgX — t) ? d[e] :
d[s];
}
This is our termination case. This case will only prove true when
we’ve narrowed down our array to two final values, and our target
is between those values. If our target is between those values, we
return whichever is closer.
Next, we check to see if our target value is greater than our middle
value:
In this case it is! Target value of 3.7 is greater than middle value
of 3. We can get rid of the first two values in our array:
Using recursion we return a new invocation of
the binarySearch() function. We pass in our array, the target value
of 3.7, the middle value as our starting value, and the ending
value as our end value.
Now we have a brand new invocation of binarySearch() that will
search from 2 to data.length-1:
if (e — 1 === s) {
return
Math.abs(d[s].svgX — t) > Math.abs(d[e].svgX — t) ? d[e] :
d[s];
}
Since our ending value minus one equals our starting value, we
know the target value is somewhere between the two. We’re going
to return whichever data point is closer to the value of 3.7.
Since 4, (the ending value) is closer, we return the ending
value:d[3].
Speed Test
With smaller data sets, recursion can actually be slower than
a for loop. Testing on jsperf with just 10 data points, the recursive
function averaged 3% slower than the for loop.
However, at 10,000 data points, the for loop is 72% slower
than the recursive function. This means the recursive
function is nearly twice as fast as the for loop! That’s a massive
time savings.
Closing Notes
Hopefully you can now understand the basics of a binary search in
JavaScript!