Day 11: 100 Days of DSA

Sorting Basics

Hey, welcome to Day 11 of 100 Days of DSA. Today I’ll be solving questions related to sorting. We’ll be analyzing its complexities as sorting is a fundamental technique in data structures. Let’s dive in!


1. Implement Bubble Sort and analyze its time complexity.

Bubble Sort involves repeatedly stepping through the array, comparing adjacent elements, and swapping them if they are out of order. This process is repeated for all elements until the array is sorted. The time complexity of Bubble Sort is O(n2)O(n^2)O(n2) in the worst and average cases, as every pair of elements is compared. It performs best on already sorted data, with a time complexity of O(n)..

Code:

// To implement bubble sort.
// Time Complexity -> O(n)

#include<iostream>
using namespace std;

void bubbleSort(int arr[],int size){
    for(int i=0;i<size-1;i++){
        for(int j=0;j<size-i-1;j++){
            if(arr[j]>arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

int main(){
    int arr[] = {5,4,3,2,1};
    cout<<"Array before sorting: ";
    for(int i=0;i<5;i++){
        cout<<arr[i]<<" ";
    }
    cout<<endl;
    cout<<"Array after sorting: ";
    int size = sizeof(arr)/sizeof(arr[0]);
    bubbleSort(arr,size);
    for(int i=0;i<size;i++){
        cout<<arr[i]<<" ";
    }
    return 0;
}

Output:


2. Implement Selection Sort and analyze its time complexity.

Selection Sort divides the array into a sorted and unsorted section. It repeatedly selects the smallest element from the unsorted section and swaps it with the first unsorted element. This method ensures one element is placed in the correct position during each iteration. The time complexity is O(n2)O(n^2)O(n2) for all cases because it always makes n(n−1)/2n(n-1)/2n(n−1)/2 comparisons, regardless of the initial order.

Code:

// To implement selection sort

#include<iostream>
using namespace std;

void selectionSort(int arr[],int size){
    for(int i=0;i<size-1;i++){
        int minIndex = i;
        for(int j=i+1;j<size;j++){
            if(arr[j]<arr[minIndex]){
                minIndex = j;
            }
        }
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

int main(){
    int arr[] = {5,4,3,2,1};
    cout<<"Array before sorting: ";
    for(int i=0;i<5;i++){
        cout<<arr[i]<<" ";
    }
    cout<<endl;
    cout<<"Array after sorting: ";
    int size = sizeof(arr)/sizeof(arr[0]);
    selectionSort(arr,size);
    for(int i=0;i<size;i++){
        cout<<arr[i]<<" ";
    }
    return 0;
}

Output:


3. Solve the "sort an array of 0s, 1s, and 2s" problem.

This problem can be solved using the Dutch National Flag algorithm. Use three pointers (low, mid, high) to divide the array into three partitions: 0s, 1s, and 2s. As you traverse the array, move elements to the appropriate partition by swapping. This algorithm sorts the array in O(n) time with O(1) space, as it processes each element only once.

Code:

//  Solve the "sort an array of 0s, 1s, and 2s" problem.

#include<iostream>
using namespace std;

void sort012(int arr[],int size){
    int low = 0;
    int mid = 0;
    int high = size-1;
    while(mid<=high){
        if(arr[mid]==0){
            int temp = arr[low];
            arr[low] = arr[mid];
            arr[mid] = temp;
            low++;
            mid++;
        }
        else if(arr[mid]==1){
            mid++;
        }
        else{
            int temp = arr[mid];
            arr[mid] = arr[high];
            arr[high] = temp;
            high--;
        }
    }
}

int main(){
    int arr[] = {0,1,2,0,1,2};
    cout<<"Array before sorting: ";
    for(int i=0;i<6;i++){
        cout<<arr[i]<<" ";
    }
    cout<<endl;
    cout<<"Array after sorting: ";
    int size = sizeof(arr)/sizeof(arr[0]);
    sort012(arr,size);
    for(int i=0;i<size;i++){
        cout<<arr[i]<<" ";
    }
    return 0;
}

Output:


4. Implement Insertion Sort and count the number of shifts/swaps during sorting.

Insertion Sort builds the sorted portion of the array one element at a time by repeatedly picking the next element and placing it in the correct position within the sorted section. While inserting each element, count the number of shifts or swaps required to maintain the order. The time complexity is O(n2) in the worst case and O(n) in the best case when the array is already sorted.
Code:

//  Implement Insertion Sort and count the number of shifts/swaps during sorting.
// Time Complexity -> O(n^2)

#include<iostream>
using namespace std;

int insertionSort(int arr[],int size){
    int count = 0;
    for(int i=1;i<size;i++){
        int key = arr[i];
        int j = i-1;
        while(j>=0 && arr[j]>key){
            arr[j+1] = arr[j];
            j--;
            count++;
        }
        arr[j+1] = key;
    }
    return count;
}

int main(){
    int arr[] = {5,4,3,2,1};
    cout<<"Array before sorting: ";
    for(int i=0;i<5;i++){
        cout<<arr[i]<<" ";
    }
    cout<<endl;
    cout<<"Array after sorting: ";
    int size = sizeof(arr)/sizeof(arr[0]);
    int count = insertionSort(arr,size);
    for(int i=0;i<size;i++){
        cout<<arr[i]<<" ";
    }
    cout<<endl;
    cout<<"Number of shifts: "<<count;
    return 0;
}

Output:


5. Solve the "merge two sorted arrays without extra space" problem.

To merge two sorted arrays in-place, start from the last element of the combined arrays. Use two pointers to compare elements from the end of each array and place the larger one at the last available position. This avoids using additional space while maintaining sorted order. The time complexity is O(n+m), where nnn and mmm are the sizes of the arrays, and the space complexity is O(1).

Code:

// Solve the "merge two sorted arrays without extra space" problem.

#include <iostream>
#include <vector>
using namespace std;

void mergeArrays(vector<int>& arr1, vector<int>& arr2) {
    int n = arr1.size(), m = arr2.size();
    int i = n - 1, j = m - 1, k = n + m - 1;
    arr1.resize(n + m);
    while (j >= 0) {
        if (i >= 0 && arr1[i] > arr2[j]) {
            arr1[k] = arr1[i];
            i--;
        } else {
            arr1[k] = arr2[j];
            j--;
        }
        k--;
    }
}

int main() {
    vector<int> arr1 = {1, 3, 5, 7};
    vector<int> arr2 = {2, 4, 6, 8};

    cout << "Array 1: ";
    for (int num : arr1) cout << num << " ";
    cout << endl;

    cout << "Array 2: ";
    for (int num : arr2) cout << num << " ";
    cout << endl;

    mergeArrays(arr1, arr2);

    cout << "Array after merging: ";
    for (int num : arr1) cout << num << " ";
    cout << endl;

    return 0;
}

Ouput:


Will be back tomorrow, happy coding!