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.
- For the first iteration (3), we slide 4 to the right to obtain
- For the second iteration (1), we slide 3, 4 to the right
- For the third iteration (8), we slide nothing to the right
- For the fourth iteration (3), we slide 4, 8 to the right
- 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.
Example: Inversions
For example, if we have , we have the following inversions. To find the number of inversions, find how many elements to the right of an index are out of place with the current index.
- For 4 at index 0, weβre out of order with 3, 1, 3, 2: .
- For 3 at index 1, weβre out of order with 1, 2:
- For 1 at index 2, weβre out of order with none of them to the right.
- For 8 at index 3, weβre out of order with 3, 2:
- For 3 at index 4, weβre out of order with 2:
We hvae a total of 9 inversions!
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.