next up previous contents index
Next: Development and Debugging Up: Examples Previous: Example One: Flatten

Example Two: Quicksort

 

                 

The Quicksort  algorithm may be easily defined in Scheme. For those not familiar with this algorithm, Quicksort sorts a list (in this case, a list of numbers) in the following manner:

  1. If the list is empty, it is obviously already sorted, so we merely return it. Otherwise...
  2. Choose a `pivot'. The easiest way is to choose the first element of the list as the pivot.
  3. Partition the list into three sublists: the elements in the list that are less than the pivot, the elements that are equal to the pivot, and the elements that are greater than the pivot.
  4. Recursively call Quicksort to sort the list of lesser elements and the list of greater elements. The list of equal elements all have the same value, so it is already sorted.
  5. Concatenate the sorted list of lesser elements, the list of equal elements, and the sorted list of greater elements, and return it as the sorted list.
This may be written in Scheme as follows:
   (define (partition compare l1)
      (cond
         ((null? l1) '())
         ((compare (car l1)) (cons (car l1) (partition compare (cdr l1))))
         (else (partition compare (cdr l1)))))

   (define (quicksort l1)
      (cond
         ((null? l1) '())
         (else (let ((pivot (car l1)))
            (append (append (quicksort (partition (lambda (x) (< x pivot)) l1))
                       (partition (lambda (x) (= x pivot)) l1))
                    (quicksort (partition (lambda (x) (> x pivot)) l1)))))))
The partition function in this example illustrates the usefulness of passing functions as arguments ; by doing so, we may use the same partition function for both the lesser and greater sublists. The function does this by taking a predicate function compare, which should return true or false, and a list, l1. If l1 is the empty list, it returns the empty list. Otherwise, if the first element in l1 returns true when compare is applied to it, we return that first element cons'ed onto the partition of the tail of l1. If compare returns false, we fall through to the last condition, in which we merely return the partition of the tail of l1, without the first element of l1.

Then, in the actual quicksort function, we perform the following actions: If l1 is the empty list, we return the empty list. Otherwise, we bind a local variable pivot to the first element in l1. We then find the list of elements less than pivot by passing the function (lambda (x) (< x pivot))  to partition. This lambda function returns true if its argument, x, is less than pivot. Thus, passing this function to partition results in the list of elements in l1 that are less than pivot. We similarly use partition to form the list of elements equal to pivot and the list of elements greater than pivot. We the recursively apply the quicksort function to the list of lesser elements and the list of greater elements, and then append the three results together.


next up previous contents index
Next: Development and Debugging Up: Examples Previous: Example One: Flatten

Steven J. Zeil
Tue Mar 4 14:36:27 EST 1997