Your Progress

17/30 completed

57% complete. Continue learning to master DSA!

Insertion Sort

Insertion sort is a simple sorting algorithm that builds the final sorted array one item at a time, similar to how people sort playing cards in their hands.

Key Takeaways

  • Insertion sort is adaptive, efficient for small data sets, and often used as part of more sophisticated algorithms
  • Time complexity: O(n²) worst and average case, O(n) best case (when array is already sorted)
  • Space complexity: O(1) as it sorts in-place
  • It's a stable sorting algorithm that preserves the relative order of equal elements
  • Works well for arrays that are already substantially sorted

How Insertion Sort Works

Insertion sort works by building a sorted array one element at a time. It takes one element from the input data in each iteration and finds its correct position within the sorted part by comparing with each element.

Algorithm Steps

  1. Start with the second element (assume the first element is already sorted)
  2. Compare the current element with the previous elements
  3. If the previous element is greater than the current element, move the previous element one position ahead
  4. Repeat step 3 until you find the correct position for the current element
  5. Place the current element in its correct position
  6. Repeat steps 2-5 for all elements in the array

Visual Example

Let's sort the array [12, 11, 13, 5, 6] using insertion sort:

Initial array: [12, 11, 13, 5, 6]

Pass 1:
- Consider 11
- 12 > 11, so move 12 ahead: [12, 12, 13, 5, 6]
- Place 11 in correct position: [11, 12, 13, 5, 6]

Pass 2:
- Consider 13
- 13 > 12, already in correct position: [11, 12, 13, 5, 6]

Pass 3:
- Consider 5
- 13 > 5, so move 13 ahead: [11, 12, 13, 13, 6]
- 12 > 5, so move 12 ahead: [11, 12, 12, 13, 6]
- 11 > 5, so move 11 ahead: [11, 11, 12, 13, 6]
- Place 5 in correct position: [5, 11, 12, 13, 6]

Pass 4:
- Consider 6
- 13 > 6, so move 13 ahead: [5, 11, 12, 13, 13]
- 12 > 6, so move 12 ahead: [5, 11, 12, 12, 13]
- 11 > 6, so move 11 ahead: [5, 11, 11, 12, 13]
- 5 < 6, so 6 is in correct position: [5, 6, 11, 12, 13]

Final sorted array: [5, 6, 11, 12, 13]

Implementing Insertion Sort

JavaScript Implementation

function insertionSort(arr) {
  const n = arr.length;
  
  // Start from the second element
  for (let i = 1; i < n; i++) {
    // Store the current element
    let current = arr[i];
    
    // Find the correct position for the current element
    let j = i - 1;
    while (j >= 0 && arr[j] > current) {
      // Move elements greater than current one position ahead
      arr[j + 1] = arr[j];
      j--;
    }
    
    // Place current element in its correct position
    arr[j + 1] = current;
  }
  
  return arr;
}

// Example usage
const array = [12, 11, 13, 5, 6];
console.log(insertionSort(array)); // Output: [5, 6, 11, 12, 13]

Python Implementation

def insertion_sort(arr):
    # Traverse through 1 to len(arr)
    for i in range(1, len(arr)):
        # Store the current element
        current = arr[i]
        
        # Find the correct position for the current element
        j = i - 1
        while j >= 0 and arr[j] > current:
            # Move elements greater than current one position ahead
            arr[j + 1] = arr[j]
            j -= 1
            
        # Place current element in its correct position
        arr[j + 1] = current
    
    return arr

# Example usage
array = [12, 11, 13, 5, 6]
print(insertion_sort(array))  # Output: [5, 6, 11, 12, 13]

C++ Implementation

#include <iostream>
#include <vector>

std::vector<int> insertionSort(std::vector<int> arr) {
    int n = arr.size();
    
    // Start from the second element
    for (int i = 1; i < n; i++) {
        // Store the current element
        int current = arr[i];
        
        // Find the correct position for the current element
        int j = i - 1;
        while (j >= 0 && arr[j] > current) {
            // Move elements greater than current one position ahead
            arr[j + 1] = arr[j];
            j--;
        }
        
        // Place current element in its correct position
        arr[j + 1] = current;
    }
    
    return arr;
}

int main() {
    std::vector<int> array = {12, 11, 13, 5, 6};
    std::vector<int> sorted = insertionSort(array);
    
    // Print the sorted array
    for (int num : sorted) {
        std::cout << num << " ";
    }
    // Output: 5 6 11 12 13
    
    return 0;
}

Time and Space Complexity

Time Complexity

  • Best Case: O(n) - When the array is already sorted
  • Average Case: O(n²) - When elements are in random order
  • Worst Case: O(n²) - When the array is sorted in reverse order

The time complexity depends on the input array configuration. Insertion sort performs well with small data sets or when the array is nearly sorted.

Space Complexity

  • Space Complexity: O(1) - Insertion sort is an in-place sorting algorithm
  • It only requires a single additional memory space for the temporary variable (current)

Advantages and Disadvantages

Advantages

  • Simple implementation: Easy to understand and code
  • Adaptive: Efficient for datasets that are already substantially sorted
  • Stable: Preserves the relative order of equal elements
  • In-place: Requires only O(1) extra space
  • Online: Can sort a list as it receives it
  • Efficient for small datasets: Low overhead makes it fast for small arrays

Disadvantages

  • Inefficient for large datasets: O(n²) time complexity makes it impractical for large arrays
  • Not suitable for reversed data: Performs poorly when elements are in reverse order
  • Requires shifting of elements: Each insertion may require many element shifts
  • Outperformed by more advanced algorithms: Merge sort, quick sort, and heap sort are more efficient for large datasets

Comparison with Other Sorting Algorithms

AlgorithmBest CaseAverage CaseWorst CaseSpaceStable
Insertion SortO(n)O(n²)O(n²)O(1)Yes
Selection SortO(n²)O(n²)O(n²)O(1)No
Bubble SortO(n)O(n²)O(n²)O(1)Yes
Merge SortO(n log n)O(n log n)O(n log n)O(n)Yes
Quick SortO(n log n)O(n log n)O(n²)O(log n)No

Compared to other sorting algorithms, insertion sort has the following characteristics:

  • More efficient than selection sort for partially sorted arrays
  • Similar to bubble sort but generally performs fewer comparisons
  • Less complex than merge sort and quick sort, but less efficient for large datasets
  • One of the few quadratic-time algorithms that is stable without requiring extra space
  • Used in practice for small arrays or as part of more complex algorithms like Shell sort

Practical Applications

When to Use Insertion Sort

  • Small datasets: When the array size is small (typically less than 20 elements)
  • Nearly sorted data: When most elements are already in the correct position
  • Online sorting: When you need to sort data as it arrives (insertion sort can process one element at a time)
  • Auxiliary algorithms: As part of more complex algorithms like Shell sort or QuickSort (for small partitions)
  • Limited memory environments: When memory usage needs to be minimized

Real-World Scenarios

  • Card sorting: Mimics how people sort playing cards in their hands
  • Real-time data processing: For continuously arriving data that needs to be maintained in sorted order
  • Library book sorting: When librarians place new books in the correct position on a shelf
  • Embedded systems: Where resources are limited and data sets are small
  • Hybrid sorting algorithms: TimSort (used in Python and Java) uses insertion sort for small subarrays

Optimization: Binary Insertion Sort

Binary insertion sort is an optimization of insertion sort that uses binary search to find the correct position for inserting elements, reducing the number of comparisons.

Implementation

function binarySearch(arr, target, start, end) {
  if (start > end) return start;
  
  const mid = Math.floor((start + end) / 2);
  
  if (arr[mid] === target) return mid;
  
  if (arr[mid] > target) {
    return binarySearch(arr, target, start, mid - 1);
  } else {
    return binarySearch(arr, target, mid + 1, end);
  }
}

function binaryInsertionSort(arr) {
  const n = arr.length;
  
  for (let i = 1; i < n; i++) {
    const current = arr[i];
    const j = i - 1;
    
    // Find location where current should be inserted using binary search
    const location = binarySearch(arr, current, 0, j);
    
    // Move all elements after location one position ahead
    for (let k = j; k >= location; k--) {
      arr[k + 1] = arr[k];
    }
    
    // Place current at its correct location
    arr[location] = current;
  }
  
  return arr;
}

Binary insertion sort reduces the number of comparisons to O(n log n), but the number of shifts remains O(n²) in the worst case. It's beneficial when comparison operations are significantly more expensive than shift operations.

Conclusion

Insertion sort is a simple, efficient, and adaptive sorting algorithm that works well for small datasets and partially sorted arrays. While it's not suitable for large datasets due to its quadratic time complexity, its simplicity, stability, and small constant factors make it valuable in certain scenarios.

Key Points to Remember

  • Insertion sort is efficient for small datasets and nearly sorted arrays
  • It's an adaptive algorithm that performs better as the input array becomes more sorted
  • As a stable, in-place algorithm, it preserves relative order and uses minimal extra space
  • Binary insertion sort can reduce comparisons, but not shifts
  • For large datasets, consider using more advanced algorithms like merge sort or quick sort

Next Steps

To continue your learning about sorting algorithms, explore these related topics:

Related Tutorials

Related Tutorials

Selection Sort

Compare with another elementary sorting algorithm.

Learn more

Bubble Sort

Another simple sorting algorithm with similar complexity.

Learn more

Merge Sort

A more efficient divide-and-conquer sorting algorithm.

Learn more