Insertion Sort Algorithm with C, C++, Java, Python Examples
⚡ Smart Summary
Insertion Sort is a comparison-based, in-place sorting method that constructs a sorted list one element at a time. It is stable, adaptive, simple to implement, and well-suited for small or nearly sorted data sets in practice.
What is Insertion Sort?
Insertion Sort is one of the comparison sort algorithms used to sort elements by iterating on one element at a time and placing the element in its correct position within an already ordered region.
Each element is sequentially inserted into an already sorted list. The size of the already sorted list initially is one. The Insertion Sort algorithm ensures that the first k elements are sorted after the kth iteration of the outer loop.
Because Insertion Sort builds the result incrementally, it is intuitive to teach, easy to debug, and a strong baseline for very small inputs where more complex algorithms would add overhead without measurable gains.
Characteristics of Insertion Sort Algorithm
The algorithm for Insertion Sort has the following important characteristics that explain its behaviour on real workloads:
- It is a stable sorting technique, so it does not change the relative order of equal elements.
- It is efficient for smaller data sets but not effective for larger lists where quadratic growth dominates.
- Insertion Sort is adaptive, which reduces its total number of steps if the input is partially sorted. An Array is provided as input to make it efficient because random access enables constant-time shifts during the inner loop.
- It is an in-place algorithm, so it does not require auxiliary storage proportional to the input size.
With these traits in mind, the next section explains the core insert operation that powers every pass of the algorithm.
How does Insert Operation work?
In the Insertion Sort algorithm, the insert operation is used to sort unsorted elements. It helps insert a new element into an already sorted list while preserving the existing order of the sorted region.
Pseudocode of the insert operation:
Consider a list A of N elements.
// Insert A[N-1] into sorted sublist A[0..N-2] for i = N-1 to 1: if A[i] < A[i-1], then swap A[i] and A[i-1] else stop
In the above example, a new element 6 is inserted into an already sorted list. The following steps trace the inner loop as the new element migrates left toward its correct position.
Step 1) Compared with the left adjacent element of A[5], 9 > 6, we swap the position of 9 and 6. Now element 6 is moved to A[4].
Step 2) Now, we compare A[4] and A[3], and we find that A[3] > A[4], so we again swap the position of 6 and 8.
Step 3) Now compare A[3] and A[2]. As A[2] > A[3], we swap the position of 7 and 6.
Step 4) We compare A[1] and A[2]. As A[1] < A[2], the left adjacent element is no longer greater. We conclude that 6 is inserted correctly, and we stop the inner loop here.
How the Insertion Sort Works
The insert operation discussed above is the backbone of Insertion Sort. The insert procedure is executed on every element, and at the end, we get the sorted list as the sorted region grows by one element on every outer pass.
The figure above demonstrates the working of Insertion Sort in a data structure. Initially, only one element is in the sorted sublist, i.e., 4. After inserting A[1], i.e., 3, the size of the sorted sublist grows to 2, and the algorithm continues this pattern until every element has been placed.
With the conceptual flow in place, the following sections show concrete implementations in C++, C, and Python so you can compare loop structures across languages.
C++ Program for Insertion Sort
The C++ implementation below uses two nested loops: the outer loop selects the next unsorted element, and the inner loop shifts it left until the correct position is found.
#include <iostream> using namespace std; int main(){ //unsorted list int unsorted[] = {9,8,7,6,5,4,3,3,2,1}; //size of list int size_unsorted = sizeof(unsorted) / sizeof(unsorted[0]); //printing unsorted list cout << "\nUnsorted: "; for(int i = 0 ; i < size_unsorted ; i++){ cout << unsorted[i] << " "; } int current_element,temp; for(int i = 1; i < size_unsorted; i++){ current_element = unsorted[i]; for(int j = i-1; j >= 0 && unsorted[j] > current_element; j--){ //swapping if current element is lesser temp = unsorted[j+1]; unsorted[j+1] = unsorted[j]; unsorted[j] = temp; } } //printing sorted list cout << "\nSorted: "; for(int i = 0 ; i < size_unsorted ; i++){ cout << unsorted[i] << " "; } return 0; }
Output:
Unsorted: 9 8 7 6 5 4 3 3 2 1 Sorted: 1 2 3 3 4 5 6 7 8 9
C Code for Insertion Sort
The same logic translates directly to C. The standard printf calls replace stream output, but the swap pattern inside the inner loop is identical to the C++ version.
#include <stdio.h> int main() { //unsorted list int unsorted[] = {9,8,7,6,5,4,3,3,2,1}; //size of list int size_unsorted = sizeof(unsorted) / sizeof(unsorted[0]); //printing unsorted list printf("\nUnsorted: "); for(int i = 0 ; i < size_unsorted ; i++){ printf("%d ", unsorted[i]); } int current_element, temp; for(int i = 1; i < size_unsorted; i++){ current_element = unsorted[i]; for(int j = i-1; j >= 0 && unsorted[j] > current_element; j--){ //swapping if current element is lesser temp = unsorted[j+1]; unsorted[j+1] = unsorted[j]; unsorted[j] = temp; } } //printing sorted list printf("\nSorted: "); for(int i = 0 ; i < size_unsorted ; i++){ printf("%d ", unsorted[i]); } return 0; }
Output:
Output: Unsorted: 9 8 7 6 5 4 3 3 2 1 Sorted: 1 2 3 3 4 5 6 7 8 9
Python Program for Insertion Sort
Python supports tuple swapping in a single expression, so the inner loop is more compact than its C and C++ counterparts while preserving the same algorithmic behaviour.
#unsorted list unsorted = [9,8,7,6,5,4,3,3,2,1] #size of list size_unsorted = len(unsorted) #printing unsorted list print("\nUnsorted: ", end="") for i in range(size_unsorted): print(unsorted[i], end=" ") for i in range(1, size_unsorted): current_element = unsorted[i] j = i - 1 while j >= 0 and unsorted[j] > current_element: #swapping if current element is lesser unsorted[j+1], unsorted[j] = unsorted[j], unsorted[j+1] j -= 1 #printing sorted list print("\nSorted: ", end="") for i in range(size_unsorted): print(unsorted[i], end=" ")
Output:
Unsorted: 9 8 7 6 5 4 3 3 2 1 Sorted: 1 2 3 3 4 5 6 7 8 9
Properties of Insertion Sort
Here are important properties of Insertion Sort that help you decide when it is the right tool:
- Online: Insertion Sort can sort elements as it receives them. If we have already sorted a list of elements and append more elements to the list, then we do not need to run the entire sorting procedure again. Instead, we only iterate on the newly added elements.
- In-place: The space complexity of the Insertion Sort algorithm is constant and does not require extra space. This algorithm sorts elements in place.
- Stable: In Insertion Sort, we do not swap elements if their values are equal. For example, if two elements, x and y, are equal and x appears before y in the unsorted list, then in the sorted list, x will still appear before y. This makes Insertion Sort stable.
- Adaptive: A sorting algorithm is adaptive if it takes less time when the input elements or a subset of elements are already sorted. As we discussed above, the best running time of Insertion Sort is O(N), and the worst running time is O(N^2). Insertion Sort is one of the adaptive sorting algorithms.
Complexity of Insertion Sort
The complexity discussion below covers both memory usage and run time so you can position Insertion Sort against alternatives such as Bubble Sort and Quick Sort.
Space Complexity
Insertion Sort does not require extra space to sort the elements. The space complexity is constant, i.e., O(1), because only a few temporary variables are used regardless of the input size.
Time Complexity
Because Insertion Sort iterates one element at a time, it requires N-1 passes to sort N elements. For each pass, it may make zero swaps if the elements are already sorted, or it may need many swaps if the elements are arranged in descending order.
- For pass 1, the minimum swaps required are zero, and the maximum swaps required are 1.
- For pass 2, the minimum swaps required are zero, and the maximum swaps required are 2.
- For pass N, the minimum swap required is zero, and the maximum swaps required are N.
- The minimum swap is zero, so the best time complexity is O(N) for iterating N passes.
- Total maximum swaps are (1+2+3+4+…+N) i.e., N(N+1)/2, so the worst time complexity is O(N^2).
Here is the important time complexity of Insertion Sort:
- Worst Case Complexity: O(n^2): Sorting an array in descending order when it is required to be ascending is the worst-case scenario.
- Best Case Complexity: O(n): The best case occurs when the array is already sorted; the outer loop runs n times, while the inner loop does not run at all. There are only n comparisons, so the complexity is linear.
- Average Case Complexity: O(n^2): This happens when the elements of the array occur in a jumbled order that is neither ascending nor descending.



