Merge Sort
Algorithms
Merge sort is a divide-and-conquer algorithm that divides the array into two halves, sorts them recursively, and then merges the sorted halves.
Algorithm
The merge sort algorithm follows these steps:
- Divide the array into two halves
- Recursively sort both halves
- Merge the two sorted halves
Time Complexity
Merge sort has a time complexity of in all cases (best, average, and worst), where is the number of elements.
Space Complexity
The space complexity is due to the temporary arrays used during merging.
Implementation
def merge_sort(arr):
if len(arr) > 1:
# Find the middle point
mid = len(arr) // 2
# Divide the array into two halves
L = arr[:mid]
R = arr[mid:]
# Recursively sort both halves
merge_sort(L)
merge_sort(R)
# Merge the sorted halves
i = j = k = 0
# Copy data to temp arrays L[] and R[]
while i < len(L) and j < len(R):
if L[i] < R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
# Checking if any element was left
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
return arr
# Example usage with different numbers
arr = [45, 23, 78, 12, 56, 89, 34]
sorted_arr = merge_sort(arr)
print("Sorted array:", sorted_arr) Trace it by hand
Maintain two pointers i (left half) and j (right half), output one element per step:
- Compare 2 vs 1 → emit 1.
[1] - Compare 2 vs 4 → emit 2.
[1, 2] - Compare 5 vs 4 → emit 4.
[1, 2, 4] - Compare 5 vs 9 → emit 5.
[1, 2, 4, 5] - Compare 8 vs 9 → emit 8.
[1, 2, 4, 5, 8] - Left half empty. Drain right: emit 9.
[1, 2, 4, 5, 8, 9]
Result: [1, 2, 4, 5, 8, 9], produced by 5 comparisons. The merge is linear in the combined length (here, 6 elements), and the recurrence with linear merge gives merge sort's bound. The "5 comparisons for 6 elements" is the worst case — alternating halves. The best case (one half is already entirely smaller) does 3 comparisons + a drain.