No result illustrationNo result illustration

DevLoom

search

Lets Connect

chevron right
Menu
Home

Home

Community

Community

Blog Posts

Blog Posts

Programming

Programming

Tech Topics

Tech Topics

Explore

Explore

Find Jobs

Find Jobs

Tags

Tags

DevLoomPerfect Place for devs
    profile

    Jubair

    upvoteupvote

    1

    downvote

    0

    star

    Implementation of Merge Sort using C++

    clock icon

    Asked 11 months ago

    message

    1Comments

    eye

    4 Views

    Imagine you've got a messy pile of books and you want to sort them by size. That's what this code is doing, but with numbers.

    The main idea? Divide and conquer, baby!

    1. First, we split our pile of books (or numbers) in half. Then we split those halves in half again. We keep doing this until we've got single books.
    2. Now, we start putting them back together, but in order. We compare two books, put the smaller one first, and keep going.
    3. We do this over and over until our whole pile is sorted.

    That's the big picture. 

    Let's visualize this with a small test case. We'll use the array [38, 27, 43, 3, 9, 82, 10] and walk through the merge sort process step by step.

    Initial array: [38, 27, 43, 3, 9, 82, 10]

    Step 1: Divide We keep dividing the array until we get single elements:
                 [38, 27, 43, 3, 9, 82, 10]
                        /            \
             [38, 27, 43, 3]    [9, 82, 10]
               /        \         /     \
          [38, 27]    [43, 3]   [9]  [82, 10]
           /    \      /    \         /    \
        [38]   [27]  [43]   [3]     [82]  [10]

    Step 2: Conquer (Merge)
    Now we start merging these back up, sorting as we go:

    [38] [27] -> [27, 38]
    [43] [3]  -> [3, 43]
    
    [27, 38] [3, 43] -> [3, 27, 38, 43]
    
    [9] [82, 10] -> [9, 10, 82]
    
    [3, 27, 38, 43] [9, 10, 82] -> [3, 9, 10, 27, 38, 43, 82]

    Let's zoom in on one of these merge steps, say merging [27, 38] and [3, 43]:

    1. Compare 27 and 3: 3 is smaller, so it goes first. [3]
    2. Compare 27 and 43: 27 is smaller. [3, 27]
    3. 38 is next smallest. [3, 27, 38]
    4. 43 is last. [3, 27, 38, 43]

    This process happens for each merge step until we get our final sorted array.

    Final sorted array: [3, 9, 10, 27, 38, 43, 82]

    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    // Function to merge two sorted subarrays of vector v
    void merge(vector<int> &v, int start, int end) {
        // If the subarray has 0 or 1 element, it's already sorted
        if (start >= end)
            return;
    
        // Calculate the middle point
        int mid = (start + end) / 2;
    
        // Calculate lengths of two subarrays
        int len1 = mid - start + 1;  // Length of left subarray
        int len2 = end - mid;        // Length of right subarray
    
        // Create temporary arrays
        int *left = new int[len1];   // Temporary array for left subarray
        int *right = new int[len2];  // Temporary array for right subarray
    
        // Copy data to temporary arrays
    
        // Copy left subarray
        int k = start;
        for (int i = 0; i < len1; i++) {
            left[i] = v[k];
            k++;
        }
    
        // Copy right subarray
        k = mid + 1;
        for (int i = 0; i < len2; i++) {
            right[i] = v[k];
            k++;
        }
    
        // Merge the temporary arrays back into v[start..end]
    
        int leftIndex = 0;      // Index for left subarray
        int rightIndex = 0;     // Index for right subarray
        int mainArrayIndex = start;  // Index for main array
    
        // Compare elements from both subarrays and place the smaller one in the main array
        while (leftIndex < len1 && rightIndex < len2) {
            if (left[leftIndex] < right[rightIndex]) {
                v[mainArrayIndex] = left[leftIndex];
                leftIndex++;
            } else {
                v[mainArrayIndex] = right[rightIndex];
                rightIndex++;
            }
            mainArrayIndex++;
        }
    
        // Copy remaining elements of left subarray, if any
        while (leftIndex < len1) {
    
            // v[mainArrayIndex] = left[leftIndex];
            // leftIndex++;
            // mainArrayIndex++;
            // The ABOVE 3 Lines can be Written as 
            v[mainArrayIndex++] = left[leftIndex++];
            
        }
    
        // Copy remaining elements of right subarray, if any
        while (rightIndex < len2) {
            v[mainArrayIndex] = right[rightIndex];
            rightIndex++;
            mainArrayIndex++;
        }
    
        // Free the memory allocated for temporary arrays
        delete[] left;
        delete[] right;
    }
    
    // Recursive function to sort an array using merge sort
    void mergeSort(vector<int> &v, int start, int end) {
        // Base case: if the subarray has 0 or 1 element, it's already sorted
        if (start >= end)
            return;
    
        // Find the middle point to divide the array into two halves
        int mid = (start + end) / 2;
    
        // Recursively sort the left half
        mergeSort(v, start, mid);
    
        // Recursively sort the right half
        mergeSort(v, mid + 1, end);
    
        // Merge the sorted halves
        merge(v, start, end);
    }
    
    int main() {
        // Create a vector with unsorted integers
        vector<int> v = {823, 45, 34, 93, 423, 42, 232, 23, 22, 2};
        int size = v.size();
    
        // Call mergeSort to sort the entire vector
        mergeSort(v, 0, size - 1);
    
        // Print the sorted vector
        for (int i = 0; i < v.size(); i++) {
            cout << v[i] << " ";
        }
    
        return 0;
    }

    In the code, the merge function is doing these comparison and rearrangement steps. It's creating temporary arrays to hold the split pieces, then merging them back into the main array in sorted order.

    The mergeSort function is handling the recursive splitting and calling merge to put things back together.

    int leftIndex = 0;
    int rightIndex = 0;
    int mainArrayIndex = start;
    
    while (leftIndex < len1 && rightIndex < len2)
    {
        if (left[leftIndex] < right[rightIndex])
        {
            v[mainArrayIndex] = left[leftIndex++];
        }
        else
        {
            v[mainArrayIndex] = right[rightIndex++];
        }
        mainArrayIndex++;
    }

    This is where the magic happens! We compare elements from both halves and put the smaller one back into the main array ! and Handling LeftOvers ! 

    Let's dive into each of these steps in a more descriptive approach:

    1. Calculating sizes: Imagine you're splitting a deck of cards into two piles. You need to know how many cards are in each pile. That's what we're doing here:
      • len1 = mid - start + 1: This counts how many cards are in the left pile.
      • len2 = end - mid: This counts how many cards are in the right pile. These calculations ensure we know exactly how big our temporary arrays need to be.
    2. Creating temporary arrays: Now that we know how big our piles are, we're creating two new, smaller decks to hold these cards temporarily:
      • int *left = new int[len1]: This is like getting a new, empty box that can hold exactly len1 cards.
      • int *right = new int[len2]: Another new box, this time for len2 cards. These temporary arrays give us a workspace to sort our cards without messing up the original deck.
    3. Copying data to temp arrays: This step is like dealing cards into our new boxes:
      • We start at the beginning of our section (k = start) and deal cards one by one into the left box.
      • Then we move to the middle (k = mid + 1) and deal the rest into the right box. This process copies our data so we can work with it without changing the original array.
    4. Merging logic: This is the heart of the merge sort. Imagine you have two piles of sorted cards, and you're combining them into one sorted pile:
      • You look at the top card of each pile.
      • You take the smaller card and put it into your final pile.
      • You keep doing this until one pile is empty. This process ensures that as you build your new pile, it stays in order from smallest to largest.
    5. Handling leftovers: After the main merging, one pile might still have cards left:
      • If the left pile has cards, we add them all to the end of our final pile.
      • If the right pile has cards, we do the same with those. This step ensures we don't forget any cards and that all of them end up in our final, sorted pile.
    6. Cleaning up: Remember those temporary boxes we created? We don't need them anymore:
      • delete[] left: This is like recycling the left box.
      • delete[] right: And here we recycle the right box. In programming terms, we're freeing the memory we allocated earlier. This is important to prevent memory leaks, which can slow down or crash our program if we forget to clean up.

     Time Complexity is O(N log N).

     

    Algorithm
    Sorting
    MergeSort
    medium

    Share

    Write your comment here !

    1 Responses

    profile

    Jubair

    commented 9 months ago

    upvoteupvote

    0

    downvote

    0

    Anathor Approch !

    #include <vector>
    #include <iostream>
    using namespace std;
    
    // Function to merge two sorted subarrays of vector v
    void merge(vector<int> &v, int start, int end) {
        // If the subarray has 0 or 1 element, it's already sorted
        if (start >= end)
            return;
    
        vector<int> temp; // Temporary array to store the merged subarray
    
        // Calculate the middle point
        int mid = (start + end) / 2;
    
        // Pointers to traverse the two subarrays
        int leftPart = start;    // Starting index of the left subarray
        int rightPart = mid + 1; // Starting index of the right subarray
    
        // Merge the two subarrays into the temp array
        while (leftPart <= mid && rightPart <= end) {
            // Compare elements from both subarrays and pick the smaller one
            if (v[leftPart] <= v[rightPart]) {
                temp.push_back(v[leftPart++]); // Add from the left subarray
            } else {
                temp.push_back(v[rightPart++]); // Add from the right subarray
            }
        }
    
        // Copy any remaining elements from the left subarray
        while (leftPart <= mid) {
            temp.push_back(v[leftPart++]);
        }
    
        // Copy any remaining elements from the right subarray
        while (rightPart <= end) {
            temp.push_back(v[rightPart++]);
        }
    
        // Copy the merged elements back to the original vector
        for (int index = start, x = 0; index <= end; index++) {
            v[index] = temp[x++]; // Assign sorted values back to the original array
        }
    }
    
    // Recursive function to sort an array using merge sort
    void mergeSort(vector<int> &v, int start, int end) {
        // Base case: if the subarray has 0 or 1 element, it's already sorted
        if (start >= end)
            return;
    
        // Find the middle point to divide the array into two halves
        int mid = (start + end) / 2; // start + (end - start) / 2 // avoid overflow
    
        // Recursively sort the left half
        mergeSort(v, start, mid);
    
        // Recursively sort the right half
        mergeSort(v, mid + 1, end);
    
        // Merge the sorted halves
        merge(v, start, end);
    }
    
    int main() {
        // Create a vector with unsorted integers
        vector<int> v = {6, 3, 7, 2, 5, 4};
        int size = v.size();
    
        // Call mergeSort to sort the entire vector
        mergeSort(v, 0, size - 1);
    
        // Print the sorted vector
        for (int i = 0; i < size; i++) {
            cout << v[i] << " ";
        }
    
        return 0;
    }