Here is some C code that does merge sort. It assumes that two arrays,

void merge (float [], int, int, int); /* sort the (sub)array v from start to end */ void merge_sort (float v[], int start, int end) { int middle; /* the middle of the subarray */ /* no elements to sort */ if (start == end) return; /* one element; already sorted! */ if (start == end - 1) return; /* find the middle of the array, splitting it into two subarrays */ middle = (start + end) / 2; /* sort the subarray from start..middle */ merge_sort (v, start, middle); /* sort the subarray from middle..end */ merge_sort (v, middle, end); /* merge the two sorted halves */ merge (v, start, middle, end); } /* merge the subarray v[start..middle] with v[middle..end], placing the * result back into v. */ void merge (float v[], int start, int middle, int end) { int v1_n, v2_n, v1_index, v2_index, i; /* number of elements in first subarray */ v1_n = middle - start; /* number of elements in second subarray */ v2_n = end - middle; /* fill v1 and v2 with the elements of the first and second * subarrays, respectively */ for (i=0; i<v1_n; i++) v1[i] = v[start + i]; for (i=0; i<v2_n; i++) v2[i] = v[middle + i]; /* v1_index and v2_index will index into v1 and v2, respectively... */ v1_index = 0; v2_index = 0; /* ... as we pick elements from one or the other to place back * into v */ for (i=0; (v1_index < v1_n) && (v2_index < v2_n); i++) { /* current v1 element less than current v2 element? */ if (v1[v1_index] < v2[v2_index]) /* if so, this element belong as next in v */ v[start + i] = v1[v1_index++]; else /* otherwise, the element from v2 belongs there */ v[start + i] = v2[v2_index++]; } /* clean up; either v1 or v2 may have stuff left in it */ for (; v1_index < v1_n; i++) v[start + i] = v1[v1_index++]; for (; v2_index < v2_n; i++) v[start + i] = v2[v2_index++]; }The function

We need to come up with a function that expresses the number of array
accesses done by merge sort. We'll call this function *T*(*n*).
*T* will start out taking a recursive definition, just like the
`merge_sort` function. At each recursive call of `merge_sort`,
*n* in the definition of *T* will be the number of elements
being sorted for this call, `end - start`.

Assume for convenience that *n* is a power of two. We can generalize
this later (but we won't since we're lazy), but the analysis is easier
this way. So each time we subdivide v into `start..middle`
and `middle..end`, the subarrays are of equal size, each of
size *n*/2. Thus in the function `merge`, `v1_n` =
`v2_n` = *n*/2.

`merge_sort` is called recursively twice, each time with *n*
half what it was before (e.g., `start..middle` is only half
`start..end`). `merge` does a number of array accesses
proportional to `v1_n` and `v2_n` (i.e., *n*/2).
Now we can define *T*:

The first twoT(n) =

- 2
T(n/2) + the time formergewithv1_n=v2_n=n/2, ifn> 1,- 0 otherwise.

So now we have:

We'd like to get a closed form for this if we can; this type ofT(n) =

- 2
T(n/2) + 6n, ifn> 1,- 0 otherwise.

Let 2^{i} = *n* (remember, we said *n* is a power
of two; now we're just saying *k* is that power). Substituting and
commuting, we get:

If we carry out the recursion, it looks like this:T(2^{i}) =

- 6 · 2
^{i}+ 2T(2^{i-1}) ifi> 0,- 0 otherwise.

6 · 2Multiplying the twos through:^{i}+ 2 (6 · 2^{i-1}+ 2 (6 · 2^{i-2}+ 2 (6 · 2^{i-3}+ ... + 2 (6 · 2^{1}) + 0) ... )

6 · 2We can rewrite this as:^{i}+2 · 6 · 2^{i-1}+4 · 6 · 2^{i-2}+8 · 6 · 2^{i-3}+ ... + ? (6 · 2^{1}) + 0) ... )

2Substituting back, we get:^{i}= 2^{k}

[ 2^{k}· 6 · 2^{i-k}] =

k= 0

2^{i}= 2^{k}

6 [ 2^{k}· 2^{i}/2^{k}] =

k= 0

2^{i}= 2^{k}

6·2^{i}1

k= 0

And if we haven't had enough, we can remember that logn= 2^{k}

6n1 =

k= 0

k= log_{2}n

6n1 =

k= 0

6n(log_{2}n+ 1) = 6nlog_{2}n+ 6n

When we look at the orders of functions in terms of theta, omega, and "big-oh" notation, we'll see that the lower order terms and the constants are unimportant;T(n) = 8.6561nlnn+ 6n

This function *n* log *n* grows much more slowly than
the *n*^{2} term for selection sort as we saw in the last lecture,
so merge sort is a much faster sort. This speed does come with a price,
though: merge sort as presented above requires twice the memory since `v1`
and `v2` must have sizes that sum to *n*.