These lecture notes present three different sorting routines: Selection Sort,
Merge Sort, and Quicksort. Each of these routines takes three arguments: an
array of items to sort; the low and high indices in the array between which
lie the elements we wish to sort. We will sort arrays of integers, but
the reader should note that these algorithms can be used to sort floating
point numbers, rationals, fractions, etc.
We define the types `data` and `index` which we will use to
index the array. This is to avoid the confusion between integers in the
array and integers used to index the array.

The Selection Sort algorithm works by repeatedly finding the next item in
the sequence and putting that item in its proper place. This is easily
accomplished by a pair of nested loops. The inner for loop finds the index
of the smallest element of the subarray `A[i...high]`.

Merge Sort relies on the `merge` function to merge together two
sorted arrays. Merge Sort gets its efficiency from the fact that at most
one comparison is needed for each item being merged. Think about merging
two decks of cards, `A` and `B`, into a third deck
`C`. Decks `A` and `B` are assumed to each be already
in sorted order. Deck `C` stars out empty. You compare the top
cards from each deck and place the smaller of the two, face down, on the
merged deck. When either deck `A` or deck `B` becomes empty,
you place the entire remaining deck, face down, onto deck `C`. The
key here is that the two decks, `A` and `B` are sorted to
begin with. At most one comparison is made for each card merged. When
one of the decks becomes empty, no further comparisons are done and the entire
remaining deck is merged in at once. This is the basis for the following
merge algorithm.
In this algorithm, the "cards" are stored in an array. Deck `A` is
stored in indices `low1..high1`, inclusive. Deck `B` is
stored in indices `low2..high2`. We further stipulate that the two
"decks" are contiguous in the array (the last card of deck `A`
comes just before the first card of deck `B`). The
`mergesort` algorithm uses the `merge` algorithm (below) to
sort the entire array. To sort the whole array `A`, `low`
would be zero and high would be the maximum index in the array.

Merge Sort breaks the array down into smaller and smaller pieces until the individual pieces are just one item in size. Since a single item is already sorted, we can merge two contiguous items. The Merge Sort algorithm therefore breaks the array down into smaller chunks on the way down the recursion tree. On the way back up, it merges these smaller pieces of the array into larger pieces. One could say that the sorting is done on the way back up the tree.

In Quicksort, the partitioning is done on the way down the recursion tree.
One could say that the sorting is done on the way down. The
`partition()` function places all the elements smaller than the
first element in the first part of the array and all the elements larger
than the first element in the second part. The `partition()`
function starts an index at each end of the array and moves them inward.
Whenever two values that are in the wrong halves are found, they are
swapped. When the two indices meet, the partitioning is complete.

Much modified by *Richard Chang* Fri Feb 06 16:02:42 EST 1998.