Abdul Bari Algorithms - Binary Search
How to implement binary search recursively and iteratively
Binary Search Iterative
You can do binary search recursively or iteratively
{{youtube-timestamp 25}} binary search uses the divide and conquer strategy
Divide and conquer is breaking problem into subproblems, then combine them to get solution to main problem
{{youtube-timestamp 50}} List must be in sorted order to perform binary search
{{youtube-timestamp 77}} We need two index pointers, low
and high
Suppose we want to search for key element 42 in this list
[3,6,8,12,14,17,25,29,31,36,42,47,53,55,62]
middle
is the floor of
##+BEGIN_NOTE His examples used starting index of 1, but I changed it to index starting at 0 in these notes. I also changed end index to length-1 ##+END_NOTE
low
is index 0 and high
is index 14, so mid
is 7
The number at index 7 is 29
{{youtube-timestamp 163}} The number 42 which we’re searching for is greater than 29, so the new low
becomes mid + 1
, which is 8;
Now low
= 8 and high
= 14
so the new mid
is 11
{{youtube-timestamp 202}} The number at index 11 is 47
The number 42 which we’re searching for is less than 7
, so the new high
becomes mid - 1
, which is 10
Now low
= 8 and high
=10
so the new mid
is 9
The number at index 9 is 36
{{youtube-timestamp 243}} The number 42 which we’re searching for is greater than 36, so the new low
becomes mid + 1
, which is 10;
Now both low
= 10 and high
= 10
so the new mid
is 10
{{youtube-timestamp 284}} The number at index 10 is 42, which is the number we’re searching for.
{{youtube-timestamp 292}} How many comparisons have we done? 4
If we had been doing linear search it would have taken 11 comparisons
##+BEGIN_WARNING This implementation has a subtle bug, where it fails for very large arrays. See this blog post about this bug.
int mid = (low + high) / 2;
(incorrect)
vs
int mid = low + ((high - low) / 2);
(correct)
##+END_WARNING
Implementation
//returns index of value or -1
function binarySearch(array, key){
let low=0;
let high = array.length-1;
const mid = (low+high)/2;
while (low <= high){
if (array[mid]===key){
return mid;
} else if (key < array[mid]){
high = mid-1;
} else {
low = mid+1;
}
}
return -1;
}
Visualize as Binary Search Tree
{{youtube-timestamp 815}} This can be arranged as a binary search tree
What is the worst case number of comparisons when searching for an element?
If you don’t find it, you’ll search until you reach the bottom of the tree.
The height of the tree is where n is the number of elements
{{youtube-timestamp 1123}} So if there are 16 elements then , so the height of the tree is 4 levels and the worst case number of comparisons will be 4
So worst case is and best case is , when the element you’re looking for is the root.
Binary Search Recursive
[3,6,8,12,14,17,25,29,31,36,42,47,53,55,62]
When using divide and conquer, we divide into smaller problems then recombine
So we should define what defines a “small” problem when using divide and conquer
In this case a “small” problem is when there is only a single element, or when low
and high
are equal.
Then when we have a single element, if the element is the target value, otherwise return -1
If the problem is large we make it smaller based on some logic.
function recursiveBinarySearch(array, key, low, high){
if (low === high){
if (array[low]===key){
return low;
} else {
return -1;
}
} else {
const mid = (low + high)/2;
if (array[mid]===key){
return mid;
} else if (key < array[mid]){
return recursiveBinarySearch(array, key, low, mid-1);
} else {
return recursiveBinarySearch(array, key, mid+1, high);
}
}
}
Recurrence Relation
{{youtube-timestamp 297}} Calculating mid, checking if mid
= key
, and checking if array[mid]
is greater or less than target each take one unit of time.
{{youtube-timestamp 308}} When calling the recursive function it called itself with
{{youtube-timestamp 326}} When list size is one, it just makes one comparation, so each is one unit of time
By applying master’s theorem, we know the time complexity is
We use case 2 from the master’s theorem
We can think of the recurrence relation as
Remember the master’s theorem
In this equation and
The from the master’s theorem is in this equation, because , so we know is 0 and is 0
if is true, , so we know it’s case 2
so we know it’s case 2.1 of master’s theorem
Case 2.1 is