Recursion - Programming Languages and Techniques II - Lecture Slides, Slides of Programming Languages

In all programming language only syntax is different not the logic. This course discuss core concepts for many different programming language and techniques. Key points for this lecture are: Recursion, Parenthesis, Indirect Recursion, Recursive Functions, Anatomy of a Recursion, Parts of the Dumb, Improving the Dumb, Four Rules, Base Cases and Recursive Cases, Infinite Recursion

Typology: Slides

2012/2013

Uploaded on 09/29/2013

dhanvant
dhanvant 🇮🇳

4.9

(9)

89 documents

1 / 24

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Recursion
docsity.com
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18

Partial preview of the text

Download Recursion - Programming Languages and Techniques II - Lecture Slides and more Slides Programming Languages in PDF only on Docsity!

Recursion

Definitions I

 A recursive definition is a definition in which the thing

being defined occurs as part of its own definition

 Example:

 An atom is a name or a number  A list consists of:  An open parenthesis, "("  Zero or more atoms or lists, and  A close parenthesis, ")"

Recursive functions...er, methods

 The mathematical definition of factorial is:

 We can define this in Java as:

 long factorial(long n) { if (n <= 1) return 1; else return n * factorial(n – 1); }

 This is a recursive function because it calls itself

 Recursive functions are completely legal in Java

1, if n <= 1 n * factorial(n-1) otherwise

factorial(n) is

Anatomy of a recursion

long factorial(long n) {

if (n <= 1) return 1;

else return n * factorial(n – 1);

Base case: does some work without making a recursive call

Recursive case: recurs with a simpler parameter

Extra work to convert the result of the recursive call into the result of this call

Parts of the dumb example

void fill(int[ ] a, int n) {

if (n < 0) return;

else {

a[n] = n;

fill(a, n - 1);

Base case: does some work without making a recursive call

Recursive case: recurs with a simpler parameter

Extra work to convert the result of the recursive call into the result of this call

Improving the dumb example

 The line fill(a, a.length - 1); just seems ugly

 Why should we have ask the array how big it is, then tell the method?  Why can’t the method itself ask the array?

 Solution: Put a “front end” on the method, like so:

void fill(int[ ] a) {

fill(a, a.length - 1);

 Now in our run method we can just say fill(a);

 We can, if we want, “hide” the two-parameter version

by making it private

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

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

 The important part here is testing before you recur; the actual work can be done in any order  long factorial(long n) { if (n > 1) return n * factorial(n – 1); else return 1; }  However, it’s usually better style to do the base cases first

 This is just writing ordinary, nonrecursive code

Infinite recursion

 The following is the recursive equivalent of an infinite loop:

 int toInfinityAndBeyond(int x) { return toInfinityAndBeyond(x); }

 This happened because we recurred with the same case!

 While this is obviously foolish, infinite recursions can happen

by accident in more complex methods  int collatz(int n) { if (n == 1) return 1; if (n % 2 == 0) return collatz(n / 2); else return collatz(3 * n - 1); }

Don’t modify and use non-local variables

 Consider the following code fragment:

 int n = 10; ... int factorial() { if (n <= 1) return 1; else { n = n – 1; return (n + 1) * factorial(); } }

 It is very difficult to determine (without trying it)

whether this method works

 The problem is keeping track of the value of n at all the

various levels of the recursion

Using non-local variables

 int total = 0; int[ ] b = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

int sum(int n) { if (n < 0) return total; else { total += b[n]; sum(n - 1); return total; } }  System.out.println("Total is " + sum(9));  The global array b is being used, but not changed  The global variable total is being changed, but not used (at least, not in any way that affects program execution)  This program works, and can be understood

Style

 The previous method works, but it’s terrible style!

 int sum(int n) { if (n < 0) return total; else { total += b[n]; sum(n - 1); return total; } }

 What’s b? What’s total? Where do these come from?  The method just isn’t very “self-contained”  It might be acceptable if b and total are instance variables describing the state of this object—but that seems unlikely  Some programmers prefer using getters and setters for all instance variables, even within the same class

It's bad to modify objects

 There is (typically) only one copy of a given object

 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

 Hence, it’s acting like a global variable (one accessible to all parts of the program)

 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