Sorting Foundations

7 concept walkthroughs, each with a worked explanation and an interactive visualization, before you start solving problems in this area.

What is Sorting?

Sorting is the process of arranging items in a specific order: usually from smallest to largest (ascending) or largest to smallest (descending). Think of organizing books on a shelf by height, or arranging playing cards in your hand from lowest to highest.

The intuition

Imagine you have a messy pile of numbered cards. Sorting means rearranging them so you can quickly find any card. Without sorting, finding a specific card requires checking every single one. With sorting, you can use smarter search techniques!

When to use it

A real-world analogy

Think of a library. Books are sorted by category, then by author name. This organization lets you find any book quickly instead of searching randomly through thousands of books!

Bubble Sort

Bubble Sort works by repeatedly stepping through the list, comparing adjacent elements, and swapping them if they're in the wrong order. The largest elements 'bubble up' to the end of the list, like air bubbles rising to the surface of water.

The intuition

Imagine you're in a line of people sorted by height. You compare yourself with the person next to you. If you're taller, you swap places. Keep doing this until the tallest person reaches the end. Then repeat for the remaining people!

Time complexity

BestO(n) - when already sorted
AverageO(n²)
WorstO(n²)

Space complexity: O(1) - in-place sorting

When to use it

A real-world analogy

Like bubbles in soda rising to the top! Heavy (larger) elements sink to their correct position while lighter ones bubble up.

for i from 0 to n-1:
    for j from 0 to n-i-1:
        if arr[j] > arr[j+1]:
            swap(arr[j], arr[j+1])

Selection Sort

Selection Sort divides the array into sorted and unsorted parts. It repeatedly finds the MINIMUM element from the unsorted part and moves it to the end of the sorted part. You're literally 'selecting' the smallest remaining element each time.

The intuition

Imagine picking players for a team. Each round, you look at all remaining players and SELECT the best one. After each selection, that player joins your team (sorted part), and you repeat with the remaining players.

Time complexity

BestO(n²)
AverageO(n²)
WorstO(n²)

Space complexity: O(1) - in-place sorting

When to use it

A real-world analogy

Like organizing a hand of cards by repeatedly finding the lowest card and moving it to the front of your 'sorted' pile.

for i from 0 to n-1:
    minIndex = i
    for j from i+1 to n:
        if arr[j] < arr[minIndex]:
            minIndex = j
    swap(arr[i], arr[minIndex])

Insertion Sort

Insertion Sort builds the sorted array one element at a time. For each new element, it finds the correct position in the already-sorted part and INSERTS it there, shifting other elements as needed. Like sorting playing cards in your hand!

The intuition

When you're dealt cards one by one, you insert each new card into its correct position among the cards you already hold. You don't re-sort all cards: you just slide the new one into place!

Time complexity

BestO(n) - when already sorted
AverageO(n²)
WorstO(n²) - when reverse sorted

Space complexity: O(1) - in-place sorting

When to use it

A real-world analogy

Exactly like sorting playing cards in your hand! You pick up each card and slide it into its correct position among the cards you're already holding.

for i from 1 to n-1:
    key = arr[i]
    j = i - 1
    while j >= 0 and arr[j] > key:
        arr[j+1] = arr[j]  // shift right
        j = j - 1
    arr[j+1] = key  // insert

Merge Sort

Merge Sort uses the 'Divide and Conquer' strategy. It divides the array into two halves, recursively sorts each half, and then MERGES the sorted halves back together. The magic happens in the merge step, combining two sorted arrays is very efficient!

The intuition

Imagine sorting a deck of cards by splitting it in half, sorting each half separately (by splitting again and again), and then merging the sorted halves back together. Merging two sorted piles is easy. Just always take the smaller card from the top of either pile!

Time complexity

BestO(n log n)
AverageO(n log n)
WorstO(n log n)

Space complexity: O(n) - needs extra array for merging

When to use it

A real-world analogy

Like organizing a library by sections. Split books into genres, sort each genre, then merge genre sections into one organized library. Merging is easy because each genre is already sorted!

mergeSort(arr, left, right):
    if left < right:
        mid = (left + right) / 2
        mergeSort(arr, left, mid)
        mergeSort(arr, mid+1, right)
        merge(arr, left, mid, right)

Quick Sort

Quick Sort also uses 'Divide and Conquer', but differently. It picks a PIVOT element and partitions the array so all smaller elements go left and larger go right. Then it recursively sorts the left and right parts. The partitioning is the key step!

The intuition

Imagine organizing people by height. Pick one person as the 'pivot'. Everyone shorter goes to the left, everyone taller goes to the right. Now the pivot is in the correct position! Repeat this process for the left and right groups.

Time complexity

BestO(n log n)
AverageO(n log n)
WorstO(n²) - bad pivot choices

Space complexity: O(log n) - recursive call stack

When to use it

A real-world analogy

Like organizing a group photo by height. Pick someone in the middle, put shorter people on their left, taller on their right. That person is now in the right spot! Repeat for each group.

quickSort(arr, low, high):
    if low < high:
        pivotIndex = partition(arr, low, high)
        quickSort(arr, low, pivotIndex - 1)
        quickSort(arr, pivotIndex + 1, high)

partition(arr, low, high):
    pivot = arr[high]
    i = low - 1

    FOR j FROM low TO high - 1:
        IF arr[j] < pivot:
            i = i + 1
            swap arr[i] and arr[j]

    swap arr[i + 1] and arr[high]
    return i + 1

Which Sorting Algorithm to Use?

Each sorting algorithm has its strengths. For small arrays, simple algorithms like Insertion Sort work great. For large arrays, Merge Sort or Quick Sort are better. The 'best' algorithm depends on your data size, whether it's nearly sorted, and memory constraints.

The intuition

There's no single 'best' sorting algorithm, it depends on the situation! It's like choosing transportation: walking is fine for short distances, but you'd take a car for longer trips and a plane for cross-country travel.

When to use it

A real-world analogy

Choosing the right tool for the job! A hammer is perfect for nails but terrible for screws. Similarly, each sorting algorithm excels in specific situations.

All DSA learning paths