188
1 Introduction to Recursion Please fasten your seat belts.

1 Introduction to Recursion Please fasten your seat belts

Embed Size (px)

Citation preview

1

Introduction to Recursion

Please fasten your seat belts.

2

Recursion is difficult to master

Recursion yield elegant, concise code

Yet, it is difficult to debug.

Minor mistakes can be disastrous for the program

Infinite recursion is the most common problem

Infinite recursion is more complicated than infinite loop because it consume all the memory when stacking the current status of the function.

For the inexperienced programmer, the program may sometimes report a error which has no immediate relation to the recursive function

3

Recursion

When “something” is defined in terms of itself!

Recursive methods: A method that calls itself

Recursive classes: A class that contains an instance of itself

4

Recursion

Is the "art" of defining a concept using the concept itself They are the computer science equivalent of

mathematical induction In computer science terms we talk about recursive

functions: functions that invoke itself Not allowed in some languages When allowed they are very powerful

They express repetition without loops They simplify code which would otherwise be confusing

and unclear.

It is an important tool supporting data abstraction

5

Recursive Definitions

Any recursive definition has to have two parts: Basis of recursion: This is a non-recursive statement

establishing definition for a fixed number of objects. The bases is the condition that makes the recursion stop

Recursion: It is a condition that is written in such a way that after repeated executions of this code it will reduce to the basis.

// Definition of function (x raised to y)// Where y is positive

BASE : x raised to 0 is 1RECURSION: x raised to y is equal x times x raised to y-1

// Definition of function (x raised to y)// Where y is positive

BASE : x raised to 0 is 1RECURSION: x raised to y is equal x times x raised to y-1

6

Recurrence Relations

It is an relation describing the recursive function in terms of its values on smaller inputs

It will be widely used when we get to analysis of algorithms There are three methods to solve recurrences

Substitution method: based on mathematical induction Iteration method: converts the recurrence into a summation. Master method: Provides bounds for recurrences of the form:

T(n) = aT(n/b) + f(n) where a >= 1, b > 1 and f(n) is a given function Requires memorization of a few cases

Recurrence will be used quite frequently when describing sorting and tree algorithms Since a few of these algorithms are recursive

7

BNF (Backus-Naur Form)

Most Programming languages use the BNF notation to describe its syntax

It is less ambiguous than English It is a generator technique. It defined how to construct,

or generate, all possible syntactically valid strings of a language.

It is a recursive technique

<IntegerConstant> ::= <Digit> | <Digit><IntegerConstant><Digit> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0<IntegerConstant> ::= <Digit> | <Digit><IntegerConstant><Digit> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0

8

Understanding Recursion

To understand recursion we need to understand stacks Each time a function A calls a function B the status of A is

stored in the run-time stack. When the function B returns the status of A is popped from the

top of the stack.

Let's consider this programvoid whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { whatIsThis(); cout << inChar; }}

void whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { whatIsThis(); cout << inChar; }}

9

"Exploding" the recursion

Instead of imagining as stacks we could also see this as creation of new scopes at each iteration of the recursion

void whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { char inChar; { cin.get(inChar); if (inChar == '\n') cout << '\n'; else { cout << inChar; } } cout << inChar; }}

void whatIsThis() { char inChar; cin.get(inChar); if (inChar == '\n') cout << '\n'; else { char inChar; { cin.get(inChar); if (inChar == '\n') cout << '\n'; else { cout << inChar; } } cout << inChar; }}

10

Stacks

Is a “pile” or “collection” or “set” of items. Items can only be added to the top Items can only be taken off the top “Last-in-first-out” (”LIFO”)

Thing 1

Thing 2

Thing 3Push Pop

11

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

12

Thing 1

PUSH

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

What is a Stack?

13

Thing 1

Thing 2

PUSH

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

14

Thing 1

pop

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

15

Thing 1

Thing 2

PUSH

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

16

Thing 1

Thing 2

Thing 3

PUSH

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

17

Thing 1

Thing 2

pop

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

18

Thing 1

pop

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

19

pop

What is a Stack?

A data structure for storing items A data structure for storing items which are to be accessed in last-in which are to be accessed in last-in

first-out order (LIFO).first-out order (LIFO).

20

The Activation Stack

The white box represents the computers memory. The algorithm gets the first frame at the bottom of the

stack. Variables which are used within a module reside in

that module’s stack frame.

Algo var1 var2 var3

21

Algo var1 var2 var3

Proc_1 this_var that_var

Adding Modules to the Stack

When main calls a module, the module gets its own frame “pushed” on the stack.

The module’s variables live in that new frame. ONLYONLY the top frame is active. All frames underneath it

are stopped.

22

Proc_1 this_var that_var

Algo var1 var2 var3

Removing modules from the stack

When the module completes its instructions, it’s frame is “popped” off the stack and all of its data dies.

To survive, they must actually be stored in a frame that still exists (passed back).

23

How In Parameters Work

In formal parameters get a copy of the matching actual parameter.

In the algorithm:Proc_One (this_var)

In the module:procedure Proc_One(this_one in num)

24

Proc_One this_one 4

Algo 4

How In Parameters Work

In formal parameters get a copy of the matching actual parameter.

this_var that_var other_var7 9

4

25

How In/Out Parameters Work

In/out formal parameters act as a reference to the matching actual parameter.

Reading and writing are allowed.

In the algorithm:Proc_One (this_var)

In the module:procedure Proc_One(this_one in/out num)

26

Algo 7

Proc_One this_one

How In/Out Parameters Work

In/out formal parameters act as a reference to the matching actual parameter.

Reading and writing are allowed.

R this_one <- 7this_one <- 171

this_var that_var other_var 9471

Print(this_one)

1

27

How Out Parameters Work

Out formal parameters act as a reference to the matching actual parameter. Writing is only allowed at first. After writing, reading is also allowed.

In the algorithm:Proc_One (this_var)

In the module:procedure Proc_One(this_one out num)

28

How Out Parameters Work

Out formal parameters act as a reference to the matching actual parameter.

Writing is only allowed at first. After writing, reading is also allowed.

Proc_One this_one R this_one <- 88

Algo this_var that_var other_var4 7 98

29

Stack Trace Exampleprocedure juggle (x isoftype in num,

y isoftype out num, z isoftype in/out num)

y <- x + z print (x, y, z) x <- z + 4 z <- x + 2endprocedure

algorithm TraceExample a, b, c isoftype num a <- 1 b <- 2 c <- 3 print(a, b, c) juggle(c, a, b) print(a, b, c)endalgorithm

30

Procedure Juggle(x iot in Num,                 y iot out Num,                 z iot in/out Num)        y <- x + z        print(x,y,z)        x <- z + 4        z <- x - 2endprocedure

Output

Demo a b c1 2 3

1 2 3

Juggle x y z3 3 5 2

5 4 3

Algorithm Demo

a, b, c isoftype num

a <- 1        b <- 2        c <- 3        print(a,b,c)        juggle(c,a,b)        print(a,b,c)endalgorithm

RR6

5 4

31

Recursive Functions Like mathematical definitions, functions can be recursive

Direct recursion: Occurs when a function is called in its own body

Indirect recursion: Occurs when one function initiates a sequence of function invocations that eventually invokes the original

func A(int x) { . . . A(20); . . .}

func A(int x) { . . . A(20); . . .}

Direct Recursion

func A(int x) { . . . B(20); . . .}

func A(int x) { . . . B(20); . . .}

func B(int x) { . . . A(20); . . .}

func B(int x) { . . . A(20); . . .}

Indirect Recursion

32

A Recursive Procedure

Problem: Count from N to 10.

procedure CountToTen (/* in */ int n){ if (count <= 10) then{

print (count)// work CountToTen (count + 1)// recurse}//endif

}//endprocedure CountToTen Call the procedure CountToTen (7)

33

Tracing The Recursion

To keep track of recursive execution, do what a computer does: maintain information on an activation stack.

Each stack frame contains:• Module identifier and variables• Any unfinished business

ModuleID: Data values Unfinished business

34

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

35

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

7

36

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

7

37

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

38

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

78

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

39

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

78

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

40

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

78

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

41

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

42

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

43

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=10

44

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

10CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=10

45

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

10CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=10

46

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

10CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=10

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=11

47

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

10CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=10

48

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

10CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

49

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

10CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

50

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

789

10

51

789

10

Return to the algorithm.

52

Reversing the Work and Recursion

Problem: Count from 10 to N.

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

Now the work will happen as the frames pop off the stack!

53

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=7

54

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=7

55

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

56

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

57

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=9

58

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=9

59

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=10

60

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=10

61

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=10

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=11

62

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

10

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=10

63

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

10

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=9

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=10

64

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

109

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=9

65

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

109

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=9

66

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

1098

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

67

procedure CountToTen (count iot in Num) if (count <= 10) then print (count) // work CountToTen (count + 1) // recurse endifendprocedure //CountToTen

CountToTen: count=7

1098

CountToTen: count=8

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

68

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=7

10987

69

procedure CountToTen (count iot in Num) if (count <= 10) then CountToTen (count + 1) // recurse print (count) // work endifendprocedure //CountToTen

CountToTen: count=7

10987

70

10987

Return to the algorithm.

71

What is Recursion?

Recursion is when a function either directly or indirectly makes a call to itself.

Recursion is a powerful problem solving tool. Many mathematical functions and algorithms are

most easily expressed using recursion.

72

How does it work?

Functions are implemented using an internal stack of activation records.

The activation record for the currently active function is at the top of the stack.

Each time a function is called a new activation record is pushed on the stack.

When a function returns, the stack is popped and the activation record of the calling method is on top of the stack.

73

How does it work?

The function being called, and whose activation record is being pushed on the stack, can be different from the calling function (e.g., when main calls a function).

Or, the function being called can be a different instance of the calling subprogram.

Each instance of the function has its own parameters and local variables.

74

Solving Recursive Problems

See recursive solutions as two sections: Current Rest

N! = N * (N-1)!

7! = 7 * 6!

7! = 7 * (6 * 5 * 4 * 3 * 2 * 1 * 1)

75

Example Many mathematical functions are defined

recursively. For example, the factorial function:

N! = N * (N-1)! for N>0

0! = 1

We have defined factorial in terms of a smaller (or simpler) instance of itself.We must also define a base case or stopping condition.

76

Recursive Function Call

A recursive call is a function call in which the called function is the same as the one making the call.

In other words, recursion occurs when a function

calls itself!

We must avoid making an infinite sequence of function calls (infinite recursion).

77

Finding a Recursive Solution

Each successive recursive call should bring you closer to a situation in which the answer is known.

A case for which the answer is known (and can be expressed without recursion) is called a base case.

Each recursive algorithm must have at least one base case, as well as the general (recursive) case

78

General format formany recursive functions

if (some condition for which answer is known) // base case

solution statement

else // general case

recursive function call

SOME EXAMPLES . . .

79

Writing a recursive function to find n factorial

DISCUSSION

The function call Factorial(4) should have value 24, because that is 4 * 3 * 2 * 1 .

For a situation in which the answer is known, the value of 0! is 1.

So our base case could be along the lines of

if ( number == 0 ) return 1;

80

Writing a recursive function to find Factorial(n)

Now for the general case . . .

The value of Factorial(n) can be written as n * the product of the numbers from (n - 1) to 1, that is,

n * (n - 1) * . . . * 1

or, n * Factorial(n - 1)

And notice that the recursive call Factorial(n - 1) gets us “closer” to the base case of Factorial(0).

81

Recursive Function Example: Factorial

Problem: calculate n! (n factorial)

n! = 1 if n = 0 n! = 1 * 2 * 3 *...* n if n > 0

Recursively:

if n = 0, then n! = 1if n > 0, then n! = n * (n-1)!

82

Factorial Function

Int RecFactorial( /* in */ int n)// Calculates n factorial, n! // Precondition: n is a non-negative// integer{ if (n <= 0) then

return 1 else

return n * RecFactorial(n-1)}

83

1 Int RecFactorial(/*in*/int n)

3 {

4 if (n <= 0) then

5 return 1;

6 else

7 return n * RecFactorial(n-1);

8 }

main(...) { ...

20 cout<<(fact(3));

...

20

return return

address n value 3 3 * fact(2)

7

return return

address n value 2 2 * fact(1)

7

return return

address n value 1 1 * fact(0)

7

return return

address n value 0 1

84

20

return return

address n value 3 3 * fact(2)

7

return return

address n value 2 2 * fact(1)

7

return return

address n value 1 1 * fact(0)

7

return return

address n value 0 1

1 * 1

2 * 1

3 * 2

returns 6 to main()

1 Int RecFactorial(/*in*/int n)

3 {

4 if (n <= 0) then

5 return 1;

6 else

7 return n * RecFactorial(n-1);

8 }

main(...) { ...

20 cout<<(fact(3));

...

85

if (0 = 0) then Fact returns 1 else Fact returns 1 endifendfunction //Fact

if (0 = 0) then Fact returns 1 else Fact returns 1 endifendfunction //Fact

if (1 = 0) then Fact returns 1 else Fact returns 1 * Fact(0) endifendfunction //Fact

if (1 = 0) then Fact returns 1 else Fact returns 1 * Fact(0) endifendfunction //Factif (2 = 0)

then Fact returns 1 else Fact returns 2 * Fact(1) endifendfunction //Fact

if (2 = 0) then Fact returns 1 else Fact returns 2 * Fact(1) endifendfunction //Fact

if (3 = 0) then Fact returns 1 else Fact returns 3 * Fact(2) endifendfunction //Fact

if (3 = 0) then Fact returns 1 else Fact returns 3 * Fact(2) endifendfunction //Fact

algorithm Test ans <- Fact(3)endalgorithm

algorithm Test ans <- Fact(3)endalgorithm

86

Tracing Details

function RecFactorial (2) if (2 <= 0) then RecFactorial returns 1 else

return 2 * RecFactorial(1)

function RecFactorial (2) if (2 <= 0) then RecFactorial returns 1 else

return 2 * RecFactorial(1)

1. Actual parameters stored on the stack

2. Recursive call to

RecFactorial

4. Unfinished Business

3. Create a new Stack Frame

5. Return value and release stack frame

87

Activation Stack for Factorial

Call the function: answer <- Fact(5)

Main Algorithm: Unfinished: answer <- Fact (5)

88

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

89

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

90

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

91

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 4th: N=2, Unfinished: 2*Fact(1)

92

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 4th: N=2, Unfinished: 2*Fact(1)

Fact. 5th: N=1, Unfinished: 1*Fact(0)

93

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 4th: N=2, Unfinished: 2*Fact(1)

Fact. 5th: N=1, Unfinished: 1*Fact(0)

Fact. 6th: N=0, Finished: returns 1

94

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 4th: N=2, Unfinished: 2*Fact(1)

Fact. 5th: N=1, Finished: returns 1*1

95

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 4th: N=2, Finished: returns 2*1

96

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 3rd: N=3, Finished: returns 3*2

97

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Fact. 2nd: N=4, Finished: returns 4*6

98

Activation Stack for Factorial

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Finished: returns 5*24

99

Activation Stack for Factorial

Main Algorithm: Finished: answer <- 120

100

Exponentiation

baseexponent

e.g. 53

Could be written as a function

Power(base, exp)

101

Can we write it recursively?

be = b * b(e-1)

What’s the limiting case?

When e = 0 we have b0 which always equals?

1

LB

102

Another Recursive Function

function Power returnsa Num(base, exp isoftype inNum)// Computes the value of BaseExp // Pre: exp is a non-negative integer if (exp = 0) then Power returns 1 else Power returns base * Power(base, exp-1) endifendfunction //Power

Power xN = x * xN-1 for N>0 x0 = 1

103

Function Power returnsa Num (base, exp isoftype in Num)//Computes the value of BaseExp

//Preconditions: exp is a non-negative integer if(exp = 0 ) then Power returns 1 else Power returns (base * Power(base, exp – 1)) endifendfunction //Power

Activations Stack Example

Algo: total <- Power(3,4)

Power base = 3 exp = 4 3 *Power(3,3)

Power base = 3 exp = 3 3 *Power(3,2)

Power base = 3 exp = 2 3 *Power(3,1)

Power base = 3 exp = 1 3 *Power(3,0)

Power base = 3 exp = 0 Finished: 11

Total <- 81

1

3

9

27

11

33

99

2727

8181

104

In the year 1202 a distinguished Italian mathematician, Leonardo of Pisa, also known as Fibonacci, published the following puzzle:

The Man…The Man… (1170-1250)

105

The PuzzleThe Puzzle

A man has an infant male-female pair A man has an infant male-female pair of rabbits in a hutch entirely of rabbits in a hutch entirely surrounded by a wall. We wish to know surrounded by a wall. We wish to know how many rabbits can be bred from this how many rabbits can be bred from this pair in one year, if the nature of the pair in one year, if the nature of the rabbits is such that every month they rabbits is such that every month they breed one other male-female pair breed one other male-female pair which begins to breed in the second which begins to breed in the second month after their birth. Assume that no month after their birth. Assume that no rabbits die during the year. rabbits die during the year.

106

A Tree Diagram for Fibonacci’s PuzzleA Tree Diagram for Fibonacci’s Puzzle

107

ObservationsObservations

The number of rabbits at the beginning of any month equals the number of rabbits of the previous month plus the number of new pairs.

The number of new pairs at the beginning of a month equals the number of pairs two months ago.

One gets the sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …233

108

• snails• nautilus• other sea shells

11

2

3

5

8

13

The Occurrence in Nature…The Occurrence in Nature…

109

Fibonacci Numbers & Branching Fibonacci Numbers & Branching PlantsPlants

110

Fibonacci Fingers?Fibonacci Fingers?

2 hands each of which has ... 5 fingers, each of which has ... 3 parts separated by ... 2 knuckles

111

Fibonacci Numbers & Pine ConesFibonacci Numbers & Pine Cones

• 13 counterclockwise• 8 clockwise

112

Fibonacci Numbers & SunflowersFibonacci Numbers & Sunflowers

• 34 counterclockwise• 55 clockwise

113

Fibonacci sequence

Recursive definitionf(0) = 1

f(1) = 1

f(n) = f(n-1) + f(n-2)

114

Fibonacci Number Sequence

if n = 1, then Fib(n) = 1if n = 2, then Fib(n) = 1if n > 2, then Fib(n) = Fib(n-2) + Fib(n-1)

Numbers in the series:1, 1, 2, 3, 5, 8, 13, 21, 34, ...

A More Complex Recursive Function

115

Fibonacci Sequence Function

function Fib returnsaNum (n iot inNum)// Calculates the nth Fibonacci number // Precondition: N is a positive integer if ((n = 1) OR (n = 2)) then Fib returns 1 else Fib returns Fib(n-2) + Fib(n-1) endifendfunction //Fibonacci

116

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

117

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns Fib(3) + Fib(4)

118

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns Fib(1) + Fib(2)

119

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns Fib(1) + Fib(2)

Fib(1): Fib returns 1

120

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns 1 + Fib(2)

121

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns 1 + Fib(2)

Fib(2): Fib returns 1

122

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns 1 + 1

123

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

124

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns Fib(2) + Fib(3)

125

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns Fib(2) + Fib(3)

Fib(2): Fib returns 1

126

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + Fib(3)

127

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + Fib(3)

Fib(3): Fib returns Fib(1) + Fib(2)

128

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + Fib(3)

Fib(3): Fib returns Fib(1) + Fib(2)

Fib(1): Fib returns 1

129

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + Fib(3)

Fib(3): Fib returns 1 + Fib(2)

130

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + Fib(3)

Fib(3): Fib returns 1 + Fib(2)

Fib(2): Fib returns 1

131

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + Fib(3)

Fib(3): Fib returns 1 + 1

132

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + 2

133

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- Fib(5)

Fib(5): Fib returns 2 + 3

134

Tracing with Multiple Recursive Calls

Main Algorithm: answer <- 5

135

Fib(5)

Fib(3)Fib(4)

Fib(3) Fib(2)

Fib(2) Fib(1)

Fib(1) Fib(0)

Fib(1) Fib(0)

Fib(2) Fib(1)

Fib(1) Fib(0)

15 calls to Fib to find the 5th Fibonacci number!!!

136

Rules of Recursion

First two fundamental rules of recursion:

Base cases: Always have at least one case that can be solved without using recursion.

Make progress: Any recursive call must make progress towards the base case.

137

Rules of Recursion

Third fundamental rule of recursion:

“You gotta believe”: Always assume that the recursive call works.

138

Rules of Recursion

Fourth fundamental rule of recursion:

Compound interest rule: Never duplicate work by solving the same instance of a problem in separate recursive calls.

139

Towers of Hanoi Many, many years ago, in a distant part of the

Orient -- in the Vietnamese city of Hanoi -- the Emperor devised a puzzle, declaring that its solver could have the job of wise person.

The puzzle consisted of N disks and three poles: A (the source), B (the destination), and C (the spare)

140

Towers of Hanoi

B CA

141

Towers of Hanoi

B CA

142

Towers of Hanoi

B CA

143

Towers of Hanoi

B CA

144

Towers of Hanoi

B CA

145

Towers of Hanoi

B CA

146

Towers of Hanoi

B CA

147

Towers of Hanoi

B CA

148

Towers of Hanoi

A pseudocode description of the solution is:

Towers(Count, Source, Dest, Spare)

if (Count is 1)

Move the disk directly from Source to Dest

else

{

Solve Towers(Count-1, Source, Spare, Dest)

Solve Towers(1, Source, Dest, Spare)

Solve Towers(Count-1, Spare, Dest, Source)

}

149

Towers of Hanoi

void solveTowers( int count, char source, char dest, char spare){ if (count == 1) cout<<“Move disk from pole “ << source << " to pole " << destination <<endl; else { towers(count-1, source, spare, destination); towers(1, source, destination, spare); towers(count-1, spare, destination, source); }//end if}//end solveTowers

150

Pascal Triangle(Is this recursive?)

151

Pascal Triangle

152

Pascal Triangle

The combinations of n items taken r at a time. For example:three items:    a    b    c

taken 2 at a time:    ab    ac    bc Thus there are three combinations of 3 items taken 2

at a time. In General:    C(n,r) = n!/(r!(n-r))!    Obviously you

can calculate C(n,r) using factorials.

153

Pascal Triangle

Most of you know this leads to Pascals Triangle: n    0                            1

             1                       1       1             2                    1     2      1             3                1     3      3     1             4            1     4      6      4    1             5        1     5      10     10    5    1

This can also be written:            r     0    1    2    3     4    5        n  0    1            1    1     1            2    1     2    1            3    1     3    3    1            4    1     4    6    4    1            5    1     5   10  10    5    1

154

Pascal Triangle

C(n,r) occurs in many places in mathematics, statistics, chemistry, physics and business.

Note from Pascal's Triangle that:    C(n,r) = C(n-1, r-1) + C(n-1,r)

This leads to the recurrence for nonnegative r and n,

C(n,r) =           |    1             if r = 0 or r = n,                        |     0             if r > n,                        |     C(n-1, r-1) + C(n-1,r)     otherwise.

155

Pascal Triangle

This immediately leads to the recursive function for combinations:

    int C(int n, int r)    {        if((r == 0) || (r == n))            return 1;        else if(r > n)            return 0;        else            return C(n-1, r-1) + C(n-1, r);    }

156

Recall that . . .

Recursion occurs when a function calls itself (directly or indirectly).

Recursion can be used in place of iteration (looping).

Some functions can be written more easily using recursion.

157

What is the value of rose(25)?

int rose (int n)

{

if ( n == 1 ) // base case

return 0;

else // general case

return ( 1 + rose ( n / 2 ) );

}

158

Finding the value of rose(25)

rose(25) the original call

= 1 + rose(12) first recursive call

= 1 + ( 1 + rose(6) ) second recursive call

= 1 + ( 1 + ( 1 + rose(3) ) ) third recursive call

= 1 + ( 1 + ( 1 + (1 + rose(1) ) ) ) fourth recursive call

= 1 + 1 + 1 + 1 + 0

= 4

159

Writing recursive functions

There must be at least one base case, and at least one general (recursive) case. The general case should bring you “closer” to the base case.

The parameter(s) in the recursive call cannot all be the same as the formal parameters in the heading. Otherwise, infinite recursion would occur.

In function rose( ), the base case occurred when (n == 1) was true. The general case brought us a step closer to the base case, because in the general case the call was to rose(n/2), and the argument n/2 was closer to 1 (than n was).

160

Recursion for Repetition

while (<condition>) <body>while (<condition>) <body>

void recWhile() { if (<condition>) <body> recWhile();}

void recWhile() { if (<condition>) <body> recWhile();}

void anotherRecWhile() { if (<condition>) AnotherRecWhile(); <body>;}

void anotherRecWhile() { if (<condition>) AnotherRecWhile(); <body>;}

An arbitrary while loop An equivalent recursive function

…Infinite recursion

161

Three-Question Method of verifying recursive functions

Base-Case Question: Is there a nonrecursive way out of the function?

Smaller-Caller Question: Does each recursive function call involve a smaller case of the original problem leading to the base case?

General-Case Question: Assuming each recursive call works correctly, does the whole function work correctly?

162

Guidelines for writing recursive functions

1. Get an exact definition of the problem to be solved.

2. Determine the size of the problem to be solved on this call to the function. On the initial call, the size of the whole problem is expressed by the actual parameter(s).

3. Identify and solve the base case(s) which have non-recursive solutions.

4. Identify and solve the general case(s) in terms of smaller (recursive) cases of the same problem.

163

struct ListType

{ int length ; // number of elements in the list

int info[ MAX_ITEMS ] ;

} ;

ListType list ;

struct ListType

164

Recursive function to determine if value is in list

PROTOTYPE

bool ValueInList( ListType list , int value , int startIndex ) ;

Already searched Needs to be searched

74 36 . . . 95

list[0] [1] [startIndex]

75 29 47 . . .

[length -1]

index of currentelement to examine

bool ValueInList ( ListType list , int value , int startIndex )

// Searches list for value between positions startIndex// and list.length-1// Pre: list.info[ startIndex ] . . list.info[ list.length - 1 ]// contain values to be searched// Post: Function value = // ( value exists in list.info[ startIndex ] . . list.info[ list.length - 1 ] ){ if ( list.info[startIndex] == value ) // one base case

return true ; else if (startIndex == list.length -1 ) // another base case

return false ;else // general case

return ValueInList( list, value, startIndex + 1 ) ;}

165

166

“Why use recursion?”

Many solutions could have been written without recursion, by using iteration instead. The iterative solution uses a loop, and the recursive solution uses an if statement.

However, for certain problems the recursive solution is the most natural solution. This often occurs when pointer variables are used.

167

struct NodeType{

int info ;NodeType* next ;

}

class SortedType {public :

. . . // member function prototypes

private :

NodeType* listData ;

} ;

struct ListType

168

RevPrint(listData);

A B C D E

FIRST, print out this section of list, backwards

THEN, print this element

listData

169

Base Case and General Case

A base case may be a solution in terms of a “smaller” list. Certainly for a list with 0 elements, there is no more processing to do.

Our general case needs to bring us closer to the base case situation. That is, the number of list elements to be processed decreases by 1 with each recursive call. By printing one element in the general case, and also processing the smaller remaining list, we will eventually reach the situation where 0 list elements are left to be processed.

In the general case, we will print the elements of the smaller remaining list in reverse order, and then print the current pointed to element.

170

Using recursion with a linked list

void RevPrint ( NodeType* listPtr )

// Pre: listPtr points to an element of a list.

// Post: all elements of list pointed to by listPtr have been printed

// out in reverse order.

{

if ( listPtr != NULL ) // general case

{

RevPrint ( listPtr-> next ) ; // process the rest

cout << listPtr->info << endl ; // then print this element

}

// Base case : if the list is empty, do nothing

}170

171

Function BinarySearch( )

BinarySearch takes sorted array info, and two subscripts, fromLoc and toLoc, and item as arguments. It returns false if item is not found in the elements info[fromLoc…toLoc]. Otherwise, it returns true.

BinarySearch can be written using iteration, or using recursion.

172

found = BinarySearch(info, 25, 0, 14 );

item fromLoc toLocindexes

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

info 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28

16 18 20 22 24 26 28

24 26 28

24 NOTE: denotes element examined

// Recursive definition

bool BinarySearch ( ItemType info[ ] , ItemType item , int fromLoc , int toLoc )

// Pre: info [ fromLoc . . toLoc ] sorted in ascending order // Post: Function value = ( item in info [ fromLoc . . toLoc] )

{ int mid ;if ( fromLoc > toLoc ) // base case -- not found

return false ; else {

mid = ( fromLoc + toLoc ) / 2 ;

if ( info [ mid ] == item ) // base case-- found at mid

return true ;

else if ( item < info [ mid ] ) // search lower half return BinarySearch ( info, item, fromLoc, mid-1 ) ; else // search upper half

return BinarySearch( info, item, mid + 1, toLoc ) ; }

}

173

174

When a function is called...

A transfer of control occurs from the calling block to the code of the function. It is necessary that there be a return to the correct place in the calling block after the function code is executed. This correct place is called the return address.

When any function is called, the run-time stack is used. On this stack is placed an activation record (stack frame) for the function call.

175

Stack Activation Frames The activation record stores the return address for this

function call, and also the parameters, local variables, and the function’s return value, if non-void.

The activation record for a particular function call is popped off the run-time stack when the final closing brace in the function code is reached, or when a return statement is reached in the function code.

At this time the function’s return value, if non-void, is brought back to the calling block return address for use there.

// Another recursive function

int Func ( int a, int b )

// Pre: a and b have been assigned values// Post: Function value = ??

{ int result;

if ( b == 0 ) // base case

result = 0;

else if ( b > 0 ) // first general case

result = a + Func ( a , b - 1 ) ) ; // instruction 50

else // second general caseresult = Func ( - a , - b ) ; // instruction 70

return result;

}

176

177

FCTVAL ? result ? b 2 a 5Return Address 100

Run-Time Stack Activation Records

x = Func(5, 2); // original call is instruction 100

original call at instruction 100 pushes on this record for Func(5,2)

178

FCTVAL ? result ? b 1 a 5Return Address 50

FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100

record for Func(5,2)

call in Func(5,2) codeat instruction 50 pushes on this recordfor Func(5,1)

Run-Time Stack Activation Records

x = Func(5, 2); // original call at instruction 100

179

FCTVAL ? result ? b 0 a 5Return Address 50

FCTVAL ? result 5+Func(5,0) = ? b 1 a 5Return Address 50

FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100

record for Func(5,2)

record for Func(5,1)

call in Func(5,1) codeat instruction 50pushes on this record for Func(5,0)

Run-Time Stack Activation Records

x = Func(5, 2); // original call at instruction 100

180

FCTVAL 0 result 0 b 0 a 5Return Address 50

FCTVAL ? result 5+Func(5,0) = ? b 1 a 5Return Address 50

FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100

record for Func(5,2)

record for Func(5,1)

record for Func(5,0)is popped first with its FCTVAL

Run-Time Stack Activation Records

x = Func(5, 2); // original call at instruction 100

181

FCTVAL 5 result 5+Func(5,0) = 5+ 0 b 1 a 5Return Address 50

FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100

record for Func(5,2)

record for Func(5,1)is popped nextwith its FCTVAL

Run-Time Stack Activation Records

x = Func(5, 2); // original call at instruction 100

182

FCTVAL 10 result 5+Func(5,1) = 5+5 b 2 a 5Return Address 100

Run-Time Stack Activation Records

x = Func(5, 2); // original call at line 100

record for Func(5,2)is popped lastwith its FCTVAL

183

Show Activation Records for these calls

x = Func( - 5, - 3 );

x = Func( 5, - 3 );

What operation does Func(a, b) simulate?

184

Tail Recursion

The case in which a function contains only a single recursive call and it is the last statement to be executed in the function.

Tail recursion can be replaced by iteration to remove recursion from the solution as in the next example.

// USES TAIL RECURSION

bool ValueInList ( ListType list , int value , int startIndex )

// Searches list for value between positions startIndex// and list.length-1// Pre: list.info[ startIndex ] . . list.info[ list.length - 1 ]// contain values to be searched// Post: Function value = // ( value exists in list.info[ startIndex ] . . list.info[ list.length - 1 ] ){ if ( list.info[startIndex] == value ) // one base case return true ; else if (startIndex == list.length -1 ) // another base case

return false ;else // general case

return ValueInList( list, value, startIndex + 1 ) ;}

185

// ITERATIVE SOLUTION

bool ValueInList ( ListType list , int value , int startIndex )

// Searches list for value between positions startIndex// and list.length-1// Pre: list.info[ startIndex ] . . list.info[ list.length - 1 ]// contain values to be searched// Post: Function value = // ( value exists in list.info[ startIndex ] . . list.info[ list.length - 1 ] ){ bool found = false ; while ( !found && startIndex < list.length )

{ if ( value == list.info[ startIndex ] ) found = true ;

else startIndex++ ;}return found ;

}

186

187

When to Use Recursion If the problem is recursive in nature therefore it is likely

the a recursive algorithm will be preferable and will be less complex

If both recursive and non-recursive algorithm have the same complexity it is likely that a non-recursive version will perform better and therefore should be preferred

A third alternative in some problems is to use table-driven techniques

Sometimes we know that we will not use the only a few values of a particular function

If this is the case an implementation using a table would probably suffice and the performance will be better

int factorial[8] = {1, 1, 2, 6, 24, 120, 720, 5040};int factorial[8] = {1, 1, 2, 6, 24, 120, 720, 5040};

188

Use a recursive solution when:

The depth of recursive calls is relatively “shallow” compared to the size of the problem.

The recursive version does about the same amount of work as the nonrecursive version.

The recursive version is shorter and simpler than the nonrecursive solution.

SHALLOW DEPTH EFFICIENCY CLARITY