Back to Data Structures & Algorithms
2026-02-155 min read

Merge Sort (Data Structures & Algorithms)

Learn Merge Sort (Data Structures & Algorithms) step by step with clear examples and exercises.

Why This Matters

Merge sort is a powerful and efficient algorithm used for sorting large data sets. It's widely popular due to its simplicity, stability, and optimal performance on large lists. Understanding merge sort is crucial as it's commonly used in real-world applications, interview questions, and debugging complex code.

Prerequisites

To fully grasp the concept of merge sort, you should have a solid understanding of:

  1. Basic Python syntax and data structures (lists, tuples, and functions)
  2. Concepts of recursion and divide-and-conquer approach
  3. Understanding big O notation for time complexity analysis
  4. Familiarity with list slicing and concatenation in Python

Core Concept

Merge sort works by dividing an unsorted list into smaller sublists until each sublist contains a single element. Then, it merges these small sorted lists back together in a manner that results in a fully sorted list. Here's the high-level process:

  1. Divide the input list arr into two halves using the midpoint index.
  2. Recursively sort both halves (left and right sublists).
  3. Merge the sorted left and right sublists back together to produce a sorted final list.

The merge function takes three arguments:

  1. The starting indices of the two sublists to be merged, l and r.
  2. The ending index of the combined sorted list (initially set as the midpoint), m.
  3. The input list, arr.

The merge function compares elements from both sublists and places them in a new list in sorted order until one sublist is exhausted or they are equal. Then, it continues merging the remaining elements of the other sublist.

Worked Example

Let's take an example input list: [5, 3, 6, 1, 8, 4, 7, 2].

def merge_sort(arr):
if len(arr) <= 1:
return arr

mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]

left = merge_sort(left)
right = merge_sort(right)

i, j, result = 0, 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 += left[i:]
result += right[j:]

return result

arr = [5, 3, 6, 1, 8, 4, 7, 2]
sorted_arr = merge_sort(arr)
print(sorted_arr)

Output: [1, 2, 3, 4, 5, 6, 7, 8]

Common Mistakes

Forgetting the base case

Ensure you return an already sorted list when the input list has one or zero elements.

def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]

left = merge_sort(left)
right = merge_sort(right)

i, j, result = 0, 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 += left[i:]
result += right[j:]

return result
else:
return arr

Merging incorrectly

When merging two sublists, make sure to compare elements properly and handle the case when one sublist is exhausted.

def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]

left = merge_sort(left)
right = merge_sort(right)

i, j, result = 0, 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 += left[i:]
elif len(arr) == 1:
return arr

Forgetting to handle the remaining elements of one sublist

if i < len(left):

result += left[i:]

elif j < len(right):

result += right[j:]

return result

### Using a temporary list for merging
While using a temporary list is efficient, it can consume additional memory. An alternative approach is to merge the sublists in-place without creating a new list.

def merge_sort(arr):

if len(arr) > 1:

mid = len(arr) // 2

left = arr[:mid]

right = arr[mid:]

merge_sort(left)

merge_sort(right)

i, j, k = 0, 0, 0

while i < len(left) and j < len(right):

if left[i] <= right[j]:

arr[k] = left[i]

i += 1

else:

arr[k] = right[j]

j += 1

k += 1

while i < len(left):

arr[k] = left[i]

i += 1

k += 1

while j < len(right):

arr[k] = right[j]

j += 1

k += 1

Practice Questions

  1. Write a recursive implementation of the merge sort algorithm in C++.
  2. Implement an iterative version of merge sort in Python using the built-in heapify() and heappushpop() functions.
  3. Calculate the time complexity of the merge sort algorithm using big O notation.
  4. Compare the efficiency of merge sort with other popular sorting algorithms like quicksort, heapsort, and bubble sort.
  5. Modify the merge_sort function to handle duplicate values in the input list (make it stable).
  6. Implement an optimized version of merge sort that sorts the sublists using a custom comparison function.
  7. Write a function to find the kth smallest element in a sorted array using merge sort.
  8. Implement a parallel version of merge sort using Python's multiprocessing module.
  9. Extend the merge_sort function to handle lists with negative numbers (make it robust).
  10. Use recursion to find the minimum number of swaps required to sort an array using merge sort.

FAQ

Why is merge sort more efficient than other sorting algorithms for large data sets?

Merge sort's efficiency comes from its divide-and-conquer approach, which reduces the time complexity to O(n log n) in the worst case. This makes it ideal for sorting large datasets.

Can I implement merge sort using a single pass through the array?

No, merge sort requires two passes: one to split the array into smaller sublists and another to merge them back together. However, there are iterative versions of merge sort that use less memory by merging in-place without creating a new list.

What is the time complexity of the merge function in merge sort?

The time complexity of the merge function is O(n), where n is the size of one of the sublists being merged. Since we're merging two sublists of equal size at each level, the overall time complexity of the merge sort algorithm remains O(n log n).

Merge Sort (Data Structures & Algorithms) | Data Structures & Algorithms | XQA Learn