Midterm 1
- Midterm 1 will be held in 105 North Gate from 5-6 on Monday the
28th. Yes, it's in the same time and place as your regular lecture.
- The test is open book and open notes The test will cover
everything up to that point, including some recursion
- There won't be a
lecture the week before the midterm (the 21st)
- Nate will have office
hours from 10:30-noon on the day of the midterm
- There will be a review
session at some point on either Saturday the 26th or Sunday the 27th, and
it will take place some time between 10 and 2.
- You have a practice
exam in your reader, and we will be posting more stuff on the course
portal
- It is probably best if you sit down and try to work the entire
practice test in an hour, just so you'll get a feeling for what CS 3
midterms are like
Recursion
- Recursion is one of the
key topics in this class
- Yes, it's hard, but mostly in the "developing
a whole new way to think" sort of way
- The book and lab offer a bunch
of different ways to think about recursion -- the important thing is to
find one that works for you
- The first recursion lab jumps right into
recursion and assumes you have read the book. Make sure you read
Chapter 11 before you start lab!
- So what is recursion?
- It's when a procedure calls itself to solve a problem!
- What?
- Here's an example: Let's say you have a sentence like (I like
cs3) and you want to count all of the words. One way to do it would
be to count the first word (that's 1) and then count all of the rest of
the sentence. It would look something like this:
- Count I.
That's on word. Then count (like cs3).
- Count like.
That's
two words. Then count (cs3)
- Count cs3. That's three
words. Then count ().
- The empty sentence has no words, so
we're done. The total is three.
- There are four key parts to recursive problems. Not every part will be
obvious in every problem, but you should still make a note of them. They
are:
- The base case. This tells you when you stop. A good way to
find a base case is to ask yourself, "What's the simplest possible case of
this problem?"
- Do a little bit of work. The secret to recursion is only doing what
you absolutely have to right now, and passing the rest of the work off on
someone else.
- Now do all the rest of the work (recursion). This is where your
procedure calls itself again on what is left of the problem.
- Combine your little bit of work and all the rest of the work. This
might not be a part of every recursive problem.
Recursion Problems
First, let's try writing count. We already know the plan,
which is to count the first word and then count the rest. We start with
the easy part:
(define (count sent)
What next? Well, I always start recursion by figuring out how I stop. This
is the base case. What's the simplest possible sentence to count? That
would be the empty sentence.
(define (count sent)
(if (empty? sent)
0
Now let's do a little bit of work. What would that be? How about counting
the first word? That gives us 1. Then we do the rest of the work,
which is (count (bf sent)). In other words, we count everything
after the first word of the sentence. Finally, we combine the 1
for the first word and the (count (bf sent)) for all the other
words. How? We add them together:
(define (count sent)
(if (empty? sent)
0
(+ 1 (count (bf sent)))))
Do you believe this works? Why should you? Let's test it out.
- We start with (count '(I love cs3)). The sentence isn't
empty, so we do (+ 1 (count (bf sent))).
- Now we have (+ 1 (count '(love cs3))). We can't do the
+ until we figure out the underlined part, though.
- Now we do the underlined part. Since the sentence isn't empty, we do
the (+ 1 (count (bf sent))) line again. That leads us to (+ 1
(+ 1 (count '(cs3)))).
- We do the underlined part again. Since the sentence isn't empty, we do
the (+ 1 (count (bf sent))) line again. That leads us to (+ 1
(+ 1 (+ 1 (count '())))).
- Since the sentence is empty, (count '()) gives us 0. Now we
have (+ 1 (+ 1 (+ 1 0))), which gives us 3.
Now let's try writing a procedure that takes a sentence of numbers and
returns the first even number. Let's call it find-even. How do we
start? With the base case, of course. What is the base case? Well, what's
the simplest possible sentence? Hmm... I'm not quite sure what that means.
Another way to think about the base case is, "Can I look at my sentence
and give you the answer with almost no work?" Well, if the first word in
the sentence is even, I can tell you the answer right away.
(define (find-even sent)
(if (even? (first sent))
(first sent)
Okay, so if we don't find the first even number right away, we have to
look through the rest of the sentence. The rest of the sentence is (bf
sent) and we look through it with find-even, so we get
(define (find-even sent)
(if (even? (first sent))
(first sent)
(find-even (bf sent))))
How well does this work?
- We start with (find-even '(1 3 5 6 7 8)). The first
number isn't even, so we throw it away and keep looking.
- Now we have (find-even '(3 5 6 7 8)). The first number isn't
even, so we throw it away and keep looking.
- Now we have (find-even '(5 6 7 8)). The first number isn't
even, so we throw it away and keep looking.
- Now we have (find-even '(6 7 8)). The first number is even,
so we stop and return it.
Now let's try to identify all four parts of this recursive problem. The
base case is easy. We already did that. What about "Do a little bit of
work?" Personally, I'd say that checking to see if the first word is even
is doing a little bit of work. In this case, it also happens to be the
base case. That's fine. What about "Do all the rest of the work?" That's
(find-even (bf sent)). Finally, what about "Combine the little
bit of work with all the rest of the work?" Hmm... I don't see that one.
Why? Well, we aren't building something. We're looking for
something. That means we don't really have anything to combine (build).
Now let's try returning all of the even numbers in a sentence.
This is very different from finding the first number. Instead of looking
for one number, we are building a sentence. Let's call this procedure
all-evens. Once again, we start with the base case. Can we think
of the simplest sentence that we could possibly give all-evens?
What about the empty sentence? There aren't any numbers in it.
(define (all-evens sent)
(cond (empty? sent) 0)
Now we need to see if we've found an even number. We could do that with
(even? (first sent)).
(define (all-evens sent)
(cond ((empty? sent) 0)
((even? (first sent))
What do we do if we actually find an even number? We need to put it into a
sentence.
(define (all-evens sent)
(cond ((empty? sent) 0)
((even? (first sent))
(se (first sent)
What else should we put in the sentence? All of the other even numbers, of
course! How do we find them? That's what all-evens is for.
(define (all-evens sent)
(cond ((empty? sent) 0)
((even? (first sent))
(se (first sent) (all-evens (bf sent))))
So if the sentence isn't empty and the first word isn't even, the first
word must be odd. What do we do in this case? Well, we don't put the first
word in the sentence. We just go on and look for some even words.
(define (all-evens sent)
(cond ((empty? sent) 0)
((even? (first sent))
(se (first sent) (all-evens (bf sent))))
(else (all-evens (bf sent)))))