Divide and conquer is a powerful algorithm design paradigm used to solve complex problems by breaking them down into smaller subproblems, solving each subproblem independently, and then combining their solutions to solve the original problem. It typically involves three main steps:
Here are a few well-known algorithms that follow the divide and conquer strategy:
Let’s explore some of these algorithms in detail.
Merge Sort is a sorting algorithm that uses the divide and conquer approach to sort an array or list of elements.
Consider an array [8, 3, 5, 4, 7, 1, 6, 2]. Here's how merge sort works:
Divide:
[8, 3, 5, 4] and [7, 1, 6, 2][8, 3], [5, 4], [7, 1], [6, 2]Conquer:
[3, 8], [4, 5], [1, 7], [2, 6][3, 4, 5, 8] and [1, 2, 6, 7]Combine:
[1, 2, 3, 4, 5, 6, 7, 8]#include <iostream>
using namespace std;
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int i = 0; i < n2; i++)
R[i] = arr[mid + 1 + i];
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j])
arr[k++] = L[i++];
else
arr[k++] = R[j++];
}
while (i < n1)
arr[k++] = L[i++];
while (j < n2)
arr[k++] = R[j++];
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
int main() {
int arr[] = {8, 3, 5, 4, 7, 1, 6, 2};
int n = sizeof(arr)/sizeof(arr[0]);
mergeSort(arr, 0, n - 1);
cout << "Sorted array: ";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
Merge Sort is an efficient sorting algorithm, with a time complexity of O(n log n), but it uses additional space for merging the subarrays.
Quick Sort is another sorting algorithm that uses the divide and conquer technique. Unlike merge sort, quick sort selects a pivot element, and rearranges the elements around the pivot such that all elements smaller than the pivot are on the left, and all elements greater are on the right.
#include <iostream>
using namespace std;
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return i + 1;
}
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int main() {
int arr[] = {8, 3, 5, 4, 7, 1, 6, 2};
int n = sizeof(arr)/sizeof(arr[0]);
quickSort(arr, 0, n - 1);
cout << "Sorted array: ";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
Binary Search is a divide and conquer algorithm used to search for an element in a sorted array. It works by repeatedly dividing the search space in half.
#include <iostream>
using namespace std;
int binarySearch(int arr[], int left, int right, int target) {
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target)
return mid;
if (arr[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return -1; // Target not found
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
int n = sizeof(arr)/sizeof(arr[0]);
int target = 5;
int result = binarySearch(arr, 0, n - 1, target);
if (result != -1)
cout << "Element found at index " << result << endl;
else
cout << "Element not found" << endl;
return 0;
}
To analyze the complexity of divide and conquer algorithms, we often use recurrence relations. These express the time complexity in terms of the time taken to solve smaller subproblems.
Where:
2T(n/2) represents the time taken to solve the two halves of size `n/2`.
O(n) represents the time taken to merge the two halves.Using the Master Theorem, we can solve this to get the overall time complexity of O(n log n).
Divide and conquer is a versatile approach that can optimize many algorithms by reducing the size of the problem at each step. It is particularly useful in sorting (e.g., merge sort and quick sort), searching (e.g., binary search), and various computational geometry problems.
Open this section to load past papers