Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 35

Merge Sort: Analyzing O(n log n) Complexity

Recommended resources

Introduction

Hello! In the last lesson, you successfully implemented Merge Sort, a powerful sorting algorithm based on the "divide and conquer" strategy. You saw how it recursively splits a list into single elements and then merges them back into a final, sorted list.

Today, we're going to answer a crucial question: why is Merge Sort so efficient? You've heard it's an O(n log n) algorithm, which is significantly better than the O(n²) of insertion sort, especially for large lists. In this lesson, we will analyze the O(n log n) time complexity of merge sort. We'll break down where the n and the log n components come from, giving you a deep, analytical understanding of its performance. Given your math background, we'll connect the visual intuition of the algorithm to a more formal mathematical analysis.


1. Breaking Down O(n log n)

The O(n log n) complexity isn't arbitrary; it comes directly from the two main phases of the algorithm:

  1. The log n part: This arises from the recursive "divide" step.
  2. The n part: This comes from the "combine" step, where we merge the sorted halves.

Let's investigate each part, starting with log n.

The log n Component: The Depth of Recursion

The "divide" step of Merge Sort repeatedly splits the input list in half. The number of times you can halve a list of size n until you get down to lists of size 1 is precisely log₂(n).

To build a strong intuition for this, let's first consider a different problem.

Breaking Down MergeSort. And Understanding O(N log N)

The article 'Breaking Down MergeSort' provides an excellent analogy for understanding the difference between O(n) and O(log n) time. This will help clarify where the log n in Merge Sort's complexity comes from.

Read the section titled 'O(log N) v O(N)'. Pay close attention to the dictionary example. It clearly contrasts a linear search (reading page by page, O(n)) with a binary search (repeatedly halving the search space, O(log n)).

As the article explains, repeatedly cutting the problem in half is a logarithmic process. Merge Sort does exactly this. An array of 8 elements is split into two arrays of 4, which are split into four arrays of 2, which are finally split into eight arrays of 1. This took 3 levels of splits, and log₂(8) = 3.

This means the depth of our recursion tree is log n.

The n Component: The Work at Each Level

Now, where does the n come from? It represents the work done in the "combine" or merge phase.

Recall the merge function you wrote. It takes two sorted sub-lists and combines them into one. To do this, it must look at every element in both sub-lists exactly once. Therefore, merging two lists with a total of k elements takes O(k) time.

The key insight for Merge Sort's analysis is that at every level of recursion, the total work done by merging adds up to O(n).

Let's visualize this:

  • Level 1 (Top): We merge two lists of size n/2. Total elements merged: n/2 + n/2 = n. Work: O(n).
  • Level 2: We perform two separate merges, each on lists of size n/4. Total elements merged: (n/4 + n/4) + (n/4 + n/4) = n. Work: O(n).
  • Bottom Level: We perform n/2 merges, each on lists of size 1. Total elements merged: n/2 * (1 + 1) = n. Work: O(n).

No matter which level you're on, the total number of elements being processed across all merges is n.

This video provides a fantastic visualization of this concept.

Big O Notation Series #9: Understanding Merge Sort

This video from Kantan Coding clearly illustrates how the work at each level of the Merge Sort recursion tree sums to O(n).

Watch the segment from 10:42 to 15:10. The presenter breaks down the log n levels and demonstrates that the work at each level involves touching all n elements, resulting in O(n) work per level.


2. Putting It All Together: log n Levels of n Work

Now we can combine our two findings:

  • The algorithm creates O(log n) levels of recursive calls.
  • At each level, it performs a total of O(n) work to merge the sub-lists.

Total Time = (Number of Levels) × (Work per Level)

This diagram perfectly summarizes the analysis:

MergeSort Complexity Tree
This diagram illustrates how the `O(n log n)` time complexity is derived. The recursion creates `log n` levels. At each level, the total work for the merge operations is `O(n)`. Multiplying these two components gives the overall complexity.

3. A Formal Analysis: The Recurrence Relation

We can express the time complexity of a recursive algorithm like Merge Sort using a recurrence relation. This is a more formal, mathematical way to represent the work being done, which will be very useful as you analyze more complex algorithms.

Let T(n) be the time it takes to sort a list of n elements. We can define T(n) as follows:

Let's break this down:

  • T(n): The time to solve a problem of size n.
  • 2T(n/2): The time to solve two recursive subproblems, each on a list of size n/2. This is the "Conquer" step where we call merge_sort on the left and right halves.
  • O(n): The time to combine the results of the subproblems. This is the merge function, which we know takes linear time.

To solve this recurrence and show that it equals O(n log n), we can use a method called repeated substitution. This involves expanding the T(n/2) term repeatedly until we find a general pattern.

The following video provides an excellent walkthrough of this mathematical derivation. Since you're comfortable with algebra and logarithms, this method should feel quite intuitive.

Merge sort time complexity analysis

This video from Satpute Academy demonstrates how to solve the Merge Sort recurrence relation using the method of repeated substitution. This will formalize the visual intuition we've just built.

Watch the entire video (around 10 minutes). The presenter will start by setting up the recurrence T(n) = 2T(n/2) + n and then repeatedly substitute the formula into itself. Follow along as they identify the general pattern and use logarithms to find the final O(n log n) solution.

By following the substitution, you can see mathematically how the n term gets added at each of the log n levels of recursion, leading directly to the n log n result plus a lower-order n term, which we drop in Big O notation.


Conclusion

In this lesson, you've moved beyond simply knowing Merge Sort's complexity to understanding why it is O(n log n). This analytical skill is fundamental to algorithm design and a key part of technical interviews.

Key Takeaways:

  • Merge Sort's time complexity is O(n log n) in all cases (best, average, and worst) because the division and merging steps are not dependent on the input data's order.
  • The log n component comes from the number of times the list can be recursively halved—the depth of the recursion tree.
  • The n component comes from the linear-time merge operation, as the total work done at each level of recursion is O(n).
  • The formal way to express this is with the recurrence relation T(n) = 2T(n/2) + O(n), which can be solved to prove the O(n log n) complexity.

Preview of the Next Lesson:
Now that you have analyzed two sorting algorithms with very different efficiencies (Insertion Sort's O(n²), Merge Sort's O(n log n)), we are ready to take a broader look. In the next lesson, we will compare the performance trade-offs of different sorting algorithms, discussing when you might choose one over the other based on factors like input size, memory usage, and stability.