Common Algorithms
Merge Sort
Large-scale data processing requires sorting algorithms with predictable, efficient performance. Merge sort guarantees O(n log n) time complexity regardless of input order, making it the algorithm of choice for sorting large datasets, external files, and situations where consistent performance is critical.
Merge sort is a divide-and-conquer algorithm that divides the list into halves, recursively sorts each half, and then merges the sorted halves.
Algorithm
- Divide the list into two halves
- Recursively sort each half
- Merge the two sorted halves
divide_conquer_sort
Split the problem into smaller parts, solve each, then combine the solutions
Basic Implementation
basic.py
Replay: real traced execution (multi-file project)
# Basic merge sort
def merge_sort(arr):
"""Merge sort implementation"""
# Base case: single element is sorted
if len(arr) <= 1:
return arr
# Divide
mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]
# Recursively sort
left = merge_sort(left)
right = merge_sort(right)
# Merge sorted halves
return merge(left, right)
def merge(left, right):
"""Merge two sorted lists"""
result = []
i = j = 0
# Compare and merge
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
# Add remaining elements
result.extend(left[i:])
result.extend(right[j:])
return result
# Test merge sort
numbers = [38, 27, 43, 3, 9, 82, 10]
print("Before:", numbers)
sorted_numbers = merge_sort(numbers)
print("After: ", sorted_numbers)
# Basic merge sort
def merge_sort(arr):
"""Merge sort implementation"""
# Base case: single element is sorted
if len(arr) <= 1:
return arr
# Divide
mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]
# Recursively sort
left = merge_sort(left)
right = merge_sort(right)
# Merge sorted halves
return merge(left, right)
def merge(left, right):
"""Merge two sorted lists"""
result = []
i = j = 0
# Compare and merge
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
# Add remaining elements
result.extend(left[i:])
result.extend(right[j:])
return result
# Test merge sort
numbers = [8, 3, 7, 4, 9, 2]
print("Before:", numbers)
sorted_numbers = merge_sort(numbers)
print("After: ", sorted_numbers)
# Basic merge sort
def merge_sort(arr):
"""Merge sort implementation"""
# Base case: single element is sorted
if len(arr) <= 1:
return arr
# Divide
mid = len(arr) // 2
left = arr[:mid]
right = arr[mid:]
# Recursively sort
left = merge_sort(left)
right = merge_sort(right)
# Merge sorted halves
return merge(left, right)
def merge(left, right):
"""Merge two sorted lists"""
result = []
i = j = 0
# Compare and merge
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
# Add remaining elements
result.extend(left[i:])
result.extend(right[j:])
return result
# Test merge sort
numbers = [5, 1, 6]
print("Before:", numbers)
sorted_numbers = merge_sort(numbers)
print("After: ", sorted_numbers)
numbers ← [38, 27, 43, 3, 9, 82, 10]
44# Test merge sort45numbers→ [38, 27, 43, 3, 9, 82, 10] = [38, 27, 43, 3, 9, 82, 10]46#@numbers=[8, 3, 7, 4, 9, 2], [5, 1, 6]4748print("Before:", numbers[38, 27, 43, 3, 9, 82, 10])49sorted_numbers = merge_sort(numbers[38, 27, 43, 3, 9, 82, 10])50print("After: ", sorted_numbers)outputBefore: [38, 27, 43, 3, 9, 82, 10]mid ← 3, left ← [38, 27, 43], right ← [3, 9, 82, 10]
pass 1 of 134def merge_sort(arr[38, 27, 43, 3, 9, 82, 10]):5 """Merge sort implementation"""6 # Base case: single element is sorted7 if len(arr) <= 1:8 return arr910 # Divide11 mid→ 3 = len(arr[38, 27, 43, 3, 9, 82, 10]) // 212 left→ [38, 27, 43] = arr[:mid][38, 27, 43]13 right→ [3, 9, 82, 10] = arr[mid:][3, 9, 82, 10]1415 # Recursively sort16 left = merge_sort(left[38, 27, 43])17 right = merge_sort(right)13 passes — pass 1 is the card above pass arrarr[:mid]arr[mid:]midleftright1 [38, 27, 43, 3, 9, 82, 10] [38, 27, 43] [3, 9, 82, 10] 3 [38, 27, 43] [3, 9, 82, 10] 2 [38, 27, 43] [38] [27, 43] 1 [38] [27, 43] 3 [38] — — — — — 4 [27, 43] [27] [43] 1 [27] [43] 5 [27] — — — — — 6 [43] — — — — — 7 [3, 9, 82, 10] [3, 9] [82, 10] 2 [3, 9] [82, 10] 8 [3, 9] [3] [9] 1 [3] [9] 9 [3] — — — — — ⋯ 2 more passes ⋯ 12 [82] — — — — — 13 [10] — — — — — if len(arr) <= 1:
pass 1 of 76# Base case: single element is sorted7if len(arr[38]) <= 1:8 return arr[38]All 7 passes — pass 1 is the card above pass arr1 [38] 2 [27] 3 [43] 4 [3] 5 [9] 6 [82] 7 [10] left ← [38]
15# Recursively sort16left→ [38] = merge_sort(left)17right = merge_sort(right[27, 43])left ← [27]
15# Recursively sort16left→ [27] = merge_sort(left)17right = merge_sort(right[43])right ← [43]
16left = merge_sort(left)17right→ [43] = merge_sort(right)1819# Merge sorted halves20return merge(left[27], right[43])result ← [], i ← 0, j ← 0
pass 1 of 623def merge(left[27], right[43]):24 """Merge two sorted lists"""25 result→ [] = []26 i→ 0 = j→ 0 = 0All 6 passes — pass 1 is the card above pass leftrightresultij1 [27] [43] [] 0 0 2 [38] [27, 43] [] 0 0 3 [3] [9] [] 0 0 4 [82] [10] [] 0 0 5 [3, 9] [10, 82] [] 0 0 6 [27, 38, 43] [3, 9, 10, 82] [] 0 0 while i < len(left) and j < len(right):
pass 1 of 1328# Compare and merge29while i0 < len(left[27]) and j0 < len(right[43]):30 if left[i] <= right[j]:31 result.append(left[i])13 passes — pass 1 is the card above pass ileftjright1 0 [27] 0 [43] 2 0 [38] 0 [27, 43] 3 0 [38] 1 [27, 43] 4 0 [3] 0 [9] 5 0 [82] 0 [10] 6 0 [3, 9] 0 [10, 82] 7 1 [3, 9] 0 [10, 82] 8 0 [27, 38, 43] 0 [3, 9, 10, 82] 9 0 [27, 38, 43] 1 [3, 9, 10, 82] ⋯ 2 more passes ⋯ 12 1 [27, 38, 43] 3 [3, 9, 10, 82] 13 2 [27, 38, 43] 3 [3, 9, 10, 82] result ← [27], i ← 1
pass 1 of 829while i < len(left) and j < len(right):30 if left[i]27 <= right[j]43:31 result→ [27].append(left[i]27)32 i→ 1 += 133 else:All 8 passes — pass 1 is the card above pass left[i]right[j]resulti1 27 43 [] → [27] 0 → 1 2 38 43 [27] → [27, 38] 0 → 1 3 3 9 [] → [3] 0 → 1 4 3 10 [] → [3] 0 → 1 5 9 10 [3] → [3, 9] 1 → 2 6 27 82 [3, 9, 10] → [3, 9, 10, 27] 0 → 1 7 38 82 [3, 9, 10, 27] → [3, 9, 10, 27, 38] 1 → 2 8 43 82 [3, 9, 10, 27, 38] → [3, 9, 10, 27, 38, 43] 2 → 3 result ← [27, 43]
37# Add remaining elements38result[27].extend(left[i:][])39result→ [27, 43].extend(right[j:][43])4041return result[27, 43]right ← [27, 43]
16left = merge_sort(left)17right→ [27, 43] = merge_sort(right)1819# Merge sorted halves20return merge(left[38], right[27, 43])result ← [27], j ← 1
pass 1 of 531 result.append(left[i])32 i += 133else:34 result→ [27].append(right[j]27)35 j→ 1 += 1All 5 passes — pass 1 is the card above pass right[j]resultj1 27 [] → [27] 0 → 1 2 10 [] → [10] 0 → 1 3 3 [] → [3] 0 → 1 4 9 [3] → [3, 9] 1 → 2 5 10 [3, 9] → [3, 9, 10] 2 → 3 result ← [27, 38, 43]
37# Add remaining elements38result[27, 38].extend(left[i:][])39result→ [27, 38, 43].extend(right[j:][43])4041return result[27, 38, 43]left ← [27, 38, 43]
15# Recursively sort16left→ [27, 38, 43] = merge_sort(left)17right = merge_sort(right[3, 9, 82, 10])left ← [3]
15# Recursively sort16left→ [3] = merge_sort(left)17right = merge_sort(right[9])right ← [9]
16left = merge_sort(left)17right→ [9] = merge_sort(right)1819# Merge sorted halves20return merge(left[3], right[9])result ← [3, 9]
37# Add remaining elements38result[3].extend(left[i:][])39result→ [3, 9].extend(right[j:][9])4041return result[3, 9]left ← [3, 9]
15# Recursively sort16left→ [3, 9] = merge_sort(left)17right = merge_sort(right[82, 10])left ← [82]
15# Recursively sort16left→ [82] = merge_sort(left)17right = merge_sort(right[10])right ← [10]
16left = merge_sort(left)17right→ [10] = merge_sort(right)1819# Merge sorted halves20return merge(left[82], right[10])result ← [10, 82]
37# Add remaining elements38result→ [10, 82].extend(left[i:][82])39result[10, 82].extend(right[j:][])4041return result[10, 82]right ← [10, 82]
16left = merge_sort(left)17right→ [10, 82] = merge_sort(right)1819# Merge sorted halves20return merge(left[3, 9], right[10, 82])result ← [3, 9, 10, 82]
37# Add remaining elements38result[3, 9].extend(left[i:][])39result→ [3, 9, 10, 82].extend(right[j:][10, 82])4041return result[3, 9, 10, 82]right ← [3, 9, 10, 82]
16left = merge_sort(left)17right→ [3, 9, 10, 82] = merge_sort(right)1819# Merge sorted halves20return merge(left[27, 38, 43], right[3, 9, 10, 82])result ← [3, 9, 10, 27, 38, 43, 82]
37# Add remaining elements38result[3, 9, 10, 27, 38, 43].extend(left[i:][])39result→ [3, 9, 10, 27, 38, 43, 82].extend(right[j:][82])4041return result[3, 9, 10, 27, 38, 43, 82]sorted_numbers ← [3, 9, 10, 27, 38, 43, 82]
48print("Before:", numbers)49sorted_numbers→ [3, 9, 10, 27, 38, 43, 82] = merge_sort(numbers[38, 27, 43, 3, 9, 82, 10])50print("After: ", sorted_numbers[3, 9, 10, 27, 38, 43, 82])outputAfter: [3, 9, 10, 27, 38, 43, 82]
numbers ← [8, 3, 7, 4, 9, 2]
44# Test merge sort45numbers→ [8, 3, 7, 4, 9, 2] = [8, 3, 7, 4, 9, 2]4647print("Before:", numbers[8, 3, 7, 4, 9, 2])48sorted_numbers = merge_sort(numbers[8, 3, 7, 4, 9, 2])49print("After: ", sorted_numbers)outputBefore: [8, 3, 7, 4, 9, 2]mid ← 3, left ← [8, 3, 7], right ← [4, 9, 2]
pass 1 of 114def merge_sort(arr[8, 3, 7, 4, 9, 2]):5 """Merge sort implementation"""6 # Base case: single element is sorted7 if len(arr) <= 1:8 return arr910 # Divide11 mid→ 3 = len(arr[8, 3, 7, 4, 9, 2]) // 212 left→ [8, 3, 7] = arr[:mid][8, 3, 7]13 right→ [4, 9, 2] = arr[mid:][4, 9, 2]1415 # Recursively sort16 left = merge_sort(left[8, 3, 7])17 right = merge_sort(right)All 11 passes — pass 1 is the card above pass arrarr[:mid]arr[mid:]midleftright1 [8, 3, 7, 4, 9, 2] [8, 3, 7] [4, 9, 2] 3 [8, 3, 7] [4, 9, 2] 2 [8, 3, 7] [8] [3, 7] 1 [8] [3, 7] 3 [8] — — — — — 4 [3, 7] [3] [7] 1 [3] [7] 5 [3] — — — — — 6 [7] — — — — — 7 [4, 9, 2] [4] [9, 2] 1 [4] [9, 2] 8 [4] — — — — — 9 [9, 2] [9] [2] 1 [9] [2] 10 [9] — — — — — 11 [2] — — — — — if len(arr) <= 1:
pass 1 of 66# Base case: single element is sorted7if len(arr[8]) <= 1:8 return arr[8]All 6 passes — pass 1 is the card above pass arr1 [8] 2 [3] 3 [7] 4 [4] 5 [9] 6 [2] left ← [8]
15# Recursively sort16left→ [8] = merge_sort(left)17right = merge_sort(right[3, 7])left ← [3]
15# Recursively sort16left→ [3] = merge_sort(left)17right = merge_sort(right[7])right ← [7]
16left = merge_sort(left)17right→ [7] = merge_sort(right)1819# Merge sorted halves20return merge(left[3], right[7])result ← [], i ← 0, j ← 0
pass 1 of 523def merge(left[3], right[7]):24 """Merge two sorted lists"""25 result→ [] = []26 i→ 0 = j→ 0 = 0All 5 passes — pass 1 is the card above pass leftrightresultij1 [3] [7] [] 0 0 2 [8] [3, 7] [] 0 0 3 [9] [2] [] 0 0 4 [4] [2, 9] [] 0 0 5 [3, 7, 8] [2, 4, 9] [] 0 0 while i < len(left) and j < len(right):
pass 1 of 1128# Compare and merge29while i0 < len(left[3]) and j0 < len(right[7]):30 if left[i] <= right[j]:31 result.append(left[i])All 11 passes — pass 1 is the card above pass ileftjright1 0 [3] 0 [7] 2 0 [8] 0 [3, 7] 3 0 [8] 1 [3, 7] 4 0 [9] 0 [2] 5 0 [4] 0 [2, 9] 6 0 [4] 1 [2, 9] 7 0 [3, 7, 8] 0 [2, 4, 9] 8 0 [3, 7, 8] 1 [2, 4, 9] 9 1 [3, 7, 8] 1 [2, 4, 9] 10 1 [3, 7, 8] 2 [2, 4, 9] 11 2 [3, 7, 8] 2 [2, 4, 9] result ← [3], i ← 1
pass 1 of 529while i < len(left) and j < len(right):30 if left[i]3 <= right[j]7:31 result→ [3].append(left[i]3)32 i→ 1 += 133 else:All 5 passes — pass 1 is the card above pass left[i]right[j]resulti1 3 7 [] → [3] 0 → 1 2 4 9 [2] → [2, 4] 0 → 1 3 3 4 [2] → [2, 3] 0 → 1 4 7 9 [2, 3, 4] → [2, 3, 4, 7] 1 → 2 5 8 9 [2, 3, 4, 7] → [2, 3, 4, 7, 8] 2 → 3 result ← [3, 7]
37# Add remaining elements38result[3].extend(left[i:][])39result→ [3, 7].extend(right[j:][7])4041return result[3, 7]right ← [3, 7]
16left = merge_sort(left)17right→ [3, 7] = merge_sort(right)1819# Merge sorted halves20return merge(left[8], right[3, 7])result ← [3], j ← 1
pass 1 of 631 result.append(left[i])32 i += 133else:34 result→ [3].append(right[j]3)35 j→ 1 += 1All 6 passes — pass 1 is the card above pass right[j]resultj1 3 [] → [3] 0 → 1 2 7 [3] → [3, 7] 1 → 2 3 2 [] → [2] 0 → 1 4 2 [] → [2] 0 → 1 5 2 [] → [2] 0 → 1 6 4 [2, 3] → [2, 3, 4] 1 → 2 result ← [3, 7, 8]
37# Add remaining elements38result→ [3, 7, 8].extend(left[i:][8])39result[3, 7, 8].extend(right[j:][])4041return result[3, 7, 8]left ← [3, 7, 8]
15# Recursively sort16left→ [3, 7, 8] = merge_sort(left)17right = merge_sort(right[4, 9, 2])left ← [4]
15# Recursively sort16left→ [4] = merge_sort(left)17right = merge_sort(right[9, 2])left ← [9]
15# Recursively sort16left→ [9] = merge_sort(left)17right = merge_sort(right[2])right ← [2]
16left = merge_sort(left)17right→ [2] = merge_sort(right)1819# Merge sorted halves20return merge(left[9], right[2])result ← [2, 9]
37# Add remaining elements38result→ [2, 9].extend(left[i:][9])39result[2, 9].extend(right[j:][])4041return result[2, 9]right ← [2, 9]
16left = merge_sort(left)17right→ [2, 9] = merge_sort(right)1819# Merge sorted halves20return merge(left[4], right[2, 9])result ← [2, 4, 9]
37# Add remaining elements38result[2, 4].extend(left[i:][])39result→ [2, 4, 9].extend(right[j:][9])4041return result[2, 4, 9]right ← [2, 4, 9]
16left = merge_sort(left)17right→ [2, 4, 9] = merge_sort(right)1819# Merge sorted halves20return merge(left[3, 7, 8], right[2, 4, 9])result ← [2, 3, 4, 7, 8, 9]
37# Add remaining elements38result[2, 3, 4, 7, 8].extend(left[i:][])39result→ [2, 3, 4, 7, 8, 9].extend(right[j:][9])4041return result[2, 3, 4, 7, 8, 9]sorted_numbers ← [2, 3, 4, 7, 8, 9]
47print("Before:", numbers)48sorted_numbers→ [2, 3, 4, 7, 8, 9] = merge_sort(numbers[8, 3, 7, 4, 9, 2])49print("After: ", sorted_numbers[2, 3, 4, 7, 8, 9])outputAfter: [2, 3, 4, 7, 8, 9]
numbers ← [5, 1, 6]
44# Test merge sort45numbers→ [5, 1, 6] = [5, 1, 6]4647print("Before:", numbers[5, 1, 6])48sorted_numbers = merge_sort(numbers[5, 1, 6])49print("After: ", sorted_numbers)outputBefore: [5, 1, 6]mid ← 1, left ← [5], right ← [1, 6]
pass 1 of 54def merge_sort(arr[5, 1, 6]):5 """Merge sort implementation"""6 # Base case: single element is sorted7 if len(arr) <= 1:8 return arr910 # Divide11 mid→ 1 = len(arr[5, 1, 6]) // 212 left→ [5] = arr[:mid][5]13 right→ [1, 6] = arr[mid:][1, 6]1415 # Recursively sort16 left = merge_sort(left[5])17 right = merge_sort(right)All 5 passes — pass 1 is the card above pass arrarr[:mid]arr[mid:]midleftright1 [5, 1, 6] [5] [1, 6] 1 [5] [1, 6] 2 [5] — — — — — 3 [1, 6] [1] [6] 1 [1] [6] 4 [1] — — — — — 5 [6] — — — — — if len(arr) <= 1:
pass 1 of 36# Base case: single element is sorted7if len(arr[5]) <= 1:8 return arr[5]All 3 passes — pass 1 is the card above pass arr1 [5] 2 [1] 3 [6] left ← [5]
15# Recursively sort16left→ [5] = merge_sort(left)17right = merge_sort(right[1, 6])left ← [1]
15# Recursively sort16left→ [1] = merge_sort(left)17right = merge_sort(right[6])right ← [6]
16left = merge_sort(left)17right→ [6] = merge_sort(right)1819# Merge sorted halves20return merge(left[1], right[6])result ← [], i ← 0, j ← 0
pass 1 of 223def merge(left[1], right[6]):24 """Merge two sorted lists"""25 result→ [] = []26 i→ 0 = j→ 0 = 0while i < len(left) and j < len(right):
pass 1 of 328# Compare and merge29while i0 < len(left[1]) and j0 < len(right[6]):30 if left[i] <= right[j]:31 result.append(left[i])All 3 passes — pass 1 is the card above pass leftrightleft[i]right[j]resultij1 [1] [6] 1 6 [] → [1] 0 → 1 0 2 [5] [1, 6] — 1 [] → [1] 0 0 → 1 3 [5] [1, 6] 5 6 [1] → [1, 5] 0 → 1 1 result ← [1], i ← 1
pass 1 of 229while i < len(left) and j < len(right):30 if left[i]1 <= right[j]6:31 result→ [1].append(left[i]1)32 i→ 1 += 133 else:result ← [1, 6]
37# Add remaining elements38result[1].extend(left[i:][])39result→ [1, 6].extend(right[j:][6])4041return result[1, 6]right ← [1, 6]
16left = merge_sort(left)17right→ [1, 6] = merge_sort(right)1819# Merge sorted halves20return merge(left[5], right[1, 6])result ← [], i ← 0, j ← 0
pass 2 of 223def merge(left[5], right[1, 6]):24 """Merge two sorted lists"""25 result→ [] = []26 i→ 0 = j→ 0 = 0result ← [1], j ← 1
31 result.append(left[i])32 i += 133else:34 result→ [1].append(right[j]1)35 j→ 1 += 1result ← [1, 5], i ← 1
pass 2 of 229while i < len(left) and j < len(right):30 if left[i]5 <= right[j]6:31 result→ [1, 5].append(left[i]5)32 i→ 1 += 133 else:result ← [1, 5, 6]
37# Add remaining elements38result[1, 5].extend(left[i:][])39result→ [1, 5, 6].extend(right[j:][6])4041return result[1, 5, 6]sorted_numbers ← [1, 5, 6]
47print("Before:", numbers)48sorted_numbers→ [1, 5, 6] = merge_sort(numbers[5, 1, 6])49print("After: ", sorted_numbers[1, 5, 6])outputAfter: [1, 5, 6]
The Merge Operation
merge_only.py
Replay: real traced execution (multi-file project)
# Merge two sorted lists
def merge_two_sorted(left, right):
"""Merge two already sorted lists"""
result = []
i = j = 0
# Compare and merge
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
# Add remaining elements
result.extend(left[i:])
result.extend(right[j:])
return result
# Test merging sorted lists
left = [1, 3, 5, 7]
right = [2, 4, 6, 8]
print("Left: ", left)
print("Right:", right)
merged = merge_two_sorted(left, right)
print("Merged:", merged)
# Different sizes
arr1 = [1, 5, 9]
arr2 = [2, 3, 4, 6, 7]
print("\nLeft: ", arr1)
print("Right:", arr2)
merged2 = merge_two_sorted(arr1, arr2)
print("Merged:", merged2)
left ← [1, 3, 5, 7], right ← [2, 4, 6, 8]
25# Test merging sorted lists26left→ [1, 3, 5, 7] = [1, 3, 5, 7]27right→ [2, 4, 6, 8] = [2, 4, 6, 8]2829print("Left: ", left[1, 3, 5, 7])30print("Right:", right[2, 4, 6, 8])3132merged = merge_two_sorted(left[1, 3, 5, 7], right[2, 4, 6, 8])33print("Merged:", merged)outputLeft: [1, 3, 5, 7] Right: [2, 4, 6, 8]result ← [], i ← 0, j ← 0
pass 1 of 24def merge_two_sorted(left[1, 3, 5, 7], right[2, 4, 6, 8]):5 """Merge two already sorted lists"""6 result→ [] = []7 i→ 0 = j→ 0 = 0while i < len(left) and j < len(right):
pass 1 of 149# Compare and merge10while i0 < len(left[1, 3, 5, 7]) and j0 < len(right[2, 4, 6, 8]):11 if left[i] <= right[j]:12 result.append(left[i])14 passes — pass 1 is the card above pass ileftjright1 0 [1, 3, 5, 7] 0 [2, 4, 6, 8] 2 1 [1, 3, 5, 7] 0 [2, 4, 6, 8] 3 1 [1, 3, 5, 7] 1 [2, 4, 6, 8] 4 2 [1, 3, 5, 7] 1 [2, 4, 6, 8] 5 2 [1, 3, 5, 7] 2 [2, 4, 6, 8] 6 3 [1, 3, 5, 7] 2 [2, 4, 6, 8] 7 3 [1, 3, 5, 7] 3 [2, 4, 6, 8] 8 0 [1, 5, 9] 0 [2, 3, 4, 6, 7] 9 1 [1, 5, 9] 0 [2, 3, 4, 6, 7] ⋯ 3 more passes ⋯ 13 2 [1, 5, 9] 3 [2, 3, 4, 6, 7] 14 2 [1, 5, 9] 4 [2, 3, 4, 6, 7] result ← [1], i ← 1
pass 1 of 610while i < len(left) and j < len(right):11 if left[i]1 <= right[j]2:12 result→ [1].append(left[i]1)13 i→ 1 += 114 else:All 6 passes — pass 1 is the card above pass left[i]right[j]resulti1 1 2 [] → [1] 0 → 1 2 3 4 [1, 2] → [1, 2, 3] 1 → 2 3 5 6 [1, 2, 3, 4] → [1, 2, 3, 4, 5] 2 → 3 4 7 8 [1, 2, 3, 4, 5, 6] → [1, 2, 3, 4, 5, 6, 7] 3 → 4 5 1 2 [] → [1] 0 → 1 6 5 6 [1, 2, 3, 4] → [1, 2, 3, 4, 5] 1 → 2 result ← [1, 2], j ← 1
pass 1 of 812 result.append(left[i])13 i += 114else:15 result→ [1, 2].append(right[j]2)16 j→ 1 += 1All 8 passes — pass 1 is the card above pass right[j]resultj1 2 [1] → [1, 2] 0 → 1 2 4 [1, 2, 3] → [1, 2, 3, 4] 1 → 2 3 6 [1, 2, 3, 4, 5] → [1, 2, 3, 4, 5, 6] 2 → 3 4 2 [1] → [1, 2] 0 → 1 5 3 [1, 2] → [1, 2, 3] 1 → 2 6 4 [1, 2, 3] → [1, 2, 3, 4] 2 → 3 7 6 [1, 2, 3, 4, 5] → [1, 2, 3, 4, 5, 6] 3 → 4 8 7 [1, 2, 3, 4, 5, 6] → [1, 2, 3, 4, 5, 6, 7] 4 → 5 result ← [1, 2, 3, 4, 5, 6, 7, 8]
18# Add remaining elements19result[1, 2, 3, 4, 5, 6, 7].extend(left[i:][])20result→ [1, 2, 3, 4, 5, 6, 7, 8].extend(right[j:][8])2122return result[1, 2, 3, 4, 5, 6, 7, 8]merged ← [1, 2, 3, 4, 5, 6, 7, 8], arr1 ← [1, 5, 9], arr2 ← [2, 3, 4, 6, 7]
32merged→ [1, 2, 3, 4, 5, 6, 7, 8] = merge_two_sorted(left[1, 3, 5, 7], right[2, 4, 6, 8])33print("Merged:", merged[1, 2, 3, 4, 5, 6, 7, 8])3435# Different sizes36arr1→ [1, 5, 9] = [1, 5, 9]37arr2→ [2, 3, 4, 6, 7] = [2, 3, 4, 6, 7]3839print("\nLeft: ", arr1[1, 5, 9])40print("Right:", arr2[2, 3, 4, 6, 7])4142merged2 = merge_two_sorted(arr1[1, 5, 9], arr2[2, 3, 4, 6, 7])43print("Merged:", merged2)outputMerged: [1, 2, 3, 4, 5, 6, 7, 8] Left: [1, 5, 9] Right: [2, 3, 4, 6, 7]result ← [], i ← 0, j ← 0
pass 2 of 24def merge_two_sorted(left[1, 5, 9], right[2, 3, 4, 6, 7]):5 """Merge two already sorted lists"""6 result→ [] = []7 i→ 0 = j→ 0 = 0result ← [1, 2, 3, 4, 5, 6, 7, 9]
18# Add remaining elements19result→ [1, 2, 3, 4, 5, 6, 7, 9].extend(left[i:][9])20result[1, 2, 3, 4, 5, 6, 7, 9].extend(right[j:][])2122return result[1, 2, 3, 4, 5, 6, 7, 9]merged2 ← [1, 2, 3, 4, 5, 6, 7, 9]
42merged2→ [1, 2, 3, 4, 5, 6, 7, 9] = merge_two_sorted(arr1[1, 5, 9], arr2[2, 3, 4, 6, 7])43print("Merged:", merged2[1, 2, 3, 4, 5, 6, 7, 9])outputMerged: [1, 2, 3, 4, 5, 6, 7, 9]
merge_operation
Combine two sorted lists into one sorted list by comparing front elements
Trace Example
trace.py
Replay: real traced execution (multi-file project)
# Merge sort with trace
depth = 0
def merge_sort_trace(arr):
"""Merge sort with step-by-step trace"""
global depth
if len(arr) <= 1:
return arr
# Trace divide
print(" " * depth + f"Divide: {arr}")
depth += 1
mid = len(arr) // 2
left = merge_sort_trace(arr[:mid])
right = merge_sort_trace(arr[mid:])
result = merge_trace(left, right)
depth -= 1
print(" " * depth + f"Merged: {result}")
return result
def merge_trace(left, right):
"""Merge with trace"""
global depth
print(" " * depth + f" Merge {left} and {right}")
result = []
i = 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
# Test with trace
numbers = [5, 2, 8, 1, 9]
print("Initial:", numbers)
print()
sorted_numbers = merge_sort_trace(numbers)
print()
print("Final: ", sorted_numbers)
depth ← 0, numbers ← [5, 2, 8, 1, 9]
4depth→ 0 = 0567def merge_sort_trace(arr):8 """Merge sort with step-by-step trace"""9 global depth1011 if len(arr) <= 1:12 return arr1314 # Trace divide15 print(" " * depth + f"Divide: {arr}")16 depth += 11718 mid = len(arr) // 219 left = merge_sort_trace(arr[:mid])20 right = merge_sort_trace(arr[mid:])2122 result = merge_trace(left, right)2324 depth -= 125 print(" " * depth + f"Merged: {result}")2627 return result282930def merge_trace(left, right):31 """Merge with trace"""32 global depth33 print(" " * depth + f" Merge {left} and {right}")3435 result = []36 i = j = 03738 while i < len(left) and j < len(right):39 if left[i] <= right[j]:40 result.append(left[i])41 i += 142 else:43 result.append(right[j])44 j += 14546 result.extend(left[i:])47 result.extend(right[j:])4849 return result505152# Test with trace53numbers→ [5, 2, 8, 1, 9] = [5, 2, 8, 1, 9]5455print("Initial:", numbers[5, 2, 8, 1, 9])56print()57sorted_numbers = merge_sort_trace(numbers[5, 2, 8, 1, 9])58print()outputInitial: [5, 2, 8, 1, 9]depth ← 1, mid ← 2
pass 1 of 97def merge_sort_trace(arr[5, 2, 8, 1, 9]):8 """Merge sort with step-by-step trace"""9 global depth1011 if len(arr) <= 1:12 return arr1314 # Trace divide15 print(" " * depth0 + f"Divide: {arr[5, 2, 8, 1, 9]}")16 depth→ 1 += 11718 mid→ 2 = len(arr[5, 2, 8, 1, 9]) // 219 left = merge_sort_trace(arr[:mid][5, 2])20 right = merge_sort_trace(arr[mid:])outputDivide: [5, 2, 8, 1, 9]All 9 passes — pass 1 is the card above pass arrarr[:mid]depthmid1 [5, 2, 8, 1, 9] [5, 2] 0 → 1 2 2 [5, 2] [5] 1 → 2 1 3 [5] — — — 4 [2] — — — 5 [8, 1, 9] [8] 1 → 2 1 6 [8] — — — 7 [1, 9] [1] 2 → 3 1 8 [1] — — — 9 [9] — — — if len(arr) <= 1:
pass 1 of 511if len(arr[5]) <= 1:12 return arr[5]All 5 passes — pass 1 is the card above pass arr1 [5] 2 [2] 3 [8] 4 [1] 5 [9] left ← [5]
18mid = len(arr) // 219left→ [5] = merge_sort_trace(arr[:mid][5])20right = merge_sort_trace(arr[mid:][2])right ← [2]
19left = merge_sort_trace(arr[:mid])20right→ [2] = merge_sort_trace(arr[mid:][2])2122result = merge_trace(left[5], right[2])result ← [], i ← 0, j ← 0
pass 1 of 430def merge_trace(left[5], right[2]):31 """Merge with trace"""32 global depth33 print(" " * depth2 + f" Merge {left[5]} and {right[2]}")3435 result→ [] = []36 i→ 0 = j→ 0 = 0output Merge [5] and [2]All 4 passes — pass 1 is the card above pass leftrightdepthresultij1 [5] [2] 2 [] 0 0 2 [1] [9] 3 [] 0 0 3 [8] [1, 9] 2 [] 0 0 4 [2, 5] [1, 8, 9] 1 [] 0 0 while i < len(left) and j < len(right):
pass 1 of 738while i0 < len(left[5]) and j0 < len(right[2]):39 if left[i] <= right[j]:40 result.append(left[i])All 7 passes — pass 1 is the card above pass ileftjright1 0 [5] 0 [2] 2 0 [1] 0 [9] 3 0 [8] 0 [1, 9] 4 0 [8] 1 [1, 9] 5 0 [2, 5] 0 [1, 8, 9] 6 0 [2, 5] 1 [1, 8, 9] 7 1 [2, 5] 1 [1, 8, 9] result ← [2], j ← 1
pass 1 of 340 result.append(left[i])41 i += 142else:43 result→ [2].append(right[j]2)44 j→ 1 += 1All 3 passes — pass 1 is the card above pass right[j]resultj1 2 [] → [2] 0 → 1 2 1 [] → [1] 0 → 1 3 1 [] → [1] 0 → 1 result ← [2, 5]
46result→ [2, 5].extend(left[i:][5])47result[2, 5].extend(right[j:][])4849return result[2, 5]result ← [2, 5], depth ← 1
22result→ [2, 5] = merge_trace(left[5], right[2])2324depth→ 1 -= 125print(" " * depth1 + f"Merged: {result[2, 5]}")2627return result[2, 5]output Merged: [2, 5]arr[:mid] ← [5, 2], left ← [2, 5]
18mid = len(arr) // 219left→ [2, 5] = merge_sort_trace(arr[:mid]→ [5, 2])20right = merge_sort_trace(arr[mid:][8, 1, 9])left ← [8]
18mid = len(arr) // 219left→ [8] = merge_sort_trace(arr[:mid][8])20right = merge_sort_trace(arr[mid:][1, 9])left ← [1]
18mid = len(arr) // 219left→ [1] = merge_sort_trace(arr[:mid][1])20right = merge_sort_trace(arr[mid:][9])right ← [9]
19left = merge_sort_trace(arr[:mid])20right→ [9] = merge_sort_trace(arr[mid:][9])2122result = merge_trace(left[1], right[9])result ← [1], i ← 1
pass 1 of 438while i < len(left) and j < len(right):39 if left[i]1 <= right[j]9:40 result→ [1].append(left[i]1)41 i→ 1 += 142 else:All 4 passes — pass 1 is the card above pass left[i]right[j]resulti1 1 9 [] → [1] 0 → 1 2 8 9 [1] → [1, 8] 0 → 1 3 2 8 [1] → [1, 2] 0 → 1 4 5 8 [1, 2] → [1, 2, 5] 1 → 2 result ← [1, 9]
46result[1].extend(left[i:][])47result→ [1, 9].extend(right[j:][9])4849return result[1, 9]result ← [1, 9], depth ← 2
22result→ [1, 9] = merge_trace(left[1], right[9])2324depth→ 2 -= 125print(" " * depth2 + f"Merged: {result[1, 9]}")2627return result[1, 9]output Merged: [1, 9]arr[mid:] ← [1, 9], right ← [1, 9]
19left = merge_sort_trace(arr[:mid])20right→ [1, 9] = merge_sort_trace(arr[mid:]→ [1, 9])2122result = merge_trace(left[8], right[1, 9])result ← [1, 8, 9]
46result[1, 8].extend(left[i:][])47result→ [1, 8, 9].extend(right[j:][9])4849return result[1, 8, 9]result ← [1, 8, 9], depth ← 1
22result→ [1, 8, 9] = merge_trace(left[8], right[1, 9])2324depth→ 1 -= 125print(" " * depth1 + f"Merged: {result[1, 8, 9]}")2627return result[1, 8, 9]output Merged: [1, 8, 9]arr[mid:] ← [8, 1, 9], right ← [1, 8, 9]
19left = merge_sort_trace(arr[:mid])20right→ [1, 8, 9] = merge_sort_trace(arr[mid:]→ [8, 1, 9])2122result = merge_trace(left[2, 5], right[1, 8, 9])result ← [1, 2, 5, 8, 9]
46result[1, 2, 5].extend(left[i:][])47result→ [1, 2, 5, 8, 9].extend(right[j:][8, 9])4849return result[1, 2, 5, 8, 9]result ← [1, 2, 5, 8, 9], depth ← 0
22result→ [1, 2, 5, 8, 9] = merge_trace(left[2, 5], right[1, 8, 9])2324depth→ 0 -= 125print(" " * depth0 + f"Merged: {result[1, 2, 5, 8, 9]}")2627return result[1, 2, 5, 8, 9]outputMerged: [1, 2, 5, 8, 9]sorted_numbers ← [1, 2, 5, 8, 9]
56print()57sorted_numbers→ [1, 2, 5, 8, 9] = merge_sort_trace(numbers[5, 2, 8, 1, 9])58print()59print("Final: ", sorted_numbers[1, 2, 5, 8, 9])outputFinal: [1, 2, 5, 8, 9]
In-Place Variation
inplace.py
Replay: real traced execution (multi-file project)
# In-place merge sort
def merge_sort_inplace(arr, left=0, right=None):
"""Merge sort that modifies array in place"""
if right is None:
right = len(arr) - 1
# Divide and conquer
if left < right:
mid = left + (right - left) // 2
merge_sort_inplace(arr, left, mid)
merge_sort_inplace(arr, mid + 1, right)
merge_inplace(arr, left, mid, right)
def merge_inplace(arr, left, mid, right):
"""Merge in place using temporary list"""
# Create temporary arrays
left_arr = arr[left:mid + 1]
right_arr = arr[mid + 1:right + 1]
# Merge back into original
i = j = 0
k = left
while i < len(left_arr) and j < len(right_arr):
if left_arr[i] <= right_arr[j]:
arr[k] = left_arr[i]
i += 1
else:
arr[k] = right_arr[j]
j += 1
k += 1
# Copy remaining
while i < len(left_arr):
arr[k] = left_arr[i]
i += 1
k += 1
while j < len(right_arr):
arr[k] = right_arr[j]
j += 1
k += 1
# Test in-place version
numbers = [38, 27, 43, 3, 9, 82, 10]
print("Before:", numbers)
merge_sort_inplace(numbers)
print("After: ", numbers)
numbers ← [38, 27, 43, 3, 9, 82, 10]
50# Test in-place version51numbers→ [38, 27, 43, 3, 9, 82, 10] = [38, 27, 43, 3, 9, 82, 10]5253print("Before:", numbers[38, 27, 43, 3, 9, 82, 10])54merge_sort_inplace(numbers[38, 27, 43, 3, 9, 82, 10])55print("After: ", numbers)outputBefore: [38, 27, 43, 3, 9, 82, 10]def merge_sort_inplace(arr, left=0, right=None):
pass 1 of 134def merge_sort_inplace(arr[38, 27, 43, 3, 9, 82, 10], left0=0, rightNone=NoneNone):5 """Merge sort that modifies array in place"""6 if right is None:13 passes — pass 1 is the card above pass arrleftmidright1 [38, 27, 43, 3, 9, 82, 10] 0 — None → 6 2 [38, 27, 43, 3, 9, 82, 10] 0 — 3 3 [38, 27, 43, 3, 9, 82, 10] 0 — 1 4 [38, 27, 43, 3, 9, 82, 10] 0 0 0 5 [38, 27, 43, 3, 9, 82, 10] 1 0 1 6 [27, 38, 43, 3, 9, 82, 10] 2 — 3 7 [27, 38, 43, 3, 9, 82, 10] 2 2 2 8 [27, 38, 43, 3, 9, 82, 10] 3 2 3 9 [3, 27, 38, 43, 9, 82, 10] 4 — 6 ⋯ 2 more passes ⋯ 12 [3, 27, 38, 43, 9, 82, 10] 5 4 5 13 [3, 27, 38, 43, 9, 82, 10] 6 5 6 right ← 6
5"""Merge sort that modifies array in place"""6if rightNone is None:7 right→ 6 = len(arr[38, 27, 43, 3, 9, 82, 10]) - 1mid ← 3
pass 1 of 69# Divide and conquer10if left0 < right6:11 mid→ 3 = left0 + (right6 - left) // 21213 merge_sort_inplace(arr[38, 27, 43, 3, 9, 82, 10], left0, mid3)14 merge_sort_inplace(arr, mid + 1, right)All 6 passes — pass 1 is the card above pass leftrightarrmid1 0 6 [38, 27, 43, 3, 9, 82, 10] 3 2 0 3 [38, 27, 43, 3, 9, 82, 10] 1 3 0 1 [38, 27, 43, 3, 9, 82, 10] 0 4 2 3 [27, 38, 43, 3, 9, 82, 10] 2 5 4 6 [3, 27, 38, 43, 9, 82, 10] 5 6 4 5 [3, 27, 38, 43, 9, 82, 10] 4 left_arr ← [38], right_arr ← [27], i ← 0, j ← 0, k ← 0
pass 1 of 619def merge_inplace(arr[38, 27, 43, 3, 9, 82, 10], left0, mid0, right1):20 """Merge in place using temporary list"""21 # Create temporary arrays22 left_arr→ [38] = arr[left:mid + 1][38]23 right_arr→ [27] = arr[mid + 1:right + 1][27]2425 # Merge back into original26 i→ 0 = j→ 0 = 027 k→ 0 = left0All 6 passes — pass 1 is the card above pass arrleftmidrightarr[left:mid + 1]arr[mid + 1:right + 1]left_arrright_arrijk1 [38, 27, 43, 3, 9, 82, 10] 0 0 1 [38] [27] [38] [27] 0 0 0 2 [27, 38, 43, 3, 9, 82, 10] 2 2 3 [43] [3] [43] [3] 0 0 2 3 [27, 38, 3, 43, 9, 82, 10] 0 1 3 [27, 38] [3, 43] [27, 38] [3, 43] 0 0 0 4 [3, 27, 38, 43, 9, 82, 10] 4 4 5 [9] [82] [9] [82] 0 0 4 5 [3, 27, 38, 43, 9, 82, 10] 4 5 6 [9, 82] [10] [9, 82] [10] 0 0 4 6 [3, 27, 38, 43, 9, 10, 82] 0 3 6 [3, 27, 38, 43] [9, 10, 82] [3, 27, 38, 43] [9, 10, 82] 0 0 0 while i < len(left_arr) and j < len(right_arr):
pass 1 of 1429while i0 < len(left_arr[38]) and j0 < len(right_arr[27]):30 if left_arr[i] <= right_arr[j]:31 arr[k] = left_arr[i]14 passes — pass 1 is the card above pass ileft_arrjright_arr1 0 [38] 0 [27] 2 0 [43] 0 [3] 3 0 [27, 38] 0 [3, 43] 4 0 [27, 38] 1 [3, 43] 5 1 [27, 38] 1 [3, 43] 6 0 [9] 0 [82] 7 0 [9, 82] 0 [10] 8 1 [9, 82] 0 [10] 9 0 [3, 27, 38, 43] 0 [9, 10, 82] ⋯ 3 more passes ⋯ 13 2 [3, 27, 38, 43] 2 [9, 10, 82] 14 3 [3, 27, 38, 43] 2 [9, 10, 82] arr[k] ← 27, j ← 1
pass 1 of 631 arr[k] = left_arr[i]32 i += 133else:34 arr[k]→ 27 = right_arr[j]2735 j→ 1 += 136k += 1All 6 passes — pass 1 is the card above pass right_arr[j]arr[k]j1 27 27 0 → 1 2 3 3 0 → 1 3 3 3 0 → 1 4 10 10 0 → 1 5 9 9 0 → 1 6 10 10 1 → 2 k ← 1
35 j += 136k→ 1 += 1arr[k] ← 38, i ← 1, k ← 2, arr ← [27, 38, 43, 3, 9, 82, 10], left ← 0
pass 1 of 313 merge_sort_inplace(arr→ [27, 38, 43, 3, 9, 82, 10], left→ 0, mid→ 1)14 merge_sort_inplace(arr[27, 38, 43, 3, 9, 82, 10], mid1 + 1, right3)1516 merge_inplace(arr→ [27, 38, 43, 3, 9, 82, 10], left0, mid0, right1)171819def merge_inplace(arr, left, mid, right):20 """Merge in place using temporary list"""21 # Create temporary arrays22 left_arr = arr[left:mid + 1]23 right_arr = arr[mid + 1:right + 1]2425 # Merge back into original26 i = j = 027 k = left2829 while i < len(left_arr) and j < len(right_arr):30 if left_arr[i] <= right_arr[j]:31 arr[k] = left_arr[i]32 i += 133 else:34 arr[k] = right_arr[j]35 j += 136 k += 13738 # Copy remaining39 while i0 < len(left_arr[38]):40 arr[k]→ 38 = left_arr[i]3841 i→ 1 += 142 k→ 2 += 1All 3 passes — pass 1 is the card above pass left_arrleft_arr[i]arr[k]ikarrleftmidright1 [38] 38 38 0 → 1 1 → 2 [38, 27, 43, 3, 9, 82, 10] → [27, 38, 43, 3, 9, 82, 10] 0 0 → 1 1 2 [43] 43 43 0 → 1 3 → 4 [27, 38, 43, 3, 9, 82, 10] → [27, 38, 3, 43, 9, 82, 10] 0 1 3 3 [9, 82] 82 82 1 → 2 6 → 7 [3, 27, 38, 43, 9, 82, 10] → [3, 27, 38, 43, 9, 10, 82] 0 3 6 k ← 3
35 j += 136k→ 3 += 1k ← 1
35 j += 136k→ 1 += 1arr[k] ← 27, i ← 1
pass 1 of 829while i < len(left_arr) and j < len(right_arr):30 if left_arr[i]27 <= right_arr[j]43:31 arr[k]→ 27 = left_arr[i]2732 i→ 1 += 133 else:All 8 passes — pass 1 is the card above pass left_arr[i]right_arr[j]arr[k]i1 27 43 27 0 → 1 2 38 43 38 1 → 2 3 9 82 9 0 → 1 4 9 10 9 0 → 1 5 3 9 3 0 → 1 6 27 82 27 1 → 2 7 38 82 38 2 → 3 8 43 82 43 3 → 4 k ← 2
35 j += 136k→ 2 += 1k ← 3
35 j += 136k→ 3 += 1arr[k] ← 43, j ← 2, k ← 4, arr ← [3, 27, 38, 43, 9, 82, 10], left ← 0
pass 1 of 313 merge_sort_inplace(arr→ [3, 27, 38, 43, 9, 82, 10], left→ 0, mid→ 3)14 merge_sort_inplace(arr[3, 27, 38, 43, 9, 82, 10], mid3 + 1, right6)1516 merge_inplace(arr→ [3, 27, 38, 43, 9, 82, 10], left0, mid1, right3)171819def merge_inplace(arr, left, mid, right):20 """Merge in place using temporary list"""21 # Create temporary arrays22 left_arr = arr[left:mid + 1]23 right_arr = arr[mid + 1:right + 1]2425 # Merge back into original26 i = j = 027 k = left2829 while i < len(left_arr) and j < len(right_arr):30 if left_arr[i] <= right_arr[j]:31 arr[k] = left_arr[i]32 i += 133 else:34 arr[k] = right_arr[j]35 j += 136 k += 13738 # Copy remaining39 while i < len(left_arr):40 arr[k] = left_arr[i]41 i += 142 k += 14344 while j1 < len(right_arr[3, 43]):45 arr[k]→ 43 = right_arr[j]4346 j→ 2 += 147 k→ 4 += 1All 3 passes — pass 1 is the card above pass right_arrright_arr[j]rightarr[k]jkarrleftmid1 [3, 43] 43 3 43 1 → 2 3 → 4 [27, 38, 3, 43, 9, 82, 10] → [3, 27, 38, 43, 9, 82, 10] 0 1 → 3 2 [82] 82 5 82 0 → 1 5 → 6 [3, 27, 38, 43, 9, 82, 10] 4 4 → 5 3 [9, 10, 82] 82 6 82 2 → 3 6 → 7 [3, 27, 38, 43, 9, 10, 82] → [3, 9, 10, 27, 38, 43, 82] 0 3 k ← 5
35 j += 136k→ 5 += 1k ← 5
35 j += 136k→ 5 += 1k ← 6
35 j += 136k→ 6 += 1k ← 1
35 j += 136k→ 1 += 1k ← 2
35 j += 136k→ 2 += 1k ← 3
35 j += 136k→ 3 += 1k ← 4
35 j += 136k→ 4 += 1k ← 5
35 j += 136k→ 5 += 1k ← 6
35 j += 136k→ 6 += 1numbers ← [3, 9, 10, 27, 38, 43, 82]
53print("Before:", numbers)54merge_sort_inplace(numbers→ [3, 9, 10, 27, 38, 43, 82])55print("After: ", numbers[3, 9, 10, 27, 38, 43, 82])outputAfter: [3, 9, 10, 27, 38, 43, 82]
Characteristics
- Time complexity: O(n log n) - always
- Space complexity: O(n) - requires temporary lists
- Stable: maintains relative order of equal elements
- Not in-place: requires additional memory
- Predictable: always same performance
guaranteed_performance
O(n log n) in all cases - best, average, and worst
When to Use
- Need guaranteed O(n log n) performance
- Stability matters
- Large datasets
- External sorting
Exercise: practical.py
Implement merge sort to sort a list of log entries by timestamp, then merge two sorted log files into one