Merge Sort Algorithm Explaination and Visualization

Merge Sort Algorithm: Visualization, Python Code and Time Complexity | BeingNeuron

Merge Sort Algorithm

Imagine you have to sort 1,000 exam papers by roll number. You could pick up one paper at a time and search the pile for its place. That works, but it gets slow very quickly. A smarter plan is to split the pile between friends, let each friend sort a smaller pile, and then combine the sorted piles into one. Merge Sort works in exactly this way.

A sorting algorithm is a set of steps that puts items in order, such as smallest to largest or A to Z. Sorting matters because ordered data is easier to search, compare, and process. Binary search only works on sorted data, and tasks like finding duplicates become much faster once the data is in order.

Merge Sort is a sorting algorithm built on the divide-and-conquer technique. It splits an array into halves until every piece holds a single element, then merges the pieces back together in sorted order. It runs in O(n log n) time in every case, which is why people consider it one of the dependable sorting algorithms. Watch it run below, then read on to see why it works.

Interactive Merge Sort Visualization

The animation starts by itself. Pause it at any time, then use Previous and Next to move one step at a time. You can also type your own array.

Step 1 / 1 Current phase: Ready Recursion Level: 0
  • Unprocessed
  • Left part (L)
  • Right part (R)
  • Being compared
  • Taken (lifted, outlined)
  • Already used
  • Sorted (✓)

Merged Result

Current Operation

Recursion Tree (built as the algorithm runs)

What Is Merge Sort?

Merge Sort is a sorting algorithm that sorts an array by splitting it into smaller parts, sorting those parts, and merging them back together. It repeats four actions:

  1. Divide the array into two smaller parts.
  2. Keep dividing until every part contains one element.
  3. Merge those small parts back together.
  4. While merging, place the elements in sorted order.

The key fact is this: a single element is already sorted. One item cannot be out of order with itself. Merge Sort uses this to turn a hard problem into many trivial ones. Here is a tiny example:

[8, 3, 5, 1]

split  →  [8, 3]   [5, 1]
split  →  [8] [3]  [5] [1]

merge  →  [3, 8]   [1, 5]
merge  →  [1, 3, 5, 8]

The array splits into pairs, then into single elements. Merging goes the other way. [8] and [3] become [3, 8]. [5] and [1] become [1, 5]. Finally the two sorted pairs merge into [1, 3, 5, 8].

The Main Idea Behind Merge Sort

Merge Sort follows three stages: divide, conquer, and combine.

  • Divide: Split the array into two smaller arrays.
  • Conquer: Sort each half. The algorithm does this by calling itself on each half, which is called recursion.
  • Combine: Merge the two sorted halves into one sorted array.

The combine step is where the real sorting happens. Splitting only cuts the array in the middle and never moves any values. The merge step is cheap because both halves are already sorted. To merge them, you only need to look at the front of each half, since the smallest remaining element in each half always sits at its front. You never have to search through a half.

How Merge Sort Works

Let us sort [38, 27, 43, 3, 9, 82, 10]. The array has 7 elements, so the left half gets 3 elements (7 // 2 = 3) and the right half gets the other 4. This is how the array splits, level by level:

Level 0:  [38, 27, 43, 3, 9, 82, 10]
Level 1:  [38, 27, 43]   [3, 9, 82, 10]
Level 2:  [38]  [27, 43]   [3, 9]  [82, 10]
Level 3:  [38]  [27]  [43]   [3]  [9]  [82]  [10]

Every part at level 3 has one element, so no more splitting is needed. Odd lengths cause no trouble. One half is simply one element bigger than the other.

Now the algorithm merges upward. It retraces the same levels in reverse:

Level 3 → 2:  [38]  [27, 43]   [3, 9]  [10, 82]
Level 2 → 1:  [27, 38, 43]   [3, 9, 10, 82]
Level 1 → 0:  [3, 9, 10, 27, 38, 43, 82]

The final result is [3, 9, 10, 27, 38, 43, 82]. Notice that [38] waited alone until the level 2 merge. Not every part merges at every level.

Divide and Conquer

Divide and conquer is a way to solve big problems. You break the problem into smaller versions of itself, solve the small versions, and then use their answers to build the answer to the big problem. The smaller problems must look like the original, so the same method works on them again.

StageGeneral ideaIn Merge Sort
DivideBreak a large problem into smaller problems.Split the array at the middle.
ConquerSolve the smaller problems.Sort each half by calling Merge Sort again. One-element parts are already sorted.
CombineJoin the solutions into the final answer.Merge the two sorted halves into one sorted array.

Binary search, Quick Sort, and many other algorithms use the same pattern. Merge Sort is a popular first example because each stage is easy to see: the divide step is trivial, and all the work sits in the combine step.

Step-by-Step Example

We use the same array again: [38, 27, 43, 3, 9, 82, 10].

  • Stage 1: [38, 27, 43, 3, 9, 82, 10]
  • Stage 2: split into [38, 27, 43] and [3, 9, 82, 10]
  • Stage 3: split again into [38] [27, 43] [3, 9] [82, 10]
  • Stage 4: split until only single elements remain: [38] [27] [43] [3] [9] [82] [10]
  • Stage 5: merge neighbors: [27, 43], [3, 9], and [10, 82]
  • Stage 6: merge again: [27, 38, 43] and [3, 9, 10, 82]
  • Stage 7: merge the last two parts: [3, 9, 10, 27, 38, 43, 82]

The stages above show the idea level by level, but the program does not work that way. It works depth first: it finishes the whole left side before it touches the right side. In the visualization you can see this order of merges:

  1. Merge [27] and [43] into [27, 43].
  2. Merge [38] and [27, 43] into [27, 38, 43]. The left half is now sorted.
  3. Merge [3] and [9] into [3, 9].
  4. Merge [82] and [10] into [10, 82].
  5. Merge [3, 9] and [10, 82] into [3, 9, 10, 82]. The right half is now sorted.
  6. Merge [27, 38, 43] and [3, 9, 10, 82] into the final array.

Merge number 6 does the most work. It compares 27 with 3 and takes 3. Then it compares 27 with 9 and takes 9, compares 27 with 10 and takes 10, and compares 27 with 82 and takes 27. Next, 38 beats 82 and 43 beats 82. Only 82 remains in the right half, so it goes to the end.

How the Merge Process Works

This is the most important part of Merge Sort, and the visualization shows it clearly. Suppose we need to merge two sorted arrays:

Left:   [3, 27, 38]
Right:  [9, 10, 43]

Merge Sort does not just glue the two arrays together. Gluing would give [3, 27, 38, 9, 10, 43], which is not sorted. Instead, it compares the smallest remaining element of each array and takes the smaller one.

StepCompareTakeMerged so far
13 vs 93[3]
227 vs 99[3, 9]
327 vs 1010[3, 9, 10]
427 vs 4327[3, 9, 10, 27]
538 vs 4338[3, 9, 10, 27, 38]
6Left is empty43[3, 9, 10, 27, 38, 43]

The method works because each array is already sorted. The front element of an array is its smallest, so the smaller of the two front elements is the smallest of everything left. Taking it is always safe.

The merge uses one pointer for each array. Move a pointer forward only when you take an element from that array. When one array runs out, copy everything left in the other array to the end. Since it is already sorted, nothing else needs checking.

When two values are equal, take the one from the left array first. This keeps equal values in their original order, and it makes Merge Sort stable.

Merge Sort Pseudocode

MERGE_SORT(array)
    IF length(array) <= 1
        RETURN array

    middle ← length(array) / 2        (rounded down)

    left  ← MERGE_SORT(first half of array)
    right ← MERGE_SORT(second half of array)

    RETURN MERGE(left, right)


MERGE(left, right)
    result ← empty array

    WHILE left is not empty AND right is not empty
        IF first element of left <= first element of right
            remove first element of left and add it to result
        ELSE
            remove first element of right and add it to result

    add all remaining elements of left to result
    add all remaining elements of right to result

    RETURN result

Merge Sort in Python

def merge_sort(arr):
    # Base case: 0 or 1 elements are already sorted
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2

    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])

    return merge(left, right)


def merge(left, right):
    result = []
    i = 0
    j = 0

    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    result.extend(left[i:])
    result.extend(right[j:])

    return result


numbers = [38, 27, 43, 3, 9, 82, 10]
print(merge_sort(numbers))   # [3, 9, 10, 27, 38, 43, 82]

Line-by-Line Explanation

Recursion in plain words

Recursion means a function calls itself on a smaller version of the same job. Think of a manager who gets a stack of files to sort. She keeps none of the work. She cuts the stack in half, hands one half to each assistant, and waits. Each assistant does the same with a smaller stack. Eventually someone receives a stack of one file and hands it straight back, because one file is already in order. Then each manager merges the two sorted stacks she receives.

The base case

if len(arr) <= 1: return arr stops the recursion. An array with zero or one element is already sorted, so the function returns it unchanged. Without this line, the function would call itself forever.

The middle index

mid = len(arr) // 2 finds the split point. The // operator divides and rounds down, so 7 elements give mid = 3.

The recursive calls

arr[:mid] is the left half: everything before index mid. arr[mid:] is the right half: everything from index mid onward. Each half goes into merge_sort again, and the function returns a sorted version of it. By the time both calls finish, left and right are sorted.

The merge function

merge takes two sorted lists and builds one. It starts with an empty list called result.

The pointers i and j

i tracks the next unused element in left. j does the same for right. Both start at 0.

The comparison

The loop runs while both lists still have unused elements. Each round compares left[i] with right[j]. The <= sign means that on a tie, the left element wins. That choice keeps the sort stable.

Appending elements

The winner goes into result with append, and only its pointer moves forward. The other pointer stays put, because that element has not been used yet.

The remaining elements

When the loop ends, at least one list is used up. The other may still hold elements. left[i:] and right[j:] are the unused tails. One of them is empty, and the other is already sorted and larger than everything in result, so extend can add it as it is.

The final result

return result hands the merged, sorted list back to the caller. That caller is either another merge step higher up the recursion or, at the very top, your finished answer.

Time Complexity

Merge Sort runs in O(n log n) time. Two ideas explain where the two parts come from.

The log n part. The array splits into two halves each time, so the number of levels is about log₂(n). An array of 8 elements needs 3 levels of splitting (8 → 4 → 2 → 1). An array of 1,000,000 elements needs only about 20.

The n part. At every level, the merge steps together touch all n elements once. Some merges are small and some are large, but their sizes add up to n.

Level (n = 8)PartsSize of each partElements merged at this level
Top merge188
Next248
Next428
Bottom (single elements)81no merging needed

Three merge levels with about 8 elements each give about 24 element moves, which is 8 × log₂(8). In general:

O(n) work per level × O(log n) levels = O(n log n)

CaseTime
Best caseO(n log n)
Average caseO(n log n)
Worst caseO(n log n)

All three are the same for standard Merge Sort because the algorithm always splits and always merges, no matter what the data looks like. An already sorted array does need fewer comparisons, since one half runs out early. Still, the algorithm splits and copies the same number of elements, so the total time stays proportional to n log n.

Space Complexity

The standard array-based version of Merge Sort needs O(n) extra memory. The reason is the merge step. It cannot safely write the merged values into the same spots it is still reading from, so it builds the result in a temporary array of the same total size as the parts being merged. The recursion also uses a call stack that is O(log n) deep, but that is small next to the O(n) temporary storage.

Implementation details change the exact numbers. The Python code above creates new lists with slicing, while other versions reuse one helper array. Both are O(n) in extra space. Truly in-place versions exist, but they are much more complicated and rarely worth the effort.

Merge Sort vs Quick Sort

FeatureMerge SortQuick Sort
Basic strategySplit at the middle, sort each half, mergeChoose a pivot, partition around it, sort each side
Best-case timeO(n log n)O(n log n)
Average-case timeO(n log n)O(n log n)
Worst-case timeO(n log n)O(n²) with poor pivots
Additional memoryO(n) for arraysUsually O(log n) for the call stack
Stable?Yes, when ties take the left elementUsually not
Recursive?Usually, but a bottom-up loop version existsUsually, but it can be written with a stack
Typical useLinked lists, external sorting, stable sortingIn-memory arrays
Performance traitsSteady and predictable; extra copyingOften fast in practice; sensitive to pivot choice

Neither algorithm is better in every situation. Quick Sort works in place and often performs well on in-memory arrays, but a bad pivot choice can slow it down. Merge Sort gives steady timing and stability, but it needs extra memory. Real performance depends on your implementation, your data, your memory limits, and the hardware you run on.

Merge Sort vs Bubble Sort

FeatureMerge SortBubble Sort
ApproachDivide, sort halves, mergeSwap neighboring elements that are out of order, again and again
Best caseO(n log n)O(n) with an early-exit check
Average caseO(n log n)O(n²)
Worst caseO(n log n)O(n²)
SpaceO(n)O(1)
Practical useReal sorting jobs, large dataTeaching and very small inputs

The gap shows up as the data grows. For 1,000,000 elements, n log₂ n is about 20 million steps, while n² is about one trillion. Merge Sort finishes in moments, while Bubble Sort would take hours. That is why Merge Sort scales to large datasets and Bubble Sort does not.

Advantages of Merge Sort

  • Guaranteed O(n log n) time. The worst case is as good as the average case.
  • Predictable performance. The running time hardly depends on how the input is arranged.
  • Stable. When implemented with the <= rule, equal elements keep their original order. This matters when you sort records by one field and want an earlier order preserved.
  • Handles large datasets well. The work grows only slightly faster than the input size.
  • Suits linked lists. Merging needs only sequential access, so linked lists can be merged with almost no extra memory.
  • Useful for external sorting. Data too large for memory can be sorted in chunks on disk and merged.
  • A clear divide-and-conquer example. Learning it prepares you for many other algorithms.

Limitations of Merge Sort

  • Extra memory. The standard array version needs O(n) additional storage, unlike in-place algorithms.
  • More complex than simple sorts. It has more moving parts than Bubble Sort or Insertion Sort.
  • Recursion can confuse beginners. Following several calls at once takes practice.
  • Overhead on small inputs. For very small arrays, a simple algorithm can be faster because it avoids the copying and function calls. Many libraries switch to Insertion Sort for tiny parts.
  • Copying costs time. Moving elements in and out of temporary arrays adds a constant cost that in-place methods avoid.

When Should You Use Merge Sort?

Merge Sort is a good choice in these situations:

  • Large datasets where an O(n²) algorithm would be far too slow.
  • Strict time guarantees. If you cannot risk a slow worst case, O(n log n) in every case helps.
  • Stability matters. For example, when sorting people by city after sorting them by name.
  • External sorting of files that do not fit in memory.
  • Linked lists, where merging is natural and cheap.
  • Learning. It is one of the clearest ways to understand divide and conquer.

It is not always the best tool. If memory is tight and stability does not matter, an in-place algorithm may suit you better. For a handful of elements, a simple sort is fine.

Conclusion

Merge Sort solves a large sorting problem by breaking it into tiny ones. It splits the array until single elements remain, then merges sorted parts by always taking the smaller front element. This gives it O(n log n) time in every case, at the price of O(n) extra memory. The animation at the top of this page shows both halves of the process, so replay it with your own arrays until the split-and-merge pattern feels natural. Then try writing the Python version from memory.

Frequently Asked Questions

What is Merge Sort?

Merge Sort is a divide-and-conquer sorting algorithm. It splits an array into halves, sorts each half, and merges the sorted halves into one sorted array.

How does Merge Sort work?

It divides the array until each part has one element. Then it repeatedly merges two sorted parts by comparing their front elements and taking the smaller one, until one sorted array remains.

What is the time complexity of Merge Sort?

O(n log n) in the best, average, and worst cases. There are about log₂(n) levels, and each level does about n work.

What is the space complexity of Merge Sort?

The standard array-based version uses O(n) extra space for temporary arrays. The recursion adds an O(log n) call stack.

Is Merge Sort stable?

Yes, when the merge takes the left element on a tie (the <= comparison). Equal values then keep their original order.

Is Merge Sort better than Quick Sort?

Not always. Merge Sort has a guaranteed O(n log n) worst case and is stable, but it needs extra memory. Quick Sort sorts in place and is often fast in practice, but its worst case is O(n²). The better choice depends on your data and constraints.

Why does Merge Sort use recursion?

Each half of the array is a smaller sorting problem of the same kind, so the algorithm can call itself on each half. Recursion also lets the splitting stop cleanly at the one-element base case. You can also write Merge Sort with loops, from the bottom up.

Can Merge Sort work with duplicate values?

Yes. Duplicates cause no problem. With the <= rule, equal values stay in their original order. Try 5,5,3,3,1 in the visualization to see it.

Scroll to Top