0% found this document useful (0 votes)
53 views7 pages

Lecture P6: Recursion

The document provides an overview of recursion, explaining that recursion is when a function calls itself directly or indirectly. It gives examples of problems that are naturally recursive, like directories that contain subdirectories. It then discusses how recursion works, using stacks to save the local environment of each function call. The document provides examples of simple recursive programs to compute sums and factorials. It also discusses potential pitfalls of recursion, like inefficient recomputation of values. Overall, the document provides a good introduction to recursion, explaining what it is, how it works, simple examples, and some considerations around recursion versus iteration.

Uploaded by

naokar
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
53 views7 pages

Lecture P6: Recursion

The document provides an overview of recursion, explaining that recursion is when a function calls itself directly or indirectly. It gives examples of problems that are naturally recursive, like directories that contain subdirectories. It then discusses how recursion works, using stacks to save the local environment of each function call. The document provides examples of simple recursive programs to compute sums and factorials. It also discusses potential pitfalls of recursion, like inefficient recomputation of values. Overall, the document provides a good introduction to recursion, explaining what it is, how it works, simple examples, and some considerations around recursion versus iteration.

Uploaded by

naokar
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Overview

Lecture P6: Recursion

What is recursion?
s

When one function calls ITSELF directly or indirectly.

Why learn recursion?


s

New mode of thinking. Powerful programming tool. Many computations are naturally self-referential. a Unix directory contains files and other directories Euclids gcd algorithm linked lists and trees GNU = GNUs Not Emacs

Start
s

Goal

Overview
How does recursion work? ! Just like any other function call. How does a function call work?
s

Implementing Functions
How does the compiler implement functions? ! With a STACK. Return from functions in last-in first-out (LIFO) order.
s

A function lives in a local environment: values of local variables which statement the computer is currently executing When f() calls g(), the system saves local environment of f sets value of parameters in g jumps to first instruction of g, and executes that function returns from g, passing return value to f restores local environment of f resumes execution in f just after the function call to g

FUNCTION CALL: push local environment onto stack. RETURN: pop from stack and restore local environment.

A Simple Example
Goal: function to compute sum(n) = 0 + 1 + 2 + . . . + n-1 + n. Simple ITERATIVE solution. iterative sum 1 int sum(int n) { int i, s = 0; for (i = 0; i <= n; i++) s += i; return s; } iterative sum 2 int sum(int n) { int s = n; while (n > 0) { n--; s += n; } return s; }

A Simple Example
Goal: function to compute sum(n) = 0 + 1 + 2 + . . . + n-1 + n. Simple ITERATIVE solution. sum(n-1)

Can also express using SELF-REFERENCE.

if n = 0 0 sum(n ) = n + sum( n 1) otherwise

base case reduction step converges to base case

recursive sum int sum(int n) { if (n == 0) return 0; return n + sum(n-1); } base case reduction step

Note that changing the variable n in sum does not change the value in the calling function.
5

A Simple Example
Goal: function to compute sum(n) = 0 + 1 + 2 + . . . + n-1 + n. Simple ITERATIVE solution. Can also express using SELF-REFERENCE.
s

A Bad Recursive Function


BASE CASE is special input for which the answer is trivial. Wont "bottom-out" of recursion without a base case. Analog of infinite loops with for and while loops.

This is just a stupid example to illustrate recursion.


s

Dont even need iteration, let alone recursion. 0 + 1 + 2 + . . . + n = n(n+1) / 2 better sum int sum(int n) { return (n * (n+1)) / 2; } Is n even?

mystery1(n) void mystery1(int n) { printf("%d\n", n); if (n % 2 == 0) mystery1(n/2); else mystery1(3*n + 1); } no base case

A Bad Recursive Function


BASE CASE is special input for which the answer is trivial. REDUCTION STEP makes input converge to base case.
s

Greatest Common Divisor


Find largest integer d that evenly divides into m and n.

Unknown whether program terminates for all positive integers n. Stay tuned for Halting Problem in Lecture T4.

if n = 0 m gcd(m , n ) = gcd(n, m % n ) otherwise

base case reduction step converges to base case

mystery2(n) void mystery2(int n) { printf("%d\n", n); if (n <= 1) return; else if (n % 2 == 0) mystery2(n/2); else mystery2(3*n + 1); }

gcd(1440, 408) base case reduction step

= gcd(408, 216) = gcd(216, 192) = gcd(192, 24) = gcd(24, 0) = 24.

anti-reduction step Euclid (300 BC)


9

1440 = 25 32 51 408 = 23 31 171

10

Greatest Common Divisor


Find largest integer d that evenly divides into m and n.
s

Number Conversion
To print binary representation of integer N: Stop if N = 0. Write 1 if N is odd; 0 if n is even. Move pencil one position to left. Print binary representation of N / 2. (integer division) base case reduction step converges to base case 43 21 10 5 2 1 0 1 11 011 1011 01011 101011

if n = 0 m gcd(m , n ) = gcd(n, m % n ) otherwise

gcd(m, n) int gcd(int m, int n) { if (n == 0) return m; else return gcd(n, m % n); }

Check: 43 = 1 25 + 0 14 + 1 23 + 0 22 + 1 21 + 1 20 = 32 + 0 + 8 + 0 + 2 + 1 base case reduction step Easiest way to compute by hand.


s

Corresponds directly with a recursive program.

11

12

Recursive Number Conversion


Computer naturally prints from left to right.
s

Recursive Number Conversion


Computer naturally prints from left to right.
s

So we need to first convert N / 2. Then write 0 or 1.

convert( ) void convert(int N) { if (N == 0) return; convert(N / 2); printf("%d", N % 2); } Unix 1 if N is odd; 0 if N is even

So we need to first convert N / 2. Then write 0 or 1.

convert( ) void convert(int N) { if (N == 0) return; convert(N / 2); printf("%d", N % 2); } 1 if N is odd; 0 if N is even

function calls Proof of correctness: convert(43)/ 2) + (N % 2) N = 2 * (N convert(21) convert(10) convert(5) convert(2) convert(1) convert(0) printf("1") printf("0") printf("1") printf("0") printf("1") printf("1")

Proof of correctness: N = 2 * (N / 2) + (N % 2)

% gcc convert.c % a.out 43 101011 Indentation level pairs statements belonging to same "invocation"
13

Convert to any base b 10. ! Change 2 to b everywhere in code.


s

Exercise: extend to handle hexadecimal (base 16).

14

Possible Pitfalls With Recursion


Is recursion fast? ! Yes. We produced remarkably efficient program for gcd. ! No. Can easily write remarkably inefficient programs.

Possible Pitfalls With Recursion


F(39) is computed once. F(38) is computed 2 times. F(37) is computed 3 times.
F(38) F(39) F(37) F(37) F(40) F(38) F(36)

Fibonacci numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . It takes a really long time to compute F(40).

if n = 0 0 Fn = 1 if n = 1 F + Fn 2 otherwise n 1

F(36) is computed 5 times. F(35) is computed 8 times. ...

F(37) F(36) F(36) F(35) F(36) F(35) F(35) F(34)

F(0) is computed 165,580,141 times. bad Fibonacci function int F(int n) { if (n == 0 || n == 1) return n; else return F(n-1) + F(n-2); }
15

331,160,281 function calls for F(40).

bad Fibonacci function int F(int n) { if (n == 0 || n == 1) return n; else return F(n-1) + F(n-2); }
16

Possible Pitfalls With Recursion


Recursion can take a long time if it needs to repeatedly recompute intermediate results.
s s

Recursion vs. Iteration


Fact 1. Any recursive function can be written with iteration. Compiler implements recursion with stack. Can avoid recursion by explicitly maintaining a stack.

DYNAMIC PROGRAMMING solution: save away intermediate results in a table. Fibonacci using dynamic programming int knownF[1000] = {0}; int F(int n) { if (knownF[n] != 0) return knownF[n]; else if (n == 0 || n == 1) return n; knownF[n] = F(n-1) + F(n-2); return knownF[n]; } Stores ith Fibonacci number in ith element.

Fact 2. Any iterative function can be written with recursion. Should I use iteration or recursion?
s

Ease and clarity of implementation. Time/space efficiency.

Uses only 2n recursive calls to compute F(n).

17

18

Towers of Hanoi
Move all the discs from the leftmost peg to the rightmost one.
s

Towers of Hanoi: Recursive Solution


A B C

Only one disc may be moved at a time. A disc can be placed either on empty peg or on top of a larger disc.

Move N-1 smallest discs to pole B.

Move largest disc to pole C.

Start Towers of Hanoi demo

Goal

Move N-1 smallest discs to pole C. Edouard Lucas (1883)


19 20

Towers of Hanoi: Recursive Solution


hanoi.c #include <stdio.h> Unix void hanoi(int n, char from, char to) { char temp; % gcc hanoi.c if (n == 0) % a.out return; temp = getOtherPeg(from, to); Move disc 1 from A to B. Move disc 2 from A to C. hanoi(n-1, from, temp); to printf("Move disc %d from %c toMove discn, from,Bto);C. %c.\n", 1 from Move disc 3 from A to B. hanoi(n-1, temp, to); Move disc 1 from C to A. } Move disc 2 from C to B. Move disc 1 from A to B. int main(void) { Solve 4 disc Move disc 4 from A to C. hanoi(4, A, C); problem disc 1 from B to C. Move return 0; Move disc 2 from B to A. } Move disc 1 from C to A. Move disc 3 from B to C. Move disc 1 from A to B. Move disc 2 from A to C. Move disc 1 from B to C.
21

Towers of Hanoi: Recursive Solution

hanoi.c char getOtherPeg(char x, char y) { if (x == A && y == B) || (x == B && y == A) return C; if (x == A && y == C) || (x == C && y == A) return B; return A; }

22

Towers of Hanoi
Is world going to end (according to legend)?
s

Summary
How does recursion work?
s

Monks have to solve problem with N = 40 discs. Computer algorithm should help. ! Not really! Takes 2N - 1 steps. (assuming rate of 1 disc per second, will take 348 centuries)

Just like any other function call.

How does a function call work?


s

Save away local environment using a stack.

Better understanding of recursive algorithm supplies non-recursive solution!


s

Trace the executing of a recursive program.


s

Use pictures.

Alternate between two moves: ! Move smallest disc 1 peg to right (left) if N is even (odd). ! Make only legal move not involving smallest disc. See Sedgewick 5.2.

Write simple recursive programs.


s

Base case. Reduction step.

23

24

Root Finding

Lecture P6.5: Extra Slides

Given a function, find a root, i.e., a value x such that f(x) = 0.


s

f(x) = x2 - x - 1

1+ 5 = 1.61803... is a root. 2

Assume f is continuous and l, r satisfy f(l) < 0.0 and f(r) > 0.0.
2 1.5 1 0.5 0 -0.5 -1 -1.5
26

0.2

0.4

0.6

0.8

1.2

1.4

1.6

1.8

2.2

Root Finding
Reduction step:
s

Root Finding
Given a function, find a root, i.e., a value x such that f(x) = 0.

Maintain interval [l, r] such that f(l) < 0, f(r) > 0. Compute midpoint m = (l + r) / 2. If f(m) < 0 then run algorithm recursively on interval is [m, r]. If f(m) > 0 then run algorithm recursively on interval is [l, m]. recursive bisection function #define EPSILON 0.000001 double f (double x) { return x*x - x - 1; } double bisect (double left, double right) { double mid = (left + right) / 2; if (right - left < EPSILON || 0.0 == f(mid)) return mid; if (f(mid) < 0.0) return bisect(mid, right); return bisect(left, mid); }

Progress achieved at each step.


s

Size of interval is cut in half.

Base case (when to stop): Ideally when (0.0 == f(m)), but this may never happen!
s

root may be irrational machine precision issues Stop when (r - l) is sufficiently small. guarantees m is sufficiently close to root

27

28

You might also like