Recursion. Definitions I A recursive definition is a definition in which the thing being defined...

21
Recursion
  • date post

    22-Dec-2015
  • Category

    Documents

  • view

    218
  • download

    0

Transcript of Recursion. Definitions I A recursive definition is a definition in which the thing being defined...

Recursion

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, ")"

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

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

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

Information hiding

• function spread (int A[], int size) { int max, min; sort_up(A, size); min = A[0]; max = A[size - 1]; return max - min;}

• Can you understand this function without looking at sort?

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

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

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

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

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”

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}

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))) ) )

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

}}

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))) ) )

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

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!

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

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!

Reprise

• Do the base cases first• Recur only with a simpler case• Don't use global or reference variables• Don't look down

The End