# Merge sort#

Merge sort is a divide-and-conquer approach to sorting that generates a new list. Like quicksort, it works by splitting the list in half. Unlike quicksort, the idea is quite simple:

• Split the list in two arbitrarily.

• Recursively sort each of the split lists.

• Merge the shorter, sorted lists into a single list.

Here’s the pseudocode:

```-- merge - merge two sorted lists into a single list
merge(l1, l2):
if l1 is empty: return l2
if l2 is empty: return l1

if l1[0] < l2[0]:
return l1[0] followed by merge(l1[1:], l2)
else:
return l2[0] followed by merge(l1, l2[1:])

-- mergesort - sort a list l into a new list
mergesort(l):
split l arbitrarily into two lists l1 and l2 of nearly equal length
l1_sorted = mergesort(l1)
l2_sorted = mergesort(l2)
return merge(l1_sorted, l2_sorted)
```

For the split, we can do something simple: copy every other element to one of two lists. Let’s try it in Python:

## Correctness#

The correctness of merge sort is substantially easier to see than for quicksort. The `split` procedure is more or less arbitrary, and produces lists that are approximately half the list in length. The `merge` procedure will clearly produce a sorted list from two sorted lists: each time it picks off the lowest element on the front of the two lists. The `mergesort` procedure itself is quite simple: it splits the list, sorts them (guaranteed to be correct by an inductive argument), and then merges them.

## Performance#

Merge sort will produce recursions with a perfect tree pattern: each recursive call splits the list in half. We don’t have to worry about pivot elements the way that quicksort does. We’ll get the `n * log2(n)` comparisons every time.

One big difference with quicksort is that merge sort produces new lists—and by default, it produces quite a few of them! It’s possible to use less space than our implementation: in general, to merge sort a list of `n` elements, you need to allocate space for another `n` elements. Our code allocates as it goes, and the merge will allocate again.

Our `split` routine splits every other item. In Python, it’d be easy enough to define a simpler split as, e.g., `(l[0:len(l)//2], l[len(l)//2:])`. Efficient implementations may use ranges of the original list and do some work in place.