Skip to content

Instantly share code, notes, and snippets.

@cspotcode
Last active December 18, 2015 18:49
Show Gist options
  • Save cspotcode/5828079 to your computer and use it in GitHub Desktop.
Save cspotcode/5828079 to your computer and use it in GitHub Desktop.
My attempt at the Great Binary Search Experiment: http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/
// Given an array of numbers, returns either the index containing that number
// or `undefined` if the array doesn't contain that number.
// Assumes that `list` is a non-sparse JavaScript array, that all items in the list are integers,
// and that the list is sorted in ascending order (obviously)
// Assumes that `value` is an integer.
function binarySearch(list, value) {
// Lower bound = minimum possible index
var lowerBound = 0;
// Upper bound = maximum possible index + 1
var upperBound = list.length;
// An index in the middle of our range. We will compute this shortly.
var middleIndex;
// Loop forever (we will break out of this loop via a return statement)
while(true) {
// Is our target range of length 0 (or negative!?)? Then the target value must not be in the list
if(upperBound - lowerBound <= 0) return undefined;
// Compute the index of the middle of our target range
// Assumes that upperBound >= lowerBound
middleIndex = lowerBound + Math.floor((upperBound - lowerBound) / 2);
// Have we found the target value? Great! We're done.
if(list[middleIndex] === value) return middleIndex;
if(value < list[middleIndex]) {
// The middleIndex value is greater than our target value
// so the target value comes *before* middleIndex
// upperBound = middleIndex, meaning that our range has everything *up to but not including* middleIndex
upperBound = middleIndex;
} else {
// The middleIndex value is less than our target value
// so the target value comes *after* middleIndex
// lowerBound = middleIndex + 1, meaning that our range has everything *after and not including* middleIndex
lowerBound = middleIndex + 1;
}
}
}
// Test cases
test("empty list", function() {
ok(binarySearch([], 4) === undefined);
});
test("one-item list", function() {
ok(binarySearch([3], 3) === 0);
ok(binarySearch([3], 10) === undefined);
ok(binarySearch([3], 1) === undefined);
});
test("two-item list", function() {
var list = [5, 10];
ok(binarySearch(list, 0) === undefined);
ok(binarySearch(list, 5) === 0);
ok(binarySearch(list, 7) === undefined);
ok(binarySearch(list, 10) === 1);
ok(binarySearch(list, 12) === undefined);
});
test("three-item list", function() {
var list = [5, 10, 15];
ok(binarySearch(list, 0) === undefined);
ok(binarySearch(list, 5) === 0);
ok(binarySearch(list, 7) === undefined);
ok(binarySearch(list, 10) === 1);
ok(binarySearch(list, 12) === undefined);
ok(binarySearch(list, 15) === 2);
ok(binarySearch(list, 20) === undefined);
});
test("four-item list", function() {
var list = [5, 10, 15, 20];
ok(binarySearch(list, 0) === undefined);
ok(binarySearch(list, 5) === 0);
ok(binarySearch(list, 7) === undefined);
ok(binarySearch(list, 10) === 1);
ok(binarySearch(list, 12) === undefined);
ok(binarySearch(list, 15) === 2);
ok(binarySearch(list, 17) === undefined);
ok(binarySearch(list, 20) === 3);
ok(binarySearch(list, 40) === undefined);
});
var totalIterations = 500000;
var chunkSize = 1000;
for(var i = 0; i < totalIterations / chunkSize; i++) {
test("many random lists of random length with random contents, searching for random numbers", function() {
var list, length, j, value, listContainsValue, result;
for(var i = 0; i < chunkSize; i++) {
list = [];
length = (Math.random() * 300)|0;
for(j = 0; j < length; j++) {
list.push((Math.random() * 200)|0);
}
list.sort(function(a, b) {return a < b ? -1 : a > b ? 1 : 0});
value = (Math.random() * 200)|0;
listContainsValue = false;
for(j = 0; j < length; j++) {
if(list[j] === value) {
listContainsValue = true;
break;
}
}
result = binarySearch(list, value);
ok(result !== undefined || listContainsValue === false, '' + value + ' in ' + JSON.stringify(list));
ok(result === undefined || list[result] === value);
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment