Algorithm

Take a list of length .

We can use the divide and conquer approach to sort this array. By splitting the array in half, we can sort each subarray individually, and recombine them to form a larger sorted list. As our base case, we have a list of size 1, which is already sorted.

Note that if we have two sorted lists, we can easily “zip” them together to form a larger list in time (keep picking the smallest / largest value from either list).

This process can be done recursively!

For example, given our above list, we sort it with MergeSort as follows:

graph TD
      1[5 1 2 3 4 2] -.->
          2[5 1 2] & 3[3 4 2];

      subgraph Splitting
      2 -.-> 4[5 1] & 5[2];
      3 -.-> 6[3 4] & 7[2];

      4 -.-> 8[5] & 9[1];
      5 -.-> 10[2];
      6 -.-> 11[3] & 12[4];
      7 -.-> 13[2];
      end

      subgraph Merging
      9 & 8 -.-> a[1 5];
      10 -.-> b[2];
      11 & 12 -.-> c[3 4];
      13 -.-> d[2];

      a & b -.-> e[1 2 5];
      c & d -.-> f[2 3 4];
      end

      e & f -.-> g[1 2 2 3 4 5];

Pseudocode

Pseudocode for Merge Sort is given below.

def merge_sort(array):
    if len(array) > 1:
       middle = len(array) // 2
 
       left_subarray = array[0:middle-1]
       right_subarray = array[middle:len(array)]
 
       left_subarray = merge_sort(left_subarray)
       right_subarray = merge_sort(right_subarray)
 
       # merge lists by "zipping" them together.
       array = merge_sorted_lists(left_subarray, right_subarray)
 
    return array

Let’s find the time complexity of merge sort! Merge sort yields the recurrence relation:

We can solve this relation easily using the Master Theorem. We find that , , and see that .

We see that we satisfy the Master Theorem (property 2) with and , giving us

Note that this represents all possible (best, worst, average) cases!

Additionally, we find

  • The auxilliary memory is , as at the highest recursive call, we use up space (lengths of left and right subarrays combined). Note that we disregard lower recursive calls, as when they finish, the memory is freed.
  • The algorithm can be either stable or unstable, depending on the comparisons performed in the merge_sorted_lists() function.
  • The algorithm is not in place, as it generates new lists every recursive call.