Algorithm

Take a list of length

We can iterate through the list, and for every iteration , we check if any value at index is greater than our value . We slide any element that to the right, and place in the newly created place.

  1. For the first iteration (3), we slide 4 to the right to obtain
  2. For the second iteration (1), we slide 3, 4 to the right
  3. For the third iteration (8), we slide nothing to the right
  4. For the fourth iteration (3), we slide 4, 8 to the right
  5. Finally, for the 5th iteration (2), we slide 3, 3, 4, 8 to the right

Note that after every iteration , the subarray to the left of is sorted. We slowly build this sorted array until we are done!

Pseudocode

Pseudocode for Insertion Sort is given below.

def insertion_sort(array):
    for i in range(1, len(array)):
        key = array[i] # cur value to insert
 
        # shift elements
        j = i - 1
        while j >= 0 and key < array[j]: 
              array[j + 1] = A[j]
              j -= 1
 
        array[j + 1] = k # insert 

Let’s find the time complexity of Insertion Sort. However, note that the while loop will run differently depending on different conditions in the array.

  • If the array is sorted, while’s body will not execute at all - the algorithm will run the fastest.
  • If the array is reverse sorted, while’s body will always execute - the algorithm will run the slowest.

Because of this, we will analyze the time complexity of Insertion Sort based on these best and worst case executions. Let indicate the runtime cost of line .

  • For the best case scenario (sorted array), we know that the while loop doesn’t execute - so, only lines contribute to the runtime (the while loop check at line 7 only occurs once).
  • For the worst case scenario (unsorted array), we assume the maximum iterations by the while loop, in that it will always run until . Thus, for every iteration , the while loop will run for total iterations ().

Notice that our time complexity depends on how sorted our array is! So, how can we measure an average time complexity for Insertion Sort?

We can do this using the concepts of inversions.

Inversion

For a list , an inversion is a pair of elements which is out of sorted order.

Observe that the number of inversions in a list gives a measurement of how sorted a list is.

  • If the list is sorted, the number of inversions is 0.
  • If the list is unsorted, the number of inversions is equal to every pair of indices, .

Let be the number of inversions in . Note that for every element shift we do, we fix one inversion. Thus, the number of times the while loop runs is equal to the number of inversions! This gives us runtime

So for an β€œaverage list”, we get , giving us the average time complexity of

Additionally, we find

  • The auxilliary memory to be .
  • The algorithm is stable, as our insertion sort will not shift elements that are equal.
  • The algorithm is in place, as it operates solely on the list itself.