Transcript Recursion

Recursion
1
Definitions I
• A recursive definition is a definition in which the
thing being defined occurs as part of its own
definition
• Example: A list consists of:
– An open parenthesis, "("
– Zero or more atoms or lists, and
– A close parenthesis, ")"
2
Definitions II
• Indirect recursion is when a thing is defined in
terms of other things, but those other things are
defined in terms of the first thing
• Example: A list is:
– An open parenthesis,
– Zero or more S-expressions, and
– A close parenthesis
• An S-expression is an atom or a list
3
Understanding recursion
• The usual way to teach recursion is to “trace
through” a recursion, seeing what it does at each
level
• This may be a good way to understand how
recursion works...
• ...but it's a terrible way to try to use recursion
• There is a better way
4
Base cases and recursive cases
• Every valid recursive definition consists of two
parts:
– One or more base cases, where you compute the
answer directly, without recursion
– One or more recursive cases, where you do part of the
work, and recur with a simpler problem
5
Information hiding
• function spread (int A[], int size) {
int max, min;
sort(A, size);
min = A[0];
max = A[size - 1];
return max - min;
}
• Can you understand this function without looking
at sort?
6
Stepping through called functions
• Functions should do something simple and
understandable
• When you try to understand a function, you should
not have to step through the code of the functions
that it calls
• When you try to understand a recursive function,
you should not have to step through the code of
the functions it calls
7
We have small heads
• It's hard enough to understand one level of one
function at a time
• It's almost impossible to keep track of many levels
of the same function all at once
• But you can understand one level of one function
at a time...
• ...and that's all you need to understand in order to
use recursion well
8
The four rules
•
•
•
•
Do the base cases first
Recur only with a simpler case
Don't use global or reference variables
Don't look down
9
Do the base cases first
• Every recursive function must have some things it
can do without recursion
• These are the simple, or base, cases
• Test for these cases, and do them first
• This is just writing ordinary, nonrecursive code
10
Recur only with a simpler case
• If the problem isn't simple enough to be a base
case, break it into two parts:
– A simpler problem of the same kind (for example, a
smaller number, or a shorter list)
– Extra work not solved by the simpler problem
• Combine the results of the recursion and the extra
work into a complete solution
• “Simpler” means “more like a base case”
11
Example 1: member
• Is value X a member of list L ?
boolean member(X, L) {
if (L is the empty list)
return false; // this is a base case
if (X equals the first element in L)
return true; // another base case
return member(X, L - first element);
// simpler because more like empty list
}
12
MEMBER in Lisp
(DEFUN MEMBER (X L)
(COND
; base case: L is empty
((NULL L) NIL)
; base case: X = (CAR L)
((EQ X (CAR L)) T)
; recur with a case that is simpler
; because it’s more like 1st base case
(T (MEMBER X (CDR L))) ) )
13
Example 2: double
• Double every element of a list of numbers
function double(L) {
if (L is the empty list)
return the empty list;
// base case
else {
L2 = double (L - first element);
// recur
D = 2 * first element in L;
// extra work
return (list made by adding D to L2); // combine
}
}
14
DOUBLE in Lisp
(DEFUN DOUBLE (L)
(COND
; if L is the empty list, return the empty list
((NULL L) ())
; otherwise, double the first number and
; cons it to the double of the rest of the list
(T (CONS (* 2 (CAR L)) (DOUBLE (CDR L))) ) )
15
It's OK to use locals variables and
parameters passed by value
• A function has its own copy of
– local variables
– parameters passed by value
• Each level of a recursive function has its own copy
of these variables and parameters
• Changing them at one level does not change them
at other levels
• One level can't interfere with another level
16
It's bad to use global variables or
parameters passed by reference
• There is only one copy of a global variable
• If a parameter is passed by reference, there is only
one copy of it
• If such a variable is changed by a recursive function,
it's changed at all levels
• The various levels interfere with one another
• This can get very confusing
• Don't let this happen to you!
17
Don't look down
• When you write or debug a recursive function,
think about this level only
• Wherever there is a recursive call, assume that it
works correctly
• If you can get this level correct, you will
automatically get all levels correct
• You really can't understand more than one level at
a time, so don't even try
18
MEMBER again
• (DEFUN MEMBER (X L)
(COND
((NULL L) NIL)
– This says: if list L is empty, then X isn’t an element of L
– Is this a true statement?
•
((EQ X (CAR L)) T)
– This says: if X = the first element in L, then it’s in L
– Is this a true statement?
•
–
–
–
–
–
–
(T (MEMBER X (CDR L))) ) )
This says: if X isn’t the first element of L, then X is in L if and
only if X is in the tail of L
Is this a true statement?
Did we cover all possible cases?
Did we recur only with simpler cases?
Did we change any global variables?
We’re done!
19
Reprise
•
•
•
•
Do the base cases first
Recur only with a simpler case
Don't use global or reference variables
Don't look down
20
The End
21