Insertion sort
Algorithm
def insertion(a):
"""
Implements the insertion sort algorithm
"""
for i in range(0, len(a) - 1):
if a[i] < a[i+1]:
continue
insert_index = i+1
insert_element = a[i+1]
for j in range(i,-1,-1):
if a[j+1] < a[j]:
temp = a[j+1]
a[j+1] = a[j]
a[j] = temp
return a
def insertion2(a):
"""
Implements the insertion sort algorithm.
"""
if len(a) == 1:
return a
for i in range(1, len(a)):
if a[i] > a[i-1]:
continue
for j in range(i,0,-1):
if a[j] < a[j-1]:
a[j], a[j-1] = a[j-1], a[j]
return a
Key concepts
- Insert the current element where it belongs.
- It will be inserted in an already sorted subarray.
- Start looking for a place to insert the element from the current index and move towards the beginning of the array.
Step by step
array = [1,0,3,4,2,5]
i = 0
a[0] < a[1] | 1 < 0 | False
insert_index = 1
insert_element = 0
j = 0
a[1] < a[0] | 0 < 1 | True
temp = a[1] | temp = 0
a[1] = a[0] | a[1] = 1
a[0] = temp | a[0] = 0
array = [0,1,3,4,2,5]
i = 1
a[1] < a[2] | True
array = [0,1,3,4,2,5]
i = 2
a[2] < a[3] | 3 < 4 | True
array = [0,1,3,4,2,5]
i = 3
a[3] < a[4] | 4 < 2 | False
insert_index = 4
insert_element = 2
j = 3
a[4] < a[3] | 2 < 4 | True
temp = a[4] | temp = 2
a[4] = a[3] | a[4] = 4
a[3] = temp | a[3] = 2
array = [0,1,3,2,4,5]
j = 2
a[3] < a[2] | 2 < 3 | True
temp = a[3] | temp = 2
a[3] = a[2] | a[3] = 3
a[2] = temp | a[2] = 2
array = [0,1,2,3,4,5]
j = 1
a[2] < a[1] | 2 < 1 | False
j = 0
a[1] < a[0] | 1 < 0 | False
array = [0,1,2,3,4,5]
i = 4
a[4] < a[5] | 4 < 5 | True
Complexity analysis
Time
For each element of the array, we compare it with all the previous elements of the array. This gives us 1 in the best case and N in the worst case. This gives us N/2 in the average case. So O(N) = N (N/2) = N²/2.
One could further argue that half of the times (for the average case) the elements we are comparing are already sorted and thus there is no need to do the insertion part of the algorithm with the N²/2 cost. In that case, we can write the computational cost as: O(N) = (1/2)(N²/2) = (N²/4)
Space
We use the same array that is passed as argument and a few more variables, so the cost is: O(N) = N + K ≈ N.
Use cases
This algorithm is specially useful for arrays that are:
- Partially sorted
- Tiny
Examples:
- Array where each entry is not far from its final position
- Arrays in which only a few entries are not sorted
- Arrays that are a concatenation of two sorted arrays