Below are my reminders for lecture. A more fleshed out version of most of these topics can be found from previous semesters: (pdf) Look at the code for each of Is there a pattern? A template, to help guide you? Well, barely: For each of the programs we wrote, what is the base case? subprobs? combination? Termination arg?: Here's threes;
  (define (threes n)
     (cond [(= n 1)  true]
           [else (threes (if (even? n) 
                             (/ n 2) 
                             (+ (* 3 n) 1)))]))

; example hand-evaluation:
  (threes  3)
= (threes 10)
= (threes  5)
= (threes 16)
= (threes  8)
= (threes  4)
= (threes  2)
= (threes  1)
= true
Does this fit the pattern for template (structure recrsion)? For generative recursion?
What about an argument of termination? For threes, termination is difficult to show -- in fact, it's a longstanding open question in mathematics! It happens to terminate for each number anybody's tried (and waited for an answer for ...), but that's not a proof.

To do: Modify threes to return the number of iterations until 1 is reached. (Hint: while it's generative recursion, and matches the gen. recur. template, the rules for base case and combining subproblems can still be simple (and still in the flavor of the structural-recursion templates).

New problem:

quicksort   
Invented by Tony Hoare, 1966, a classics major from Cambridge.
 - first, just filter > and <=
    [note to prof:
        if base case is length <= 1,
        then this buggy version will still work on *some* inputs!
        (A termination condition of empty will work later,
         but would always expose the bug immediately at this point.)
      Should probably start with length<=1, show a falsely reassuring
      test case, then show bug.
      In very final version, show that base-case empty would also works.]
 - then filter < and >, and include pivot manually
 -   (Mention trying: filter <=, 
     and place pivot to assure both partitions smaller)
 - finally, filter =s.


Termination argument: (similar to mergesort's):
   (a) We don't recur on empty lists [by the code]
   (b) When we recur, the only other work we do is
       append and some filters; these terminate [by structural recursion].
   (c) When recurring, we always recur on a shorter list:
       in particular, we never recur on a list containing
       the "pivot" value (first nums).
       Thus the recursive call will terminate, and so will this call.
  

  Notes: - we saw in lab, some inputs for which quicksort does poorly;
           (there is a fix, though sometimes it will still do poorly)
       - in-depth studies actually use quicksort until list is ~ length 10,
         and then switch over to insert-sort.
       - remember that correctness is more important than efficiency;
         we only dwell on efficiency when it's a frequently-called subroutine.
         (even experts can predict which subroutines are frequently-called).
       - append still takes some time;
         there is a different way of storing numbers (arrays)
         where quicksort is clever and gets the append for free.
         So, lists aren't quicksort's forte (though it still does reasonably)