Recommended resources
The freely available resources this lesson will direct you to.
Welcome to the next lesson in our journey through recursion and sorting. In our previous sessions, you've implemented the mergeSort algorithm and explored the call stack mechanism that enables recursion. Today, we'll connect the structure of the mergeSort algorithm directly to its performance.
Our goal is to analyze why mergeSort is considered a highly efficient sorting algorithm. We will derive its time complexity of and its space complexity of . Understanding this analysis is fundamental to making informed decisions about which algorithm to use in different scenarios.
1. The Anatomy of Merge Sort's Complexity
As we've seen, mergeSort uses a "divide and conquer" strategy. Its performance is a direct result of this two-part process:
- Divide: The recursive splitting of the array into halves.
- Conquer: The merging of the sorted halves back together.
The time complexity is a product of these two parts: the log n comes from the "divide" step, and the n comes from the "conquer" step. Let's break down each one.
2. The "log n" Factor: The Power of Halving
The "divide" phase of mergeSort repeatedly splits the array in half until we have sub-arrays of size 1. The key question is: how many times can you split an array of size n in half before you're left with single elements?
This is a classic logarithmic problem. Think of searching for a word in a physical dictionary. You don't start from page one; you open it to the middle. Based on where your word is alphabetically, you discard half the book and repeat the process with the remaining half. The number of times you have to do this is very small compared to the total number of pages.
This is the essence of logarithmic complexity. The following article provides an excellent intuition for this concept.
Breaking Down MergeSort. And Understanding O(N log N) ...
This section from the Medium article "Breaking Down MergeSort" uses the dictionary analogy to give you an intuitive feel for what O(log N) means and why it's so much more efficient than O(N).
Read the section titled "O(log N) v O(N)". Focus on the core idea of how repeatedly halving the problem space (the dictionary) leads to a logarithmic number of steps.
In mergeSort, this process of halving the array creates a recursion tree. If our initial array has n elements, the number of levels in this tree—the number of sets of recursive calls we have to make—is .
Let's see this visually. The following video demonstrates how an array of size 8 is split, resulting in levels of splits.
Why Is Merge Sort O(n * log(n))? The Really Really Long Answer.
This video from Back To Back SWE gives a detailed analysis of merge sort's complexity. We'll start with the splitting phase.
Watch from the beginning until the split analysis. The presenter traces the recursive splits for an array of size n=8, clearly showing how this results in log n levels in the recursion tree. Notice the relationship he draws between n, the number of splits, and log n.
3. The "n" Factor: Work Done at Each Level
Now we know the "divide" step gives us levels of recursion. But how much work is done at each of these levels? This is where the "conquer" (or merge) step comes in.
At each level of the recursion tree, we perform several merge operations. For example, at the bottom level, we merge pairs of 1-element arrays. At the next level up, we merge pairs of 2-element arrays, and so on.
The critical insight is this: at every single level of the recursion tree, the total number of elements processed across all merge operations for that level is exactly n.
To understand why the work per level is , let's first analyze a single merge operation.
Why Is Merge Sort O(n * log(n))? The Really Really Long Answer.
Let's return to the Back To Back SWE video to analyze the merge subroutine.
Watch the section from the merge subroutine. The key takeaway is that to merge two sorted sub-arrays with a combined total of k elements, we perform about k operations (comparisons and copies). This means the merge operation has a linear time complexity, O(k).
Since merging k elements takes time, and every level of the recursion tree involves merging a total of n elements, the work done at each level is .
4. Putting It All Together: Time Complexity is
We've now established the two key components:
- There are levels of recursion (from the splitting).
- Each level performs a total of work (from the merging).
The total time complexity is simply the product of these two:
This relationship is perfectly captured by the classic recursion tree diagram for mergeSort.

This also explains why mergeSort is so consistent. Whether the array is already sorted, in reverse order, or random, the algorithm still performs the same number of splits and merges. This is why its best-case, average-case, and worst-case time complexities are all .
The Codecademy article below provides a great summary of this entire breakdown.
Time Complexity of Merge Sort: A Detailed Analysis
This article clearly explains why the time complexity of merge sort is consistently O(n log n).
Read the sections "Time complexity of Merge Sort" and "Breaking down the time complexity of Merge Sort." This will reinforce the concepts of best/average/worst case and the log n levels of O(n) work.
For those interested in a more formal mathematical proof, the following video section derives the exact formula for the number of comparisons, showing precisely where the term originates. This is optional but can provide a deeper appreciation for the analysis.
Why Is Merge Sort O(n * log(n))? The Really Really Long Answer.
This final segment from the Back To Back SWE video develops and solves the recurrence relation for merge sort.
This is a more advanced analysis. You can watch from the recurrence relation to see the full mathematical derivation. The key is to see how the recurrence T(n) = 2T(n/2) + O(n) is expanded into a summation that results in the n \log n formula.
5. Space Complexity: Where Does the Memory Go?
While mergeSort is excellent in terms of time, it comes at a cost: memory. Its space complexity is , which is less efficient than sorting algorithms like Selection Sort or Insertion Sort that operate "in-place" ( space).
There are two main contributors to mergeSort's memory usage:
-
The Auxiliary Array for Merging: As you saw in the
mergefunction implementation, you need temporary storage to combine two sorted sub-arrays. To merge the final two halves of the main array (each of sizen/2), you need a temporary array of sizen. This is the dominant factor in memory usage, contributing to the space complexity. -
The Recursion Call Stack: In the last lesson, we saw how every recursive call adds a frame to the call stack. For
mergeSort, the maximum depth of the recursion is the number of levels in our tree, which is . Therefore, the call stack contributes space.
When we combine these, the total space complexity is . In Big-O notation, we drop the non-dominant terms, so the final space complexity simplifies to .
The following reading provides a concise explanation of this.
Time Complexity of Merge Sort: A Detailed Analysis
Let's return to the Codecademy article one last time.
Read the section "Space complexity of Merge Sort". It clearly separates the memory used by the auxiliary array from the memory used by the call stack and explains why the total is considered O(n).
Conclusion
In this lesson, we've dissected the performance of the mergeSort algorithm. By analyzing its divide-and-conquer strategy, you can now explain precisely why its performance is so reliable and efficient.
Key Takeaways:
- Time Complexity is : This is a product of having levels of recursion, with each level performing work during the merge steps.
- Consistent Performance:
mergeSort's time complexity is in the best, average, and worst cases because the number of divisions and merges is independent of the initial order of the data. - Space Complexity is : This is dominated by the need for a temporary, auxiliary array of size
nto perform the merge operations. The recursive call stack contributes a smaller amount of space.
Preview of the Next Lesson:
You have now implemented and analyzed four different sorting algorithms: Bubble Sort, Selection Sort, Insertion Sort (), and Merge Sort (). In our next lesson, we will bring it all together by comparing the performance characteristics of all of them. This will help you build the crucial skill of choosing the right tool for the job based on data size, memory constraints, and stability requirements.