ScholarQuill logoScholarQuillUniversity Notes
My Semester
Explore Notes
Past Papers12 New
Video CoursesNew
Search
Settings
Study Tools
GPA/CGPA Calculator
Schedule & To-Do
Student Portal
Contact
Contact
ScholarQuill logo
My Semester
Explore Notes
Past Papers12 New
Video CoursesNew
Search
Settings
GPA/CGPA Calculator
Schedule & To-Do
Student Portal
Contact
ScholarQuill logoScholarQuillUniversity Notes
Study PortalCC-213Divide Conquer Algorit…
Ctrl + K
Login
Explore
Search
Semester
Papers
CGPA
    CC-213

    Data Structures & Algorithms

    Progress0 / 37 done
    Topics37
    1Abstract Data Types2Complexity Analysis3Big Oh Notation4Stacks (Linked Lists and Array Implementations)5Recursion and analyzing recursive algorithms6Divide and Conquer Algorithms7Sorting Algorithms8Selection Sort9Insertion Sort10Merge Sort11Quick Sort12Bubble Sort13Heap Sort14Shell Sort15Radix Sort16Bucket Sort17Queue18Dequeuer19Priority Queues (linked and array implementations of queues)20Linked List and Its Various Types21Sorted Linked List22Searching an Unsorted Array23Binary Search for Sorted Arrays24Hashing and Indexing25Open Addressing and Chaining26Trees and Tree Traversals27Binary Search Trees28Heaps29M-Way Trees30Balanced Trees31Graphs32Breadth-First Traversal33Depth-First Traversal34Topological Order35Shortest Path36Adjacency Matrix and Adjacency List Implementations37Memory Management and Garbage Collection
    8 min read
    Topic 6 of 37
    Topic Study Note Illustration
    06

    Divide and Conquer Algorithms

    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...

    Divide and Conquer Algorithms

    What is Divide and Conquer?

    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:

    1. Divide: Split the problem into smaller subproblems that are easier to solve.
    2. Conquer: Solve each subproblem recursively.
    3. Combine: Merge the solutions of the subproblems to obtain the final solution.

    Key Characteristics of Divide and Conquer

    • Recursion: Divide and conquer algorithms often rely on recursion to solve subproblems.
    • Efficiency: These algorithms can be more efficient than iterative methods, especially for large inputs.
    • Parallelism: The independent nature of subproblems allows parallel processing, making them suitable for parallel computing.

    Common Divide and Conquer Algorithms

    Here are a few well-known algorithms that follow the divide and conquer strategy:

    1. Merge Sort
    2. Quick Sort
    3. Binary Search
    4. Closest Pair of Points
    5. Matrix Multiplication (Strassen's Algorithm)

    Let’s explore some of these algorithms in detail.

    1. Merge Sort

    Merge Sort is a sorting algorithm that uses the divide and conquer approach to sort an array or list of elements.

    Steps of Merge Sort:

    1. Divide: Split the array into two halves.
    2. Conquer: Recursively sort each half.
    3. Combine: Merge the two sorted halves into a single sorted array.

    Example:

    Consider an array [8, 3, 5, 4, 7, 1, 6, 2]. Here's how merge sort works:

    1. Divide:

      • Split into two arrays: [8, 3, 5, 4] and [7, 1, 6, 2]
      • Recursively divide further: [8, 3], [5, 4], [7, 1], [6, 2]
    2. Conquer:

      • Sort each pair: [3, 8], [4, 5], [1, 7], [2, 6]
      • Merge sorted halves: [3, 4, 5, 8] and [1, 2, 6, 7]
    3. Combine:

      • Merge the two sorted arrays to get the final sorted array: [1, 2, 3, 4, 5, 6, 7, 8]

    Merge Sort in C++:

    #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;
    }
    

    Time Complexity of Merge Sort:

    • Divide: Splitting the array into two halves takes O(log n) time (because the array is divided log(n) times).
    • Conquer: Merging two halves takes O(n) time (since we need to merge n elements).
    • Overall Time Complexity: O(n log n).

    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.

    2. Quick Sort

    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.

    Steps of Quick Sort:

    1. Divide: Choose a pivot element and partition the array around the pivot.
    2. Conquer: Recursively sort the left and right partitions.
    3. Combine: No need to explicitly combine, as the elements are already in place.

    Quick Sort in C++:

    #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;
    }
    

    Time Complexity of Quick Sort:

    • Best/Average Case: O(n log n) (when the pivot divides the array evenly).
    • Worst Case: O(n²) (when the pivot divides the array unevenly, like choosing the smallest or largest element as the pivot).
    • Space Complexity: O(log n) (for recursive call stack).

    3. Binary Search

    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.

    Steps of Binary Search:

    1. Divide: Find the middle element of the array.
    2. Conquer: If the middle element is equal to the target, return it. Otherwise, search in the left or right half depending on whether the target is smaller or larger than the middle element.
    3. Combine: No explicit combining is needed.

    Binary Search in C++:

    #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;
    }
    

    Time Complexity of Binary Search:

    • Best Case: O(1) (when the middle element is the target).
    • Worst/Average Case: O(log n) (because the search space is halved with each iteration).
    • Space Complexity: O(1) (iterative implementation).

    Analyzing Divide and Conquer Algorithms

    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.

    Example: Merge Sort Recurrence Relation

    • T(n) = 2T(n/2) + O(n)

    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).

    Conclusion

    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.

    ← Previous topic 5
    Recursion and analyzing recursive algorithms
    Next topic 7 →
    Sorting Algorithms

    Past Papers

    Open this section to view and download past papers

    Click on Show Past Papers to load available exam papers.

    Reading Progress
    0%
    8mremaining
    1.3kwords
    Intermediatelevel
    On This Page

    No headings found

    Study Toolkit

    Subject Portal

    Data Structures & Algorithms