advertisement

Sorting Algorithms

A comprehensive guide to understanding how different sorting algorithms work, their time complexities, and when to use each one.

Introduction

Sorting is one of the most fundamental operations in computer science. A sorting algorithm arranges elements in a specific order, typically ascending or descending. Understanding these algorithms is crucial for:

  • Building efficient applications
  • Preparing for technical interviews
  • Understanding algorithm design principles
  • Choosing the right tool for specific problems

Bubble Sort

How It Works

Bubble Sort repeatedly steps through the list, compares adjacent elements, and swaps them if they're in the wrong order. The pass through the list is repeated until no swaps are needed.

JavaScript
function bubbleSort(arr) {
    const n = arr.length;
    for (let i = 0; i < n - 1; i++) {
        for (let j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // Swap elements
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
            }
        }
    }
    return arr;
}
Time Complexity (Best) O(n)
Time Complexity (Worst) O(n²)
Space Complexity O(1)

Selection Sort

How It Works

Selection Sort divides the array into sorted and unsorted parts. It repeatedly selects the minimum element from the unsorted part and moves it to the beginning of the unsorted part.

JavaScript
function selectionSort(arr) {
    const n = arr.length;
    for (let i = 0; i < n - 1; i++) {
        let minIdx = i;
        for (let j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIdx]) {
                minIdx = j;
            }
        }
        if (minIdx !== i) {
            [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]];
        }
    }
    return arr;
}
Time Complexity O(n²)
Space Complexity O(1)

Insertion Sort

How It Works

Insertion Sort builds the sorted array one element at a time. It picks each element and inserts it into its correct position in the already sorted part of the array.

JavaScript
function insertionSort(arr) {
    const n = arr.length;
    for (let i = 1; i < n; i++) {
        let key = arr[i];
        let j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
    return arr;
}
Time Complexity (Best) O(n)
Time Complexity (Worst) O(n²)
Space Complexity O(1)

Quick Sort

How It Works

Quick Sort uses divide-and-conquer. It selects a 'pivot' element and partitions the array around it, placing smaller elements before and larger elements after the pivot, then recursively sorts the sub-arrays.

JavaScript
function quickSort(arr, low = 0, high = arr.length - 1) {
    if (low < high) {
        const pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
    return arr;
}

function partition(arr, low, high) {
    const pivot = arr[high];
    let i = low - 1;
    for (let j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            [arr[i], arr[j]] = [arr[j], arr[i]];
        }
    }
    [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
    return i + 1;
}
Time Complexity (Best/Avg) O(n log n)
Time Complexity (Worst) O(n²)
Space Complexity O(log n)

Merge Sort

How It Works

Merge Sort divides the array into halves, recursively sorts them, and then merges the sorted halves. It's a stable, divide-and-conquer algorithm with consistent O(n log n) performance.

JavaScript
function mergeSort(arr) {
    if (arr.length <= 1) return arr;
    
    const mid = Math.floor(arr.length / 2);
    const left = mergeSort(arr.slice(0, mid));
    const right = mergeSort(arr.slice(mid));
    
    return merge(left, right);
}

function merge(left, right) {
    const result = [];
    let i = 0, j = 0;
    while (i < left.length && j < right.length) {
        if (left[i] <= right[j]) {
            result.push(left[i++]);
        } else {
            result.push(right[j++]);
        }
    }
    return result.concat(left.slice(i)).concat(right.slice(j));
}
Time Complexity O(n log n)
Space Complexity O(n)

Algorithm Comparison

Algorithm Best Average Worst Space Stable
Bubble Sort O(n) O(n²) O(n²) O(1)
Selection Sort O(n²) O(n²) O(n²) O(1)
Insertion Sort O(n) O(n²) O(n²) O(1)
Quick Sort O(n log n) O(n log n) O(n²) O(log n)
Merge Sort O(n log n) O(n log n) O(n log n) O(n)

When to Use Which?

  • Small arrays (n < 50): Insertion Sort - simple and efficient
  • Nearly sorted data: Insertion Sort - O(n) best case
  • General purpose: Quick Sort - excellent average performance
  • Need stability: Merge Sort - consistent O(n log n)
  • Limited memory: Heap Sort or Quick Sort - O(1) or O(log n) space