The Magic of Binary Search Algorithm

Introduction
Ever tried to find a word in a dictionary? How do you do it? You don't start from the first page and flip through every single page, right? Instead, you open it roughly in the middle and check if the word you're looking for is before or after that page. This is the essence of the Binary Search Algorithm.
What is Binary Search?
Binary search is a method to quickly find a specific item in a sorted list. It works by looking at the middle element of the list and comparing it with the item you're searching for. If the middle element isn't the target, it decides whether to search in the left half or the right half of the list. This process repeats until the item is found or the list can no longer be split.
Binary Search in Action
Before we dive into the technical stuff, let's see how binary search works compared to linear search.
Linear Search
Linear search works by checking each element in the list one by one until it finds the target.
Let's click on a number from the list below to see how linear search finds it.
You see, it started from the first element and checked each one until it found the target. This takes time, especially if the list is long and the target is at very end or not present at all.
Binary Search
Binary search, on the other hand, is much faster. It divides the list in half with each step. Let's see how it works.
You can see that it starts in the middle and checks if the target is greater or less than the middle element. Based on that, it decides which half to search next. This process continues until the target is found or the list can't be divided anymore.
This is the magic of binary search! It reduces the number of comparisons needed to find the target, making it much more efficient than linear search. The time complexity of binary search is O(log n), while linear search has a time complexity of O(n). This means that as the list grows larger, binary search becomes significantly faster than linear search.
Algorithm
Now that we understand how binary search works, let's look at the algorithm in detail.
The binary search algorithm can be implemented in two ways: iteratively and recursively. Both methods achieve the same result, but they differ in their approach.
Algorithm
Step 1: Find the middle element of the list.
Step 2: Compare the middle element with the target element.
Step 3: If the middle element is equal to the target element, then return the index of the middle element.
Step 4: If the middle element is greater than the target element, then search the left half of the list.
Step 5: If the middle element is less than the target element, then search the right half of the list.
Step 6: Repeat steps 1 to 5 until the target element is found or the list cannot be divided anymore.
Pseudocode
The binary search algorithm can be represented in pseudocode as follows:
FUNCTION binary_search(SORTED_LIST[], TARGET)
SET LEFT TO 0
SET RIGHT TO LENGTH(SORTED_LIST) - 1
WHILE LEFT <= RIGHT DO
SET MIDDLE TO (LEFT + RIGHT) / 2
IF SORTED_LIST[MIDDLE] == TARGET THEN
RETURN MIDDLE
ELSE IF SORTED_LIST[MIDDLE] < TARGET THEN
SET LEFT TO MIDDLE + 1
ELSE
SET RIGHT TO MIDDLE - 1
END IF
END WHILE
RETURN -1
END FUNCTION
Implementation
Now, let's implement the binary search algorithm in various programming languages.
Binary Search using Iteration
function binarySearch(sortedList, target, left, right) {
while (left <= right) {
let middle = Math.floor((left + right) / 2);
if (sortedList[middle] === target) {
return middle;
} else if (sortedList[middle] < target) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return -1;
}
let sortedList = [1, 2, 3, 4, 5, 6, 7];
let target = 5;
let left = 0;
let right = sortedList.length - 1;
let index = binarySearch(sortedList, target, left, right);
if (index === -1) {
console.log("Element not found");
} else {
console.log("Element found at index " + index);
}
function binarySearch($sortedList, $target, $left, $right) {
while ($left <= $right) {
$middle = floor(($left + $right) / 2);
if ($sortedList[$middle] === $target) {
return $middle;
} else if ($sortedList[$middle] < $target) {
$left = $middle + 1;
} else {
$right = $middle - 1;
}
}
return -1;
}
$sortedList = [1, 2, 3, 4, 5, 6, 7];
$target = 5;
$left = 0;
$right = count($sortedList) - 1;
$index = binarySearch($sortedList, $target, $left, $right);
if ($index === -1) {
echo "Element not found";
} else {
echo "Element found at index " . $index;
}
def binary_search(sorted_list, target, left, right):
while left <= right:
middle = (left + right) // 2
if sorted_list[middle] == target:
return middle
elif sorted_list[middle] < target:
left = middle + 1
else:
right = middle - 1
return -1
sorted_list = [1, 2, 3, 4, 5, 6, 7]
target = 5
left = 0
right = len(sorted_list) - 1
index = binary_search(sorted_list, target, left, right)
if index == -1:
print("Element not found")
else:
print("Element found at index", index)
public class BinarySearch {
public static int binarySearch(int[] sortedList, int target, int left, int right) {
while (left <= right) {
int middle = (left + right) / 2;
if (sortedList[middle] == target) {
return middle;
} else if (sortedList[middle] < target) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] sortedList = {1, 2, 3, 4, 5, 6, 7};
int target = 5;
int left = 0;
int right = sortedList.length - 1;
int index = binarySearch(sortedList, target, left, right);
if (index == -1) {
System.out.println("Element not found");
} else {
System.out.println("Element found at index " + index);
}
}
}
#include <stdio.h>
int binary_search(int sorted_list[], int target, int left, int right) {
while (left <= right) {
int middle = (left + right) / 2;
if (sorted_list[middle] == target) {
return middle;
} else if (sorted_list[middle] < target) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return -1;
}
int main() {
int sorted_list[] = {1, 2, 3, 4, 5, 6, 7};
int target = 5;
int left = 0;
int right = sizeof(sorted_list) / sizeof(sorted_list[0]) - 1;
int index = binary_search(sorted_list, target, left, right);
if (index == -1) {
printf("Element not found\n");
} else {
printf("Element found at index %d\n", index);
}
}
Binary Search using Recursion
function binarySearch(sortedList, target, left, right) {
if (left > right) {
return -1;
}
let middle = Math.floor((left + right) / 2);
if (sortedList[middle] === target) {
return middle;
} else if (sortedList[middle] < target) {
return binarySearch(sortedList, target, middle + 1, right);
} else {
return binarySearch(sortedList, target, left, middle - 1);
}
}
let sortedList = [1, 2, 3, 4, 5, 6, 7];
let target = 5;
let left = 0;
let right = sortedList.length - 1;
let index = binarySearch(sortedList, target, left, right);
if (index === -1) {
console.log("Element not found");
} else {
console.log("Element found at index " + index);
}
function binarySearch($sortedList, $target, $left, $right) {
if ($left > $right) {
return -1;
}
$middle = floor(($left + $right) / 2);
if ($sortedList[$middle] === $target) {
return $middle;
} else if ($sortedList[$middle] < $target) {
return binarySearch($sortedList, $target, $middle + 1, $right);
} else {
return binarySearch($sortedList, $target, $left, $middle - 1);
}
}
$sortedList = [1, 2, 3, 4, 5, 6, 7];
$target = 5;
$left = 0;
$right = count($sortedList) - 1;
$index = binarySearch($sortedList, $target, $left, $right);
if ($index === -1) {
echo "Element not found";
} else {
echo "Element found at index " . $index;
}
def binary_search(sorted_list, target, left, right):
if left > right:
return -1
middle = (left + right) // 2
if sorted_list[middle] == target:
return middle
elif sorted_list[middle] < target:
return binary_search(sorted_list, target, middle + 1, right)
else:
return binary_search(sorted_list, target, left, middle - 1)
sorted_list = [1, 2, 3, 4, 5, 6, 7]
target = 5
left = 0
right = len(sorted_list) - 1
index = binary_search(sorted_list, target, left, right)
if index == -1:
print("Element not found")
else:
print("Element found at index", index)
public class BinarySearch {
public static int binarySearch(int[] sortedList, int target, int left, int right) {
if (left > right) {
return -1;
}
int middle = (left + right) / 2;
if (sortedList[middle] == target) {
return middle;
} else if (sortedList[middle] < target) {
return binarySearch(sortedList, target, middle + 1, right);
} else {
return binarySearch(sortedList, target, left, middle - 1);
}
}
public static void main(String[] args) {
int[] sortedList = {1, 2, 3, 4, 5, 6, 7};
int target = 5;
int left = 0;
int right = sortedList.length - 1;
int index = binarySearch(sortedList, target, left, right);
if (index == -1) {
System.out.println("Element not found");
} else {
System.out.println("Element found at index " + index);
}
}
}
#include <stdio.h>
int binary_search(int sorted_list[], int target, int left, int right) {
if (left > right) {
return -1;
}
int middle = (left + right) / 2;
if (sorted_list[middle] == target) {
return middle;
} else if (sorted_list[middle] < target) {
return binary_search(sorted_list, target, middle + 1, right);
} else {
return binary_search(sorted_list, target, left, middle - 1);
}
}
int main() {
int sorted_list[] = {1, 2, 3, 4, 5, 6, 7};
int target = 5;
int left = 0;
int right = sizeof(sorted_list) / sizeof(sorted_list[0]) - 1;
int index = binary_search(sorted_list, target, left, right);
if (index == -1) {
printf("Element not found\n");
} else {
printf("Element found at index %d\n", index);
}
}
Performance Analysis
The performance of the binary search algorithm can be analyzed in terms of time and space complexity.
The time complexity of binary search is O(log n), where n is the number of elements in the list. This is because the algorithm divides the list in half with each step, leading to a logarithmic growth in the number of comparisons needed.
The space complexity is O(1) for the iterative version, as it uses a constant amount of space. The recursive version has a space complexity of O(log n) due to the call stack used for recursion.
Case | Time Complexity | Space Complexity |
---|---|---|
Best | O(1) | O(1) |
Average | O(log n) | O(1) |
Worst | O(log n) | O(1) |
Conclusion
Binary search is a powerful algorithm that can significantly reduce the time it takes to find an element in a sorted list. By dividing the list in half with each step, it achieves a logarithmic time complexity, making it much faster than linear search for large datasets.