Contents:

- Description of MergeSort
- Time bounds
- An expression for
*T(n)* - Recursive definitions and recurrence relations
*T(n)*for particular*n*- MergeSort in action
- Further explorations
- Feedback

- If
*n<2*then the array is already sorted. Stop now. - Otherwise,
*n>1*, and we perform the following three steps in sequence:- Sort the left half of the the array.
- Sort the right half of the the array.
- Merge the now-sorted left and right halves.

It is difficult to describe
*M(n)*
exactly, so instead we describe a simpler function
*T(n)*
which bounds
*M(n)*
from above,
i.e.
*M(n) <= T(n)*.

T(n) = 0, ifn<2.

The induction case says that the number of comparisons
used to sort *n* items is at most
the sum of the worst-case number of comparisons for each
of the three steps of the induction case of MergeSort.
That is,

Let's look at this expression one term at a time.T(n) = T(n/2) + T(n/2) + n, ifn>1.

The first term accounts for the number of comparisons
used to sort the left half of the array. The left half of the array
has half as many elements as the whole array, so
*T(n/2)* is enough to account for all these comparisons.

The second term is a bound on the number of comparisons used
to sort the right half of the array. Like the left
half,
*T(n/2)* is enough here.

The last term, *n* is an upper bound on the number of comparisons
used to merge two sorted arrays. (Actually, *n-1* is a tighter
bound, but let's keep things simple.)

When a numerical expression is defined recursively, we call its
set of defining equations a *recurrence relation*.

Recursive definitions (and recurrence relations)
only make sense if we ``hit bottom'' at some point.
That is, unless the recursion terminates, we can't assign meaning
to *T(n)*. That's why we needed the base case.

How do we compute *T(16)*? One way is to unfold the recurrence all
the way until we hit bottom.

T(16) = 2T(8) + 16Now that we've hit bottom, we can ``bounce back up'' by substituting up this table.

T(8) = 2T(4) + 8

T(4) = 2T(2) + 4

T(2) = 2T(1) + 2

T(1) = 0

T(1) = 0

T(2) = 2T(1) + 2 = 0 + 2

T(4) = 2T(2) + 4 = 4 + 4 = 8

T(8) = 2T(4) + 8 = 16 + 8 = 24

T(16) = 2T(8) + 16 = 48 + 16 = 64

So MergeSort requires at most 64 comparisons to sort 16 elements. Lets see if this is true.

Ok. I hope you've seen it sort at least once. Now I'll explain the applet in a bit more detail.

To sort the left half of the array, the program calls itself recursively, passing the left half of the bars down to a new activation of MergeSort. This happens repeatedly until we have an array of only one element. As noted earlier, one-element arrays are already sorted. Bars in sorted arrays are coloured green (or light grey on a black and white screen).

When the left half of an array is sorted, we sort the right half.

Once the two halves of an array have been sorted by recursive calls,
MergeSort *merges* the two sorted halves into a sorted whole.
This is done by examining and comparing the smallest remaining bar in each
of the sorted halves. The two bars being compared are coloured
red (or medium grey). The smaller of these two bars turns green and
is moved up and
tacked onto the right end of the parent array.

When one of the two subarrays becomes empty, the remaining bars in the other subarray are copied in order into the parent array. No comparisons need to be made.

That describes the workings of MergeSort. I suggest you go back, click on the ``Load input'' button, then click on the ``Go'' button, and adjust the speed slider so that you can see the comparisons being made. Then come back.

I have used strict inequality because we have actually overestimated the number of comparisons required for merging by 1 at each level. (To tell you the truth, it's really because I couldn't find a nice-looking less-than-or-equal-to sign that would fit in that space!)

If you are adventurous, you can type in your own values for the heights of the bars by first clicking on the text box next to the input choice menu, and then typing. Actually, you can specify any set of numbers you like, but only the first 16 will be looked at. Even then, the program doesn't use the absolute values as bar heights, but only their relative ordering. If you type in fewer than 16 numbers, then the last number is repeated. For example, to see what MergeSort does when when all the inputs are the same, type in just a single 1 in the text box, then load the input, and click on ``Go''.

If you are adventurous but lazy, then you can just click on the button labelled ``Shuffle now''. This randomly rearranges the numbers in the text box. For interesting results, select the ``Ascending'' input and then shuffle it a few times.

- What if
*n*isn't a power of 2? - Tightening the estimation:
- Write down a recurrence relation for
*T'(n)*which uses the tighter estimate of*n-1*comparisons for merging two lists into one list of length*n*. - Compute the value of
*T'(16)*. - Can you find a 16-element input that forces MergeSort to use
*T'(16)*comparisons?

- Write down a recurrence relation for
- Can you describe a worst-case input for MergeSort for general
*n*? - Can you find a closed form solution for
*T(n)*? - Can you find a closed form solution for
*T(n)*to within multiplicative and additive constants, i.e. find a closed form expression*f(n)*so that*T(n)*is*O(f(n))*? Hint: the answer to that is on this web page, but its derivation is not. - What, besides comparisons, takes time when actually sorting arrays?
- What resources, besides time, does the above implementation of MergeSort use? How much? Can you make MergeSort more efficient in that respect?

Thanks,

David

Copyright 1996, David Neto.

Professor Allan Borodin aided in the conceptual design of the applet.

Back to David Neto's teaching page

Back to David Neto's Java page

Back to David Neto's home page