Searching
1. Linear Search
Description: Linear search is the simplest search algorithm. It checks each element of the list until the target element is found or the list ends.
Time Complexity:
Worst Case: O(n)
Best Case: O(1)
Average Case: O(n)
Space Complexity: O(1) (iterative version)
Use Cases:
When the list is unsorted.
Small datasets where the overhead of more complex algorithms isn't justified.
Example:
public class LinearSearch {
public static int linearSearch(int[] arr, int key) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == key) {
return i;
}
}
return -1;
}
}
2. Binary Search
Description: Binary search is used on a sorted array. It works by repeatedly dividing the search interval in half. If the value of the search key is less than the item in the middle of the interval, narrow the interval to the lower half. Otherwise, narrow it to the upper half.
Time Complexity:
Worst Case: O(logn)
Best Case: O(1)
Average Case: O(logn)
Space Complexity:
Iterative version: O(1)
Recursive version: O(logn)
Use Cases:
When the list is sorted.
Large datasets where performance is critical.
Example:
public class BinarySearch {
public static int binarySearch(int[] arr, int key) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == key) {
return mid;
}
if (arr[mid] < key) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}
3. Jump Search
Description: Jump search works on a sorted array. It jumps ahead by fixed steps and checks if the element is present, if not, it performs a linear search between the last jumped index and the current index.
Time Complexity:
Worst Case: O(√n)
Best Case: O(1)
Average Case: O(√n)
Space Complexity: O(1)
Use Cases:
Faster than linear search for large sorted arrays (time complexity of O(√n)).
Easier to implement compared to some advanced search algorithms like binary search.
Suitable for large datasets where binary search overhead is significant.
Only works for sorted arrays.
Example:
public class JumpSearch {
public static int jumpSearch(int[] arr, int key) {
int n = arr.length;
// Calculate jump step size
int step = (int) Math.floor(Math.sqrt(n));
int prev = 0;
// Search by jumping through blocks
while (arr[Math.min(step, n) - 1] < key) {
prev = step;
step += (int) Math.floor(Math.sqrt(n));
if (prev >= n) {
return -1;
}
}
// Linear search within the final block
while (arr[prev] < key) {
prev++;
if (prev == Math.min(step, n)) {
return -1;
}
}
if (arr[prev] == key) {
return prev;
}
return -1;
}
}
4. Interpolation Search
Description: Interpolation search is another searching algorithm for sorted arrays. It improves upon binary search by making an educated guess about the target element's position based on its value and the distribution of elements in the array. This guess, calculated using a formula, can significantly reduce the search space compared to simply going to the middle element like binary search.
Time Complexity:
Worst Case: O(n)
Best Case: O(1)
Average Case: O(loglogn)
Space Complexity: O(1)
Use Cases:
Faster than binary search for uniformly distributed sorted arrays (average time complexity of O(log(log(n)))).
Can be more efficient than binary search in specific scenarios.
Suitable for large datasets with uniform distribution.
Not as efficient as binary search for non-uniformly distributed data (worst-case time complexity of O(n)).
Requires the array to be sorted.
Example of sorted and uniformly distributed array
arr = [5, 10, 15, 17, 20, 22, 23, 25, 28, 29]
In this example:
The array is sorted, with values increasing gradually.
The difference between most adjacent elements is relatively small (around 2-3 gain), suggesting a somewhat even spread of values.
Uniform distribution doesn't guarantee perfectly equal differences between elements. There can be slight variations.
Example:
public class InterpolationSearch {
public static int interpolationSearch(int[] arr, int key) {
int lo = 0, hi = arr.length - 1;
while (lo <= hi && key >= arr[lo] && key <= arr[hi]) {
if (lo == hi) {
if (arr[lo] == key) {
return lo;
}
return -1;
}
// Calculate probe position using interpolation formula
int pos = lo + (((hi - lo) / (arr[hi] - arr[lo])) * (key - arr[lo]));
if (arr[pos] == key) {
return pos;
}
if (arr[pos] < key) {
lo = pos + 1;
} else {
hi = pos - 1;
}
}
return -1;
}
}
5. Exponential Search
Description: Exponential search involves two steps: finding the range where the element may be present and then using binary search within that range.
Time Complexity:
Worst Case: O(logn)
Best Case: O(1)
Average Case: O(logn)
Space Complexity:
Iterative version: O(1)
Recursive version: O(logn)
Use Cases:
When the list is sorted.
Faster than linear search for sorted arrays with a sparse distribution of elements (time complexity of O(log i), where i is the index of the target element).
Suitable for unbounded/infinite lists.
Not as efficient as binary search, which has a time complexity of O(log n) for all cases.
Example:
class ExponentialSearch {
public static int exponentialSearch(int[] arr, int key) {
if (arr[0] == key) {
return 0;
}
int i = 1;
while (i < arr.length && arr[i] <= key) {
i *= 2;
}
return binarySearch(arr, key, i / 2, Math.min(i, arr.length - 1));
}
private static int binarySearch(int[] arr, int key, int left, int right) {
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == key) {
return mid;
}
if (arr[mid] < key) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}
Comparison table
Algorithm
Time Complexity
Space Complexity
Use Cases
Linear Search
Worst: O(n)
O(1)
Unsorted lists, small datasets.
Best: O(1)
Average: O(n)
Binary Search
Worst: O(logn)
O(1)(iterative)
Sorted lists, large datasets where performance is critical.
Best: O(1)
O(logn)(recursive)
Average: O(logn)
Jump Search
Worst: O(n)
O(1)
Sorted lists, large datasets where binary search overhead is significant.
Best: O(1)
Average: O(n)
Interpolation Search
Worst: O(n)
O(1)
Sorted and uniformly distributed lists, large datasets with uniform distribution.
Best: O(1)
Average: O(loglogn)
Exponential Search
Worst: O(logn)
O(1)(iterative)
Sorted lists, unbounded/infinite lists.
Best: O(1)
O(logn)(recursive)
Average: O(logn)
Last updated
Was this helpful?