Binary Search
Binary Search
Space Complexity:
Space complexity of an algorithm represents the amount of memory space
needed the algorithm in its life cycle.
Time Complexity:
Time complexity measures how many operations an algorithm completes in
relation to the size of the input. It aids in our analysis of the algorithm's
performance scaling with increasing input size. Big O notation (O()) is the
notation that is most frequently used to indicate temporal complexity. It offers
an upper bound on how quickly an algorithm's execution time will increase.
Best, Worst, and Average Case Complexity:
In analyzing algorithms, we consider three types of time complexity:
Best-case Complexity (O(best)): This represents the minimum time
required for an algorithm to complete when given the optimal input. It denotes
an algorithm operating at its peak efficiency under ideal
circumstances(conditions).
Worst-case Complexity (O(worst)): This denotes the maximum time an
algorithm will take to finish for any given input. It represents the scenario
where the algorithm encounters the most unfavorable input.
Linked Lists:
Access: O(n)
Search: O(n)
Insertion (at the beginning): O(1)
Insertion (at the end, with a tail pointer): O(1)
Insertion (at the end, without a tail pointer): O(n)
Insertion (in the middle): O(n)
Deletion (from the beginning): O(1)
Deletion (from the end, with a tail pointer): O(1)
Deletion (from the end, without a tail pointer): O(n)
Deletion (from the middle): O(n)
Stacks:
Push: O(1)
Pop: O(1)
Peek: O(1)
Queues:
Enqueue: O(1)
Dequeue: O(1)
Peek: O(1)
Hash Tables:
Search: O(1) - on average, assuming a good hash function and minimal
collisions
Insertion: O(1) - on average, assuming a good hash function and minimal
collisions
Deletion: O(1) - on average, assuming a good hash function and minimal
collisions
Binary Search
For sorted arrays, binary search is more efficient than linear search.
The process starts from the middle of the input array:
If the target equals the element in the middle, return its index.
If the target is larger than the element in the middle, search the right half.
If the target is smaller, search the left half.
In the following binarySearch() method, the two index variables first and
last indicates the searching boundary at each round.
1 int binarySearch(int arr[], int target)
2 {
3 int first = 0, last = arr.length - 1;
4
5 while (first <= last)
6 {
7 int mid = (first + last) / 2;
8 if (target == arr[mid])
9 return mid;
10 if (target > arr[mid])
11 first = mid + 1;
12 else
13 last = mid - 1;
14 }
15 return -1;
16 }
Binary search divides the array in the middle at each round of the loop.
Suppose the array has length n and the loop runs in t rounds, then we have
n * (1/2)^t = 1 since at each round the array length is divided by 2. Thus t =
log(n). At each round, the loop body takes constant time. Therefore, binary
search runs in logarithmic time O(log n).
Time Complexity:
Best Case Complexity - It occurs when there is no sorting required, i.e. the
array is already sorted. The best-case time complexity of bubble sort is O(n).
Average Case Complexity - It occurs when the array elements are in jumbled
order that is not properly ascending and not properly descending. The average
case time complexity of bubble sort is O(n2).
Worst Case Complexity - It occurs when the array elements are required to be sorted in
reverse order. That means suppose you have to sort the array elements in ascending order,
but its elements are in descending order. The worst-case time complexity of bubble sort is
O(n2).