Inching Towards Insertion Sort

Most of the algorithms that we’ve been dealing with have been pretty slow, and seem inefficient. However, they tend to come up a lot in computer science courses and theoretical explanations because they are often used as the naive approach, or the simplest implementation of sorting a collection.
Today’s sorting algorithm is no different. In fact, some people think that this methodology of sorting is one of the most intuitive. We’re going to take a look at insertion sort, which you might already be familiar with, and may have used at some point in your life already. The interesting thing about insertion sort is that while it is not the most efficient, it always introduced in CS textbooks and lectures.
So why is this?
Well, this stems from the fact that insertion sort is one of the easier sorting algorithms to understand. In fact, the example that comes up quite often is sorting a hand of cards — you may not have even realized it, but the last time that you had a bunch of playing cards in your hand, there is a good chance that you were implementing some version of the insertion sort algorithm to sort the cards in your hand!
Let’s inch a little closer to this algorithm, and figure out what it’s all about.
Inspecting insertion sort
On a very basic level, an insertion sort algorithm contains the logic of shifting around and inserting elements in order to sort an unordered list of any size. The way that it goes about inserting elements, however, is what makes insertion sort so very interesting!

An insertion sort algorithm has two main aspects to it. It’s first important aspect has to do with how it’s structured.
The insertion sort algorithm maintains two subsets (often referred to as subsections or sublists) — a sorted subset, and an unsorted subset.
The second aspect has to do with how it iterates and sorts the collection of elements that it is given. Insertion sort will iterate through the unsorted subset, effectively “removing” it from the unsorted subset and subsequently “inserting” it into its correct, sorted spot in the sorted subset.
Let’s take a look at how this actually works:

In the example above, we start off with an unsorted collection. We can think of this as our hand of cards, which is currently in a big, jumbled mess and needs to be sorted. We’ll take the first element and start sorting based on that element. In other words, our first item is the first one that we “sort”. This now gives us two distinct collections: a sorted collection, and an unsorted collection.
Then, we’ll remove the first unsorted element, and add it to our sorted collection. In order to figure out where to put this new element, we’ll need to compare it to the single item in our sorted collection; if the item that we’re adding is larger than our single, sorted element, we’ll keep it at the same place that it is currently at, and mark it as sorted. However, in this example, the new element is smaller than our single, sorted element, we’ll move that item back to the first position in the collection, and shift the sorted element forward in the collection to make room for it.
That makes for a single iteration of insertion sort. Obviously, the list still isn’t sorted though! We’d need to continue this process for every single remaining unsorted element, and repeat the same steps as we finish iterating through the list.
In some ways, insertion sort is similar to another algorithm that we have already explored: selection sort. Both of these algorithms have one thing in common: they each maintain a concept of “sorted” elements and “unsorted” elements. However, they each do this in very different ways. This is much more clear with an example.
Let’s try our hand at using insertion sort to sort through a list of six numbers: 4, -31, 0, 99, 83, 1.

To start, our list will be unsorted. We already know that the first item is going to be moved over to our “sorted” subset, which means that, initially, only the number 4 is sorted.
To make it a little easier to see, we’ll use a red dividing line in this example to indicate the border between the sorted and unsorted collections.
Next, we’ll pull out the first unsorted element: -31. We want to add it to our sorted subset, so we’ll need to compare it to all the sorted items (we only have one right now, though!). Since -31 is smaller than 4, we’ll shift 4 into the next spot in the list, and move -31 into the spot that the number 4 was originally in.
Our sorted list now contains -31 and 4, in the correct, sorted order, as we would expect. We’ll do the same thing again, for the next unsorted element, 0. We’ll remove it from the sorted list, compare it to each of the sorted values, and move any elements that are larger in size to the right, in order to make room for the new element being added.

Effectively, once our first item is pulled out into the “sorted” subset, we continue the same process for every single unsorted item in the “unsorted” subset, until we have sorted the entire collection.
A deeper insertion sort inspection
Before we get into implementing insertion sort, it’ll be helpful to try and simplify it a bit to make it a little easier to actually write in code. We’ll can boil down this algorithm into to basic rules.

First, we must remember that whatever element is at index 0 to start off with will be our “sorted” subset — at least, initially. A helpful rule of thumb to remember is that if we only ever have one element, by definition, that element is considered sorted; this starts to make more sense if you think about it. If you only have one element, there’s no chance of anything being larger or smaller than it, so it’s sorted by default!
Second, as we iterate and expand through our “unsorted” subset, we’re slowly shifting over elements into our sorted subset with each iteration. This means one iteration shrinks the “unsorted” subset by removing and element and adding it to the “sorted” subset.
In other words, each iteration of insertion sort causes the sorted subset to grow, and the unsorted subset to shrink.
This might not make a ton of sense just yet, and that’s okay. In fact, I think it’ll be a whole lot easier to identify how this works and see it in action if we look at a quick visualization of insertion sort:

In the example above, one row represents the state of the inputted collection for each iteration of the sorting algorithm. Hopefully, it’s a bit more evident what’s going on here. In each iteration, one more element is considered “sorted”, which is indicated by the red squares. We can see that, with every iteration, there are more red, “sorted” elements, and fewer purple, “unsorted” elements. The number of items isn’t changing, of course — we’re just moving over a single unsorted element in each iteration, and adding it to the “sorted” subset. Notice the direction in which this flow is happening, too. We’ll come back to that in the next section, but you might already be able to see a pattern emerging here!
Okay, now that we have the two important rules under our belt, let’s get to the good stuff and actually write some code! Below is an adapted version of insertion sort in JavaScript, based on Rosetta Stone’s JS implementation. Here’s what our insertionSort algorithm might look like:









