I'm trying to implement a binary search algorithm in JavaScript. Things seem okay, but my return statements appear to be returning undefined? Can anybody tell what's wrong here?
Fiddle: http://jsfiddle.net/2mBdL/
Thanks.
var a = [ 1, 2, 4, 6, 1, 100, 0, 10000, 3 ]; a.sort(function (a, b) { return a - b; }); console.log('a,', a); function binarySearch(arr, i) { var mid = Math.floor(arr.length / 2); console.log(arr[mid], i); if (arr[mid] === i) { console.log('match', arr[mid], i); return arr[mid]; } else if (arr[mid] < i && arr.length > 1) { console.log('mid lower', arr[mid], i); binarySearch(arr.splice(mid, Number.MAX_VALUE), i); } else if (arr[mid] > i && arr.length > 1) { console.log('mid higher', arr[mid], i); binarySearch(arr.splice(0, mid), i); } else { console.log('not here', i); return -1; } } var result = binarySearch(a, 100); console.log(result);
Binary Search is a searching technique which works on the Divide and Conquer approach. It is used to search for any element in a sorted array. Compared with linear, binary search is much faster with a Time Complexity of O(logN), whereas linear search works in O(N) time complexity.
Binary Search is a searching algorithm for finding an element's position in a sorted array. In this approach, the element is always searched in the middle of a portion of an array. Binary search can be implemented only on a sorted list of items. If the elements are not sorted already, we need to sort them first.
As in the above code snippet we define a node class having three property data, left and right, Left and right are pointers to the left and right node in a Binary Search Tree. Data is initialized with data which is passed when object for this node is created and left and right is set to null.
It's useful to write a search function in such a way that it returns a negative value indicating the insertion point for the new element if the element is not found. Also, using recursion in a binary search is excessive and unnecessary. And finally, it's a good practice to make the search algorithm generic by supplying a comparator function as a parameter. Below is the implementation.
function binarySearch(ar, el, compare_fn) { var m = 0; var n = ar.length - 1; while (m <= n) { var k = (n + m) >> 1; var cmp = compare_fn(el, ar[k]); if (cmp > 0) { m = k + 1; } else if(cmp < 0) { n = k - 1; } else { return k; } } return -m - 1; }
This code with comments and a unit test here.
There are many workable solutions to this question, but all of them return early once they have found a match. While this might have a small positive effect on performance, this is negligible due to the logarithmic nature of binary search and can actually hurt performance if the comparison function is expensive to compute.
What is more, it prevents a very useful application of the binary search algorithm: finding a range of matching elements, also known as finding the lower or upper bound.
The following implementation returns an index 0
≤ i
≤ array.length
such that the given predicate is false
for array[i - 1]
and true
for array[i]
. If the predicate is false
everywhere, array.length
is returned.
/** * Return 0 <= i <= array.length such that !pred(array[i - 1]) && pred(array[i]). */ function binarySearch(array, pred) { let lo = -1, hi = array.length; while (1 + lo < hi) { const mi = lo + ((hi - lo) >> 1); if (pred(array[mi])) { hi = mi; } else { lo = mi; } } return hi; }
Assume for the sake of argument that pred(array[-1]) === false
and pred(array[array.length]) === true
(although of course the predicate is never evaluated at those points). The loop maintains the invariant !pred(array[lo]) && pred(array[hi])
. The algorithm terminates when 1 + lo === hi
which implies !pred(array[hi - 1]) && pred(array[hi])
, the desired postcondition.
If an array is sort()
ed with respect to a comparison function compare
, the function returns the smallest insert position of an item
when invoked as
binarySearch(array, j => 0 <= compare(item, j));
An insert position is an index at which an item would be found if it existed in the array.
It is easy to implement lower and upper bound for an array in natural ordering as follows.
/** * Return i such that array[i - 1] < item <= array[i]. */ function lowerBound(array, item) { return binarySearch(array, j => item <= j); } /** * Return i such that array[i - 1] <= item < array[i]. */ function upperBound(array, item) { return binarySearch(array, j => item < j); }
Of course, this is most useful when the array can contain several elements that compare identically, for example where elements contain additional data that is not part of the sort criteria.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With