Analyzing the Recursive Version

Let’s analyze the recursive merge sort the same way we analyzed the bottom-up one: time first, then space.

Time

Here is a diagram of the work recursive merge sort does. Each row is a level of the recursion: the top is the whole array, and each level below splits every subarray in half, down to single elements.

level 0:            [ . . . . . . . . ]        one piece  of size n
level 1:        [ . . . . ]   [ . . . . ]      two pieces of size n/2
level 2:      [ . . ] [ . . ] [ . . ] [ . . ]  four pieces of size n/4
   ...
last level:   [.] [.] [.] [.] [.] [.] [.] [.]  n pieces of size 1

Now think about the merging work that happens on the way up, one level at a time. The merges at a single level work on subarrays that do not overlap, and together those subarrays cover the whole array, so all the merges at one level together cost $O(n)$. That is the same observation we made for the bottom-up version, where each pass cost . A level of the recursion corresponds to a pass.

How many levels are there? We start at size and halve until we reach size . Halving down to takes steps, so there are about levels. We have seen this in binary search too.

That is work per level times levels, so the running time is , the same as the bottom-up version.

Space

As before, we split this into input space and auxiliary space.

The input space is : the array we are sorting.

There are two things to count in the auxiliary space now.

The first is the same as before: the temporary array that merge creates. The merges still run one at a time, because merge is only called after the recursive calls return, and it finishes before the next merge begins. So this part is still .

The second is new: the call stack. When we studied space complexity, we saw that a recursive method’s stack frames count toward its space, and that the cost depends on the maximum depth of the call stack. So we need the maximum depth here. The recursion goes down one level at a time, so at most about frames are on the stack at once. That part is .

Adding them up, the auxiliary space is . The term dominates, so the auxiliary space is , and the total space is as well. That is asymptotically the same as the bottom-up version.

In practice, the call stack has a fixed size limit, and a recursive method whose recursion depth is much larger than can reach that limit.

Recurrence relations

If you go on to an algorithms course, you will see a more formal way to analyze the complexity of a recursive algorithm like this. You will write its cost as an equation that refers to itself, called a recurrence relation. For merge sort it looks like this:

This says that sorting elements costs two half-sized sorts plus an merge. There is a standard tool, the Master Theorem, that solves recurrences of this form. In this case it gives , the same answer we reached by counting work level by level.

We will not use recurrence relations or the Master Theorem in this course.