Skip to content

Instantly share code, notes, and snippets.

@binki
Last active February 1, 2017 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save binki/fdaa9d928143a1d68cb7ab2f94af9acd to your computer and use it in GitHub Desktop.
Save binki/fdaa9d928143a1d68cb7ab2f94af9acd to your computer and use it in GitHub Desktop.
Binary search attempt
class BinkiBinarySearch {
/**
Input: `arr` is a sorted array, `sought` is a sought value,
`cmp` a comparer which when called like `cmp(a, b)` returns -1
if `a` comes before `b`, 0 if `a` and `b` are of the same
order, and 1 if `a` comes after `b`.
Returns: -1 if something equivalent to `sought` is not found,
index of any element matching `sought` otherwise.
**/
static function bsearch<T>(arr:Array<T>, sought:T, cmp:T->T->Int) {
var min = 0;
var max = arr.length - 1;
while (min <= max) {
var i = min + Std.int((max - min)/2);
var val = arr[i];
var cmpResult = cmp(sought, val);
if (cmpResult < 0) {
max = i - 1;
} else if (cmpResult > 0) {
// Ensure to avoid getting stuck where min=0, max=1,
// and min+(max-min)/2=0.
min = i + 1;
} else {
return i;
}
}
return -1;
}
static function main() {
// For validating syntax.
// Tests for my cmp function xD. I wrote cmp() wrong the first
// time according to the API of my bsearch(), I was able to
// get stuff working by fixing cmp() (I only added trace()
// debugging to bsearch() and then noticed that cmp() was
// behaving wrong then added these test cases).
expectCmp(0, 0, 0);
expectCmp(0, 1, -1);
expectCmp(1, 0, 1);
// Tests written after I decided to consider the interface
// frozen.
expect([], 2, -1);
expect([0,1,2], 2, 2);
expect([0,1,3], 2, -1);
expect([4,5,6], 2, -1);
expect([-1,0,1], 2, -1);
expect([0], 2, -1);
expect([3], 2, -1);
expect([2], 2, 0);
expect([0,1], 2, -1);
expect([1,2], 2, 1);
expect([1,3], 2, -1);
expect([4,5], 2, -1);
expect([2,3,4,5,6,7,8,9,10,11], 2, 0);
expect([1,2,3,4,5,6,7,8,9,10], 2, 1);
expect([0,1,2,3,4,5,6,7,8,9], 2, 2);
expect([-1,0,1,2,3,4,5,6,7,8], 2, 3);
expect([-2,-1,0,1,2,3,4,5,6,7], 2, 4);
expect([-3,-2,-1,0,1,2,3,4,5,6], 2, 5);
expect([-4,-3,-2,-1,0,1,2,3,4,5], 2, 6);
expect([-5,-4,-3,-2,-1,0,1,2,3,4], 2, 7);
expect([-6,-5,-4,-3,-2,-1,0,1,2,3], 2, 8);
expect([-7,-6,-5,-4,-3,-2,-1,0,1,2], 2, 9);
expect([0,1,3,4,5,6,7,8,9,10], 2, -1);
expect([-1,0,1,2,3,4,5,6,7,8], 2, 3);
}
static function cmp(a, b) return a - b;
static function expectCmp(a, b, expectedResult) {
var result = cmp(a, b);
if (result != expectedResult) {
throw 'Expected ${expectedResult} but got ${result}';
}
}
static function expect(arr, sought, expectedIndex) {
var result = bsearch(arr, sought, cmp);
if (result != expectedIndex) {
throw 'Expected ${expectedIndex} but got ${result}';
}
}
}
@binki
Copy link
Author

binki commented Jan 31, 2017

Based on the comment about using half-open ranges, I probably am not splitting down the middle quite and will tend to go slightly to the left because my ranges are not open?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment