Unraveling the Mysteries of Sorting Algorithms
1. Bubble Sort
Detailed Algorithmic Steps
Initialization:
- Start with the array you want to sort. Let’s denote the array as
arr
and its size asn
.
- Start with the array you want to sort. Let’s denote the array as
Outer Loop:
- Run a loop from
i = 0
ton-1
(orn-2
if you prefer to avoid one iteration since the last element will naturally be in place). This loop will keep track of how many passes through the array you have completed.
- Run a loop from
Swapping Flag:
- Initialize a boolean flag
swapped
tofalse
at the beginning of each outer loop iteration. This flag will help detect if any swapping happened during the inner loop.
- Initialize a boolean flag
Inner Loop:
Run a nested loop from
j = 0
ton-i-2
. The reason we stop atn-i-2
is that the lasti
elements are already sorted in each pass.Inside this inner loop, compare the current element
arr[j]
with the next elementarr[j + 1]
.
Comparison:
If
arr[j]
is greater thanarr[j + 1]
, swap them.Set the
swapped
flag totrue
to indicate that a swap has occurred.
Check for Early Exit:
After the inner loop completes, check the
swapped
flag:- If
swapped
is stillfalse
, it means the array is already sorted, and you can exit the outer loop early to save unnecessary passes.
- If
Completion:
- Once all outer loop iterations are complete, the array is sorted.
Return or Print:
- Return the sorted array or print it.
Complexity:
Time Complexity:
Worst-case: O(n2)O(n^2)O(n2) (when the array is in reverse order)
Best-case: O(n)O(n)O(n) (when the array is already sorted)
Space Complexity: O(1)O(1)O(1) (in-place sorting)
C/C++ Implementation
#include <iostream>
using namespace std;
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
bool swapped = false; // Flag to track if a swap occurred
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr[j], arr[j + 1]); // Swap if elements are in the wrong order
swapped = true; // Set the flag
}
}
// If no elements were swapped, the array is sorted
if (!swapped) {
break;
}
}
}
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
cout << "Sorted array: ";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
Java Implementation
public class BubbleSort {
void bubbleSort(int arr[]) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
boolean swapped = false; // Flag to track if a swap occurred
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Swap arr[j] and arr[j + 1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true; // Set the flag
}
}
// If no elements were swapped, the array is sorted
if (!swapped) {
break;
}
}
}
public static void main(String[] args) {
BubbleSort ob = new BubbleSort();
int arr[] = {64, 34, 25, 12, 22, 11, 90};
ob.bubbleSort(arr);
System.out.println("Sorted array:");
for (int i : arr) {
System.out.print(i + " ");
}
}
}
Python Implementation
def bubble_sort(arr):
n = len(arr)
for i in range(n - 1):
swapped = False # Flag to track if a swap occurred
for j in range(n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j] # Swap if elements are in the wrong order
swapped = True # Set the flag
# If no elements were swapped, the array is sorted
if not swapped:
break
arr = [64, 34, 25, 12, 22, 11, 90]
bubble_sort(arr)
print("Sorted array:", arr)
2.Selection Sort
Overview
Selection Sort is a simple sorting algorithm that divides the input list into two parts: a sorted part and an unsorted part. It repeatedly selects the smallest (or largest) element from the unsorted part and moves it to the end of the sorted part.
Algorithm Steps
Start with the first element as the minimum.
Iterate through the unsorted part of the array to find the smallest element.
Swap the smallest element with the first unsorted element.
Move the boundary between the sorted and unsorted parts.
Repeat steps 1-4 until the entire array is sorted.
Time Complexity
Best Case: O(n²)
Average Case: O(n²)
Worst Case: O(n²)
Space Complexity: O(1) (in-place sort)
C/C++ Implementation
#include <iostream>
using namespace std;
void selectionSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int minIndex = i; // Assume the first element is the minimum
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // Update minimum index
}
}
swap(arr[i], arr[minIndex]); // Swap the found minimum with the first element
}
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
selectionSort(arr, n);
cout << "Sorted array: ";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
Java Implementation
javaCopy codepublic class SelectionSort {
void selectionSort(int arr[]) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
int minIndex = i; // Assume the first element is the minimum
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // Update minimum index
}
}
// Swap the found minimum with the first element
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
public static void main(String[] args) {
SelectionSort ob = new SelectionSort();
int arr[] = {64, 25, 12, 22, 11};
ob.selectionSort(arr);
System.out.println("Sorted array:");
for (int i : arr) {
System.out.print(i + " ");
}
}
}
Python Implementation
def selection_sort(arr):
n = len(arr)
for i in range(n - 1):
min_index = i # Assume the first element is the minimum
for j in range(i + 1, n):
if arr[j] < arr[min_index]:
min_index = j # Update minimum index
arr[i], arr[min_index] = arr[min_index], arr[i] # Swap
arr = [64, 25, 12, 22, 11]
selection_sort(arr)
print("Sorted array:", arr)
2. Insertion Sort
Overview
Insertion Sort is a simple sorting algorithm that builds the final sorted array one element at a time. It is much less efficient on large lists than more advanced algorithms but is quite efficient for small data sets.
Algorithm Steps
Start from the second element (the first element is considered sorted).
Compare the current element with the elements in the sorted part of the array.
Shift all elements larger than the current element to the right.
Insert the current element in its correct position.
Repeat for all elements until the array is sorted.
Time Complexity
Best Case: O(n) (when the array is already sorted)
Average Case: O(n²)
Worst Case: O(n²)
Space Complexity: O(1) (in-place sort)
C/C++ Implementation
#include <iostream>
using namespace std;
void insertionSort(int arr[], int n) {
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
// Shift elements greater than key to the right
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key; // Insert the current element at the right position
}
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
insertionSort(arr, n);
cout << "Sorted array: ";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
Java Implementation
public class InsertionSort {
void insertionSort(int arr[]) {
int n = arr.length;
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
// Shift elements greater than key to the right
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key; // Insert the current element at the right position
}
}
public static void main(String[] args) {
InsertionSort ob = new InsertionSort();
int arr[] = {64, 25, 12, 22, 11};
ob.insertionSort(arr);
System.out.println("Sorted array:");
for (int i : arr) {
System.out.print(i + " ");
}
}
}
Python Implementation
def insertion_sort(arr):
n = len(arr)
for i in range(1, n):
key = arr[i]
j = i - 1
# Shift elements greater than key to the right
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key # Insert the current element at the right position
arr = [64, 25, 12, 22, 11]
insertion_sort(arr)
print("Sorted array:", arr)
4. Merge Sort
Detailed Algorithmic Steps
Divide:
If the array has one or zero elements, it is already sorted. Return it.
Otherwise, find the middle index
mid
of the array:mid = (low + high) / 2
wherelow
is the starting index andhigh
is the ending index of the current array segment.
Recursively Sort:
Recursively apply the Merge Sort algorithm to the left half of the array (
arr[low...mid]
).Recursively apply the Merge Sort algorithm to the right half of the array (
arr[mid+1...high]
).
Merge:
After sorting both halves, merge the two sorted halves:
Create temporary arrays to hold the left (
L
) and right (R
) halves.Initialize three pointers:
i
for iterating throughL
,j
forR
, andk
for the main array.Compare elements of
L
andR
:If
L[i] <= R[j]
, placeL[i]
inarr[k]
and incrementi
andk
.Otherwise, place
R[j]
inarr[k]
and incrementj
andk
.
After one of the arrays is exhausted, copy the remaining elements of the other array into
arr
.
Completion:
- Once all elements are merged, the array will be sorted.
Complexity:
Time Complexity:
Worst-case: O(nlogn)O(n \log n)O(nlogn)
Best-case: O(nlogn)O(n \log n)O(nlogn)
Space Complexity: O(n)O(n)O(n) (due to the temporary arrays used for merging)
C/C++ Implementation
#include <iostream>
using namespace std;
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1; // Size of left sub-array
int n2 = right - mid; // Size of right sub-array
// Create temporary arrays
int L[n1], R[n2];
// Copy data to temporary arrays L[] and R[]
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
// Merge the temporary arrays back into arr[left..right]
int i = 0; // Initial index of first sub-array
int j = 0; // Initial index of second sub-array
int k = left; // Initial index of merged sub-array
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// Copy the remaining elements of L[], if there are any
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
// Copy the remaining elements of R[], if there are any
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2; // Avoid overflow
mergeSort(arr, left, mid); // Sort first half
mergeSort(arr, mid + 1, right); // Sort second half
merge(arr, left, mid, right); // Merge the sorted halves
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
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] << " ";
return 0;
}
Java Implementation
public class MergeSort {
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
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);
}
}
public static void main(String[] args) {
MergeSort ob = new MergeSort();
int arr[] = {12, 11, 13, 5, 6, 7};
ob.mergeSort(arr, 0, arr.length - 1);
System.out.println("Sorted array:");
for (int i : arr) {
System.out.print(i + " ");
}
}
}
Python Implementation
def merge(arr, left, mid, right):
n1 = mid - left + 1
n2 = right - mid
L = arr[left:left + n1] # Left sub-array
R = arr[mid + 1:mid + 1 + n2] # Right sub-array
i = 0 # Initial index of first sub-array
j = 0 # Initial index of second sub-array
k = left # Initial index of merged sub-array
while i < n1 and j < n2:
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < n1:
arr[k] = L[i]
i += 1
k += 1
while j < n2:
arr[k] = R[j]
j += 1
k += 1
def merge_sort(arr, left, right):
if left < right:
mid = left + (right - left) // 2
merge_sort(arr, left, mid)
merge_sort(arr, mid + 1, right)
merge(arr, left, mid, right)
arr = [12, 11, 13, 5, 6, 7]
merge_sort(arr, 0, len(arr) - 1)
print("Sorted array:", arr)
3. Quick Sort
Detailed Algorithmic Steps
Choose a Pivot:
- Select a pivot element from the array. Common strategies include choosing the first element, the last element, or a random element.
Partitioning:
Rearrange the array so that elements less than the pivot come before it and elements greater than the pivot come after it.
Create two pointers:
i
starts before the first element (i.e.,-1
), andj
iterates through the array.
For each element
arr[j]
:- If
arr[j]
is less than or equal to the pivot, incrementi
and swaparr[i]
witharr[j]
.
- If
After the loop, swap the pivot element with
arr[i + 1]
. This places the pivot in its correct position.
Recursively Apply:
Apply the Quick Sort algorithm to the sub-arrays:
arr[low...i]
for elements less than the pivot.arr[i+2...high]
for elements greater than the pivot.
Completion:
- Once the base case (sub-array size <= 1) is reached, the recursion unwinds, and the array is sorted.
Complexity:
Time Complexity:
Worst-case: O(n2)O(n^2)O(n2) (when the pivot is the smallest or largest element repeatedly)
Average-case: O(nlogn)O(n \log n)O(nlogn)
Space Complexity: O(logn)O(\log n)O(logn) (for the recursive call stack)
C/C++ Implementation
#include <iostream>
using namespace std;
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // Choosing the last element as pivot
int i = low - 1; // Pointer for the smaller element
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++; // Increment index of smaller element
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return i + 1; // Return the partitioning index
}
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high); // Partitioning index
quickSort(arr, low, pi - 1); // Before pi
quickSort(arr, pi + 1, high); // After pi
}
}
int main() {
int arr[] = {10, 7, 8, 9, 1, 5};
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] << " ";
return 0;
}
Java Implementation
public class QuickSort {
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // Choosing the last element as pivot
int i = (low - 1); // Pointer for the smaller element
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++; // Increment index of smaller element
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1; // Return the partitioning index
}
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high); // Partitioning index
quickSort(arr, low, pi - 1); // Before pi
quickSort(arr, pi + 1, high); // After pi
}
}
public static void main(String[] args) {
QuickSort ob = new QuickSort();
int arr[] = {10, 7, 8, 9, 1, 5};
ob.quickSort(arr, 0, arr.length - 1);
System.out.println("Sorted array:");
for (int i : arr) {
System.out.print(i + " ");
}
}
}
Python Implementation
def partition(arr, low, high):
pivot = arr[high] # Choosing the last element as pivot
i = low - 1 # Pointer for the smaller element
for j in range(low, high):
if arr[j] < pivot:
i += 1 # Increment index of smaller element
arr[i], arr[j] = arr[j], arr[i] # Swap
arr[i + 1], arr[high] = arr[high], arr[i + 1] # Swap pivot
return i + 1 # Return the partitioning index
def quick_sort(arr, low, high):
if low < high:
pi = partition(arr, low, high) # Partitioning index
quick_sort(arr, low, pi - 1) # Before pi
quick_sort(arr, pi + 1, high) # After pi
arr = [10, 7, 8, 9, 1, 5]
quick_sort(arr, 0, len(arr) - 1)
print("Sorted array:", arr)
6. Heap Sort
Heap Sort is a comparison-based sorting algorithm that utilizes a binary heap data structure. It consists of two main phases:
Building a max heap from the input array.
Extracting elements from the heap one by one to produce a sorted array.
Key Concepts
Binary Heap: A complete binary tree where each node is greater than or equal to its children (in a max heap) or less than or equal to its children (in a min heap).
Heap Property: The value of each node is greater than or equal to the values of its children, ensuring that the maximum element is always at the root.
Algorithm Steps
Step 1: Build a Max Heap
Input: An unsorted array of
n
elements.Process:
Start from the last non-leaf node (at index
n/2 - 1
) and move towards the root (index0
).For each node, call the
heapify
function to maintain the max heap property.
Step 2: Sort the Array
Input: The max heap created from the previous step.
Process:
Swap the root (maximum element) with the last element of the heap.
Reduce the size of the heap by one (ignore the last element, which is now sorted).
Call
heapify
on the root of the heap to restore the max heap property.Repeat the process until the heap is empty.
Detailed Algorithm Steps
Heapify Function:
Define a function
heapify(arr, n, i)
that adjusts the heap to maintain the max heap property.Parameters:
arr[]
: The array representing the heap.n
: The size of the heap.i
: The index of the current node (subtree) being checked.
Operations:
Set
largest
asi
(current node).Calculate indices for the left (
2*i + 1
) and right (2*i + 2
) children.Compare the value of the current node with its children. If any child is greater than the current node, update
largest
.If
largest
is not equal toi
, swap the values ofarr[i]
andarr[largest]
, and recursively callheapify
on the affected subtree.
Heap Sort Function:
Define a function
heapSort(arr[])
.Operations:
Build a max heap by calling
heapify
for each non-leaf node (starting fromn/2 - 1
down to0
).Extract elements one by one:
Swap the root of the heap (maximum element) with the last element of the heap.
Call
heapify
on the root to maintain the max heap property.Decrease the heap size by one.
Example
Let’s consider an example array: [4, 10, 3, 5, 1]
.
Building the Max Heap
Start heapifying from the last non-leaf node (index
1
).- Compare
arr[1]
(10) with its childrenarr[3]
(5) andarr[4]
(1). No change needed.
- Compare
Move to index
0
(4).Compare
arr[0]
(4) with its childrenarr[1]
(10) andarr[2]
(3).10 is the largest, so swap
arr[0]
witharr[1]
:[10, 4, 3, 5, 1]
.Heapify at index
1
:- Compare
arr[1]
(4) with its children (no children in this case). No change needed.
- Compare
Final max heap: [10, 4, 3, 5, 1]
.
Sorting the Array
Swap the root with the last element:
[1, 4, 3, 5, 10]
.Heapify the root:
Compare
1
with its children (4
and3
).Swap with
4
:[4, 1, 3, 5, 10]
.Heapify at index
1
: No changes needed (only one child).
Repeat:
Swap
[4, 1, 3, 5]
with1
:[3, 1, 4, 5, 10]
.Heapify: Swap
3
and1
:[3, 1, 4]
.Swap
[3, 1]
with1
:[1, 3, 4, 5, 10]
.The final sorted array is
[1, 3, 4, 5, 10]
.
C/C++ Implementation
#include <iostream>
using namespace std;
// Function to maintain the max heap property
void heapify(int arr[], int n, int i) {
int largest = i; // Initialize largest as root
int left = 2 * i + 1; // left child index
int right = 2 * i + 2; // right child index
// If left child is larger than root
if (left < n && arr[left] > arr[largest])
largest = left;
// If right child is larger than largest so far
if (right < n && arr[right] > arr[largest])
largest = right;
// If largest is not root
if (largest != i) {
swap(arr[i], arr[largest]); // Swap
heapify(arr, n, largest); // Recursively heapify the affected subtree
}
}
// Function to perform heap sort
void heapSort(int arr[], int n) {
// Build a max heap
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// One by one extract elements from heap
for (int i = n - 1; i >= 0; i--) {
swap(arr[0], arr[i]); // Move current root to end
heapify(arr, i, 0); // Call max heapify on the reduced heap
}
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
heapSort(arr, n);
cout << "Sorted array: ";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
Java Implementation
public class HeapSort {
// Function to maintain the max heap property
void heapify(int arr[], int n, int i) {
int largest = i; // Initialize largest as root
int left = 2 * i + 1; // left child index
int right = 2 * i + 2; // right child index
// If left child is larger than root
if (left < n && arr[left] > arr[largest])
largest = left;
// If right child is larger than largest so far
if (right < n && arr[right] > arr[largest])
largest = right;
// If largest is not root
if (largest != i) {
int temp = arr[i];
arr[i] = arr[largest];
arr[largest] = temp;
heapify(arr, n, largest); // Recursively heapify the affected subtree
}
}
// Function to perform heap sort
void heapSort(int arr[]) {
int n = arr.length;
// Build a max heap
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// One by one extract elements from heap
for (int i = n - 1; i >= 0; i--) {
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
heapify(arr, i, 0); // Call max heapify on the reduced heap
}
}
public static void main(String[] args) {
HeapSort ob = new HeapSort();
int arr[] = {64, 25, 12, 22, 11};
ob.heapSort(arr);
System.out.println("Sorted array:");
for (int i : arr) {
System.out.print(i + " ");
}
}
}
Python Implementation
def heapify(arr, n, i):
largest = i # Initialize largest as root
left = 2 * i + 1 # left child index
right = 2 * i + 2 # right child index
# If left child is larger than root
if left < n and arr[left] > arr[largest]:
largest = left
#
4o mini