×
By the end of this chapter you should be able to:
In the previous chapter, we learned about three algorithms for sorting an array of numbers in JavaScript: bubble sort, insertion sort, and selection sort. These algorithms are relatively beginner-friendly when it comes to sorting algorithms, but they're also not the most efficient: all of them are typically O(n2).
The algorithms we'll learn about in this chapter are more efficient. However, this efficiency comes at a cost, as the algorithms are a more complicated and tend to take more time to understand. But with time and after working out some examples, you should be able to explain merge sort and quick sort, in addition to the algorithms you already know!
A more complex algorithm for sorting an array of elements is merge sort. Before we see the algorithm, let's visualize how it works:
As you can see, the algorithm involves splitting the array into smaller subarrays. To be more precise, the algorithm is as follows:
Here is a nice GIF of the algorithm in action; you can also see an excellent visualization here
So how does the algorithm perform in terms of its time complexity? Once the array has been broken down into one-element subarrays, it takes O(n) comparisons to get two-element merged subarrays. From there, it takes O(n)
comparisons to get four-element merged subarrays, and so on. In total it takes O(log(n)) sets of O(n) comparisons, since the logarithm roughly measures how many times you can divide a number by 2 until you get a number that is 1 or less. Therefore, the time complexity for merge sort is O(n log(n)), which is significantly better than the complexity of bubble, insertion, and selection sort!
Even in the best case, merge sort is O(n log(n)). In the worst case, it's O(n log(n)) too. Basically, whenever you think about merge sort, you should think O(n log(n)).
When trying to implement merge sort, it's helpful to first write a function that takes two sorted arrays and merges them together. Merge sort then works by splitting the array in half, recursively calling itself on each half, and then using the merge helper to merge the two sorted halves back together.
Another more complex algorithm to use for sorting is quicksort. Unfortunately, quicksort is not the most intuitive of algorithms and has a wide range of implementations. Before continuing, check out this great video from Computerphile for a quick introduction to how quicksort works.
The algorithm is as follows:
Here is a nice GIF of the algorithm in action; you can also see an excellent visualization here
Like merge sort, quicksort typically runs at O(n log(n)), and even in the best case is O(n log(n)). But in the worst case - if the pivot is chosen to be the leftmost element and the array is already sorted, for instance - the runtime will be O(n2).
Also like merge sort, it's easiest to implement quicksort with the aid of a helper function. This function is responsible for taking an array, setting the pivot value, and mutating the array so that all values less than the pivot wind up to the left of it, and all values greater than the pivot wind up to the right of it. It's also helpful if this helper returns the index of where the pivot value winds up.
For example, if we call this function pivot
, and if we decide the pivot will always be the first element in the array, it should behave in the following way:
var arr = [4, 2, 5, 3, 6]; pivot(arr); // 2 arr; // [3, 2, 4, 5, 6];
In this code, the specifics of how the arr
variable gets mutated are not important. All that matters is that 4
winds up at index 2, with 3
and 2
to the left of it (in any order), and with 5
and 6
to the right of it (in any order).
As with the other sorting algorithms we've studied, the best way to try to understand merge sort and quicksort is to implement them yourself. Complete Part II of the exercises here.
When you're ready, move on to Arrays Revisited