Skip to content

Insertion Sort

OperationMethodTimeAdaptive?In-Place?Stable?Online?
Insertion sortInsertion, IncrementalTw(n)=Θ(n2)YYYY

Idea

Insertion sort is a simple sorting algorithm that works similar to the way you sort playing cards in your hands. The array is virtually split into a sorted and an unsorted part. Values from the unsorted part are picked and placed at the correct position in the sorted part.

Insertion Sort

Incremental Technique

The array is virtually split into a k sorted and an A.lengthk unsorted part.

 int A [ ]={A[1,,j] k sorted elementsA[j+1,,A.length]A.length-k elements to sort

Initially, k=1. Our goal is to extend the sorted part of the array from k to k+1 by placing in the correct position an element from the unsorted section at each iteration.

In-Loco sorting

This algorithm sorts in-place, namely with an external additional space S(n)=O(1).

Adaptive

The algorithm is sensitive about the input's order, or better it is adaptive.

The Algorithm

Idea:

  • A first cycle to go through all the cards, a second one to
  • We start from an index i=2, since the first card is sorted for definition.

To sort an array of size n in ascending order:

  • 1: Iterate from arr[1] to arr[n] over the array.
  • 2: Compare the current element (key) to its predecessor.
  • 3: If the key element is smaller than its predecessor, compare it to the elements before. Move the greater elements one position up to make space for the swapped element.

Pseudocode:

python
insertion_sort(Array A)
    for j=2 TO A.length #Array starts from 1
        key = A[j]; 
        i = j-1; 
        while i > 0 AND A[i] > key #Modify predecessor when we find a smaller element
            A[i+1] = A[i];
            i = i-1;
        A[i+1] = key;
insertion_sort(Array A)
    for j=2 TO A.length #Array starts from 1
        key = A[j]; 
        i = j-1; 
        while i > 0 AND A[i] > key #Modify predecessor when we find a smaller element
            A[i+1] = A[i];
            i = i-1;
        A[i+1] = key;

Implementation in C and C++:

cpp
void insertion_sort_c(int *arr, int size){
    for(int j = 1; j<size; j++){
        int i = j-1;
        int key = *(arr+j);
        while(i>=0 && *(arr+i)> key){
            *(arr+i+1)= *(arr+i);
            i-=1;
        }
        *(arr+i+1)=key;
    }
}

void insertion_sort_cpp(std::vector<int> &array){
    for(int j = 1; j<array.size(); j++){
        int i = j-1;
        int key = array.at(j);
        while(i>=0 && array.at(i)>key){
            array.at(i+1) = array.at(i);
            i-=1;
        }
        array.at(i+1)=key;
    }
}
void insertion_sort_c(int *arr, int size){
    for(int j = 1; j<size; j++){
        int i = j-1;
        int key = *(arr+j);
        while(i>=0 && *(arr+i)> key){
            *(arr+i+1)= *(arr+i);
            i-=1;
        }
        *(arr+i+1)=key;
    }
}

void insertion_sort_cpp(std::vector<int> &array){
    for(int j = 1; j<array.size(); j++){
        int i = j-1;
        int key = array.at(j);
        while(i>=0 && array.at(i)>key){
            array.at(i+1) = array.at(i);
            i-=1;
        }
        array.at(i+1)=key;
    }
}

Invariant of the for-cycle

INVThe subarray A[1j1] is made of the sorted elements which were originally in A[1j1]

This is true:

  1. Initialization: This is trivially true before the for block
    1. By construction, j=2A[1]
  2. Preservation: It is respected before any iteration
  3. Conclusion: After the for block, j stops at j = A.length+1
    1. Then A[1j1] is sorted
    2. Which means A[1A.length+11] is made of the sorted elements which were originally in A[1A.length+11]

Complexity: Theorem - T(n)=Θ(n2)S(n)=O(1)

The insertion sort algorithm sorts in-place S(n)=O(1), and executes Θ(n2) comparisons in the worst case.

Demonstration - In loco

The algorithm sorts in-place as it only requires one additional variable aside from the input array.

Demonstration - Time complexity

The for cycle is executed exactly n1 times and the number of comparisons executed in the inner cycle (while), is j1 in the worst case.

  • We assume the comparisons to be the fundamental operation in this algorithm.
j=2n(j1)k=j1k=1n+1k=(n1)(n1+1)2=(n1)n2=Θ(n2)

Where n=A.length

Final Time Complexity = T(n)=Θ(n2)

  • Tbest(n)=Θ(n)
    • Array sorted in a non-decreasing manner
  • Tavg(n)=Θ(j/2)
  • Tworst(n)=Θ(n2)
    • Array sorted in a non-increasing manner

We conclude that the algorithm is sensitive about the input's order, or better it is adaptive.

Conclusions

Pros:

  • Works well with small vectors

Extra Credits