CS 163 Lecture-Module #07:
Writing Recursive Methods

introductory exercise

This exercise is basically just a joke, though it's the sort of joke that only a mathematician would find amusing. Nevertheless, it has a serious point.
Part (a)  you are in a room with a gas stove, one that is working, and already lit, and you're holding a pot of water. You need some boiling water. What do you do?
This part isn't meant to be tricky --- just give the obvious answer.
Answer:


Part (b) Now you are in the same room, with the same gas stove, still working, and already lit, together with the same pot of water, but  is holding the pot of water. You need some boiling water. What do you do?
This part is meant to be tricky -- you're supposed to give an "elegant" answer rather than say an answer requiring  to do everything themselves.
Answer:


Part (c) Now ...  is holding the pot of water.
What do you do?
Answer:




this illustrates the recursive philosophy of life:


Acknowledgement: that exercise derived from
:
The Hitchhiker's Guide to Calculus ~ (A Calculus Course Companion),
by Michael Spivak. Polished Pebble Press, Houston, TX, 1995.
Available from Mathematical Association of American Publications.

recursion

occurs if a method 
    (or if one method invokes another which invokes ...                                 which invokes the first method
    this situation called  recursion)
such a method called 

recursive invocation is sort of 
but different from  for/while/do-while
the term  is used to refer to repetition done explicitly with those constructs

e.g. method    int factorial(int n)      "n!"
how many ways  n  objects may be in different orders

(purpose here is not to teach you factorial --- many of you may already know it.
purpose here is to make some points about ;
factorial is simply good example --- convenient precisely because
you may already know it / if you don't, it's easily explained as below
so if you already know factorial, what follows next will be review)

e.g.
3 objects:   

orders        = 6

2 objects:

orders        = 2

1 object:    order        = 1

4 objects:    orders       

5 objects:    orders       

6 objects:    orders       

        .
        .
        .

formula from mathematics:
n! = 1·2·3·4·... 
                                ·(n-2)·(n-1)·n

So you know factorial.
But do you know recursion?

demonstrate recursive programming by considering implementation of this simple function
including discussing how recursion works

1·2·3·4·... could be calculated 
    could NOT do:
int factorial(int n) {
    return  1 * 2 * 3 * 4 * ... * n;    
    }

to calculate recursively, consider:
    2! ==  1  *2
          (  )
          

    3! ==  1*2 *3
          (   )
           

    4! ==  1*2*3 *4
          (     )
            

    5! ==  1*2*3*4 *5
          (       )
             
n! = (n-1)! * n

but do we really need (n-1)! every time to calculate n! ?
1! = 0! * 1
0! = (-1)! * 0 ?
(-1)! = (-2)! * (-1) ?
(-2)! = (-3)! * (-2) ?
... ?
STOP if n == 1 just know 1! = 
thus a basic piece of code here would be for calculating 1!
we can do this:

int f1 = factorial_r(1);
System.out.println("1! = " + f1);
but  factorial_r()  doesn't know how to calculate "2!".
so write another method  factorial_rr()  which will
with our guiding principle: recursive philosophy of life:
if possible, reduce problem to a simpler one (already solved)

    /**
     * can calculate "2!".
     * @author 
     */
    factorial_rr(int x)
        similar to  factorial_r() except:
        else {
            int factorial_sub_case = factorial_r(x - 1);
            return  factorial_sub_case * x;
            }

int f2 = factorial_rr(2);
System.out.println("2! = " + f2);
can continue like this

analyze
for e.g.  factorial_rrr(3):
(via debugging)
    |                                           |
    |                                           |
    +-------------------------------------------+
    | factorial_r(n:1)                          |
    |   return  1                               |
    +-------------------------------------------+
    | factorial_rr(x:2)                         |
    |   factorial_sub_case =  factorial_r(1)    |  
    |   return  factorial_sub_case * x          |  
    +-------------------------------------------+
    | factorial_rrr(y:3)                        |
    |   factorial_sub_case =  factorial_rr(2)   |  
    |   return  factorial_sub_case * y          |  
    +-------------------------------------------+
    | main(...)                                 |
    |    f3 = factorial_rrr(3)                  |  
    +-------------------------------------------+
incidentally rem. system avoids getting confused about multiple uses of variable named "factorial_sub_case" by keeping each  factorial_r...()'s `instance' of  factorial_sub_case  in the  for the invocation of  factorial_r...()

noting that each  factorial_rrr...()  sub-called is ultimately the same,
in  factorial_rrr()  simply sub-call 


what happens (in the method-call-stack)?

each method-call still gets its own  with its own variable-storage
even though same name
    |                                           |
    |                                           |
    +-------------------------------------------+
    | factorial_rrr(n:1)                        |
    |   return  1                               |
    +-------------------------------------------+
    | factorial_rrr(n:2)                        |
    |   factorial_sub_case =  factorial_rrr(1)  |  
    |   return  factorial_sub_case * n          |  
    +-------------------------------------------+
    | factorial_rrr(n:3)                        |
    |   factorial_sub_case =  factorial_rrr(2)  |  
    |   return  factorial_sub_case * n          |  
    +-------------------------------------------+
    | main(...)                                 |
    |    f3 = factorial_rrr(3)                  |  
    +-------------------------------------------+
you can think of a frame for a repeated invocation of a method
corresponding to a  system makes
analogously could solve the introductory exercise using just clones of

this demonstrates basic recursion
summarize:
* write code for 
* write code for `hard' case reducing to simpler case
could write successive methods,
but actually unify everything:
to actually write a recursive method
you should be given spec.:
* base-case
        base-result
* general case
        recursive formula
(sometimes only described in text, in which case you must determine formulas)
e.g.:
* 1! = 1
* n! = (n-1)! * n
translates to:

then can simply write:
qualifiers ret._type recursive_method(parameters) {
    if( base_case )
        return  base_value;
    // else
        return  recursive formula;
    }
e.g.:

actually you can have several base-cases, base-results, general cases, recursive formulas
you should be told conditions for each; code straightforwardly

but discussion above so you have deeper understanding of the process
e.g. to facilitate 

another example:
seek the index of the occurrence of a value target  in an array

as usual when doing anything with array, need variable index
so can access array-element via "array[index]"
with  factorial(n)  above, initial value for n  was large one given
and called recursively on  if not stopping;
stopped if 
here, searching  array[]  for value target,
with initial value for index  given large one,
what are conditions for stopping instead of doing recursion with  index - 1?
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |   | ? | X | X |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
                                              ^   ^   ^
                                              |   |   |
                                              /   /   /
                                       ---------------
                                      /
                            index: 
if (  ) 
if (  ) 
specification reflects those observations:
search(array, i, target) =
    i  if  array[i] is target
     if  i < 0 (out of range)
    search(array, i-1, target)  otherwise

then in  main():
    String[] data = { "To", "iterate", "is", "human",
                        "to", "recurse,", "divine" };
                        // : L. Peter Deutsch, who worked on PostScript, 
                        // which preceded PDF.
    int i_human = search(data, data.length - 1, "human");
    System.out.println("i_human: " + i_human);          // 
    int i_robot = search(data, data1.length - 1, "robot");
    System.out.println("i_robot: " + i_robot);          // 



summary of this lecture-module

basics of writing recursive methods:


(Copyright © 2008 by Hugh McGuire   — for thoughts about this, see   http://www.cis.gvsu.edu/~mcguire/teaching/copyright_thoughts.html .)