Logo

Programming-Idioms

  • Fortran
  • Rust
  • JS
  • Perl

Idiom #124 Binary search for a value in sorted array

Write the function binarySearch which returns the index of an element having the value x in the sorted array a, or -1 if no such element exists.

use 5.020;
sub binary_search {
    my ($x, $A, $lo, $hi) = @_;
    $lo //= 0;
    $hi //= @$A;
    my $mid = int($lo + ($hi - $lo) / 2);
    for ($x cmp $A->[$mid]) {
        use experimental 'switch';
        return $mid when 0;
        return -1 if 1 == $hi - $lo;
        return binary_search($x, $A, $lo, $mid) when -1;
        return binary_search($x, $A, $mid, $hi) when 1;
    }
}
use List::BinarySearch qw( binsearch  );
# Some ordered arrays to search within.
@num_array =   ( 100, 200, 300, 400, 500 );
@str_array = qw( Bach Beethoven Brahms Mozart );
 
 
# Find the lowest index of a matching element.
 
$index = binsearch {$a <=> $b} 300, @num_array;
$index = binsearch {$a cmp $b} 'Mozart', @str_array;

The perl CPAN library has a module for this. There are lots of tricky edge cases. Better to use a well tested public module than roll your own.

Also works on objects by providing an appropriate comparison function.
   integer function binarysearch(a,x) result(l)
      integer,intent(in)::a(:)
      integer,intent(in)::x
      integer::r,mid
      l=1
      r=size(a)
      do while(l<=r)
         mid=l+(r-l)/2;
         if(a(mid)==x)then
            l=mid
            return
         end if
         if(a(mid)<x)then
            l=mid+1;
         else 
            r=mid-1;
         end if
      end do
      l=-1
   end function binarysearch
a.binary_search(&x).unwrap_or(-1);

This only works if a is an array of signed integers.
Generally, a Result or Option would be more useful.
function binarySearch(a, x, i = 0) {
  if (a.length === 0) return -1
  const half = (a.length / 2) | 0
  return (a[half] === x) ?
    i + half :
    (a[half] > x) ?
    binarySearch(a.slice(0, half), x, i) :
    binarySearch(a.slice(half + 1), x, half + i + 1)
}

x | 0 removes the bit of x after the decimal.
This would be easier if JavaScript had more builtins for list processing.
#include <vector>
template<typename T>
int binarySearch(const std::vector<T> &a, const T &x)
{
    if(a.size() == 0) return -1;

    size_t lower = 0;
    size_t upper = a.size() - 1;

    while(lower <= upper)
    {
        auto mid = lower + (upper-lower) / 2;

        if(x == a[mid])
        {
            return (int)mid;
        }
        else if(x > a[mid])
        {
            lower = mid + 1;
        }
        else
        {
            upper = mid - 1;
        }
    }

    return -1;
}

Check for an empty vector up front, otherwise size() will return an unsigned 0, and subtracting 1 will be a big number!

New implementation...
< >
programming-idioms.org