Exercises for Data Structures and Algorithms: Sorting module of apprenticeship
Run npm install before doing anything. Testing requires mocha and chai packages, and the tests themselves rely on the deep-equal package for comparing arrays.
I couldn't suss out implementing merge sort myself, mainly as I havne't done much recursion before, so I found an example online. It's merge-sort3.js .
In that script there are two functions, one which goes through recursion and calls on the other function.
The second function that's called on by an outer function is called merge
. This takes in two sorted arrays and pushes elements into a sorted resultArray.
The mergeSort
function undergoes recursion and takes in an unsorted array. As recursion happens, the input goes from the full input array to halves, and halves of halves etc. To stop recursion happening forever there's a 'base condition' which, when true, will stop recursion. I.E, your function returns a value if that condition is true. In the case of mergeSort
the base condition is unsortedArray.length <= 1. unsortedArray.length <= 1 becomes true after an array is split and one of the products is a single element array. This means if everything is completely split, no more splitting is attempted (won't go on infinitely)
When the function is first called it is passed a long unsorted array. As its length is >1 it is split into two. The left and right arrays it is split into are passed into the merge
function, BUT are arguments in another invocation of the mergeSort
function. This means that merge will not properly start until the mergeSort
function returns a value. This first occurs when the base condition is true, i.e. when splitting has produced a single element array. That means that merging begins - you get 2 element arrays made. Crucially, where merge
is called inside mergeSort
the output of merge
is returned. So, when merge
completes and returns a merged, sorted array, mergeSort
returns that merged, sorted array. And because all the arguments being passed into merge
are calls to mergeSort
, it means everything starts merging from the bottom upwards.
The thing I was missing from my versions of merge sort was the ability to return up the tree, which is achieved here by passing calls to the recusive function as arguments for the merging function.
Select second element of the array
If element to the left of the selected element is larger or equal to value, swap their positions
continue this process until the number reaches the start of the array or its neightbour to the left is a smaller value
Select third element and repeat
You then move up through the levels of the tree and make pairwise comparisons of sorted arrays. You compare the first elements of each array being merged to find the smallest value, and place the smallest value to the end of the output/merged array from that pairwise comparison.
The single element arrays at the bottom are sorted, and this algorithm depends on the fact that all arrays being merged together are already sorted. This is what makes the comparison of the first elements a valid approach.
Example:
Three levels deep into the tree
Merge 1: [ [4],[3] ] => compare 4 to 3 and get output [3,4]
Two levels deep into the tree
Merge 1: [ [1],[5] ] => compare 1 to 5 and get output [1,5]
Merge 2: [ [2],[3,4] ]
1 level deep into the tree
Merge 1: [ [1,5],[2,3,4] ]