Data Structures Chapter 5 Recursion Andreas Savva.

73
Data Structures Data Structures Chapter 5 Chapter 5 Recursion Recursion Andreas Savva

Transcript of Data Structures Chapter 5 Recursion Andreas Savva.

Page 1: Data Structures Chapter 5 Recursion Andreas Savva.

Data StructuresData Structures

Chapter 5Chapter 5RecursionRecursion

Andreas Savva

Page 2: Data Structures Chapter 5 Recursion Andreas Savva.

22

Stack Frames for SubprogramsStack Frames for Subprograms

DD DD

BB CC CC CC DD DD DD

AA AA AA AA AA AA AA DD DD DD DD DD

MM MM MM MM MM MM MM MM MM MM MM MM MM MM MM

Tree of Subprogram CallsTree of Subprogram Calls

MM

AA DD

BB CC

DD

DD

DD

Start Finish

Time

Page 3: Data Structures Chapter 5 Recursion Andreas Savva.

33

Tree-Diagram Definitions The circles in a tree diagram are called The circles in a tree diagram are called verticesvertices or or nodesnodes.. The top of the tree is called its The top of the tree is called its rootroot.. The vertices immediately below a given vertex are called The vertices immediately below a given vertex are called

the the childrenchildren of that vertex.of that vertex. The (unique) vertex immediately above a given vertex is The (unique) vertex immediately above a given vertex is

called its called its parentparent. (The root is the only vertex in the tree . (The root is the only vertex in the tree that has no parent)that has no parent)

The line connecting two vertices is called a The line connecting two vertices is called a branchbranch.. SiblingsSiblings are vertices with the same parent.are vertices with the same parent. A vertex with no children is called a A vertex with no children is called a leafleaf or an or an external external

vertexvertex.. Two branches of a tree are Two branches of a tree are adjacentadjacent if the lower vertex of if the lower vertex of

the first branch is the upper vertex of the second. A the first branch is the upper vertex of the second. A sequence of branches in which each is adjacent to its sequence of branches in which each is adjacent to its successor is called a successor is called a pathpath..

The The heightheight of a tree is the number of vertices on a of a tree is the number of vertices on a longest possible path from the root to a leaf. (Hence a longest possible path from the root to a leaf. (Hence a tree containing only one vertex has height 1.)tree containing only one vertex has height 1.)

The The depthdepth or or levellevel of a vertex is the number of branches of a vertex is the number of branches on a path from the root to the vertex.on a path from the root to the vertex.

Page 4: Data Structures Chapter 5 Recursion Andreas Savva.

44

Every recursive process consists of two Every recursive process consists of two parts:parts:

A base case that is processed without recursion.A base case that is processed without recursion.

A general method that reduces a particular case A general method that reduces a particular case to one or more of the smaller cases, making to one or more of the smaller cases, making progress towards eventually reducing the progress towards eventually reducing the problem all the way to the base case.problem all the way to the base case.

Recursion Recursion

Page 5: Data Structures Chapter 5 Recursion Andreas Savva.

55

Mathematical RecursionMathematical Recursion

Base case: Base case: f(0)f(0) = 0 = 0 Recursion: Recursion: f(n)f(n) = = n n ++ f(n-1) f(n-1) for for n n > 0> 0

f(5)f(5) = 5 + f(4)= 5 + f(4)= 5 + 4 + f(3)= 5 + 4 + f(3)= 5 + 4 + 3 + f(2)= 5 + 4 + 3 + f(2)= 5 + 4 + 3 + 2 + f(1)= 5 + 4 + 3 + 2 + f(1)= 5 + 4 + 3 + 2 + 1 + f(0)= 5 + 4 + 3 + 2 + 1 + f(0)= 5 + 4 + 3 + 2 + 1 + 0= 5 + 4 + 3 + 2 + 1 + 0= 15= 15

Page 6: Data Structures Chapter 5 Recursion Andreas Savva.

66

A Recursive Definition - A Recursive Definition - FactorialFactorial

int factorial(int n)// Pre: n is a nonnegative integer// Post: Return the value of the factorial of n{ if (n == 0) return 1; else return n * factorial(n - 1);}

0 if )!1(

0 if 1!

nnn

nn

1 if 0( )

( 1) if 0

nf n

n f n n

Page 7: Data Structures Chapter 5 Recursion Andreas Savva.

77

MemoryMemoryFactorial(4)Factorial(4)

int factorial(int n){ if (n == 0) return 1; else return n * factorial(n-1);}

void main(){ cout << factorial(4);}

main()main()24

f(4)f(4)nn44

f(3)f(3)nn33

f(2)f(2)nn22

f(1)f(1)nn11

f(0)f(0)nn00

= 4 * f(3) = 4 * f(3)

= 3 * f(2) = 3 * f(2)

= 2 * f(1) = 2 * f(1)

= 1* f(0) = 1* f(0)

= 1= 1 11

= 1 * 1 = 1 = 1 * 1 = 1

= 2 * 1 = 2 = 2 * 1 = 2 22

= 3 * 2 = 6 = 3 * 2 = 6 66

= 4 * 6 = 24 = 4 * 6 = 24

2424

Page 8: Data Structures Chapter 5 Recursion Andreas Savva.

88

MemoryMemory

Recursive Recursive ProcedureProcedure

void Display(){ int n; cin >> n; if (n != -999) { Display(); cout << n << ’ ’; }}

void main(){ Display();}

main

1 3 12 8 -999 <enter>

Displaynn11

Displaynn33

Displaynn1212

Displaynn88

Displaynn

-999-999

88 1212 33 11

Page 9: Data Structures Chapter 5 Recursion Andreas Savva.

99

MemoryMemory

Recursive Recursive ProcedureProcedure

#include <iostream.h>

void display(int n, char c){ if (n != 0) { cout << c; display(n-1,c+1); }}

void main(){ display(4,’A’);}

mainAABBCCDD

displaynn44

cc’’A’A’

displaynn33

cc’’B’B’

displaynn22

cc’’C’C’

displaynn11

cc’’D’D’

displaynn00

cc’’E’E’

Page 10: Data Structures Chapter 5 Recursion Andreas Savva.

1010

ExerciseExercise#include <iostream.h>

void display(int n, int m, char c){ if (n==1 && m==1) cout << c; else if (n > 1) { cout << endl; display(n-1,m,c); } else if (m > 1) { cout << ’ ’; display(n,m-1,c); }}

void main(){ display(3,4,’7’);}

7

123456789 123456789

112233445566

Page 11: Data Structures Chapter 5 Recursion Andreas Savva.

1111

Function Power –Function Power – nn rr

0

1

1r r

n

n n n

1 if 0( , )

( , 1) if r 0

rf n r

n f n r

Base case:Base case:

Key step:Key step:

int power(int n, int r)// Pre: r is a nonnegative integer// Post: Return the value of n to the power r{ if (r == 0) return 1; else return n * power(n, r - 1);}

Page 12: Data Structures Chapter 5 Recursion Andreas Savva.

1212

MemoryMemory

Function PowerFunction Power

#include <iostream.h>

int power(int n, int r){ if (r == 0) return 1; else return n * power(n,r-1);}

void main(){ cout << power(2,4);}

main()1616

f(2,4)nn22

rr44

f(2,3)nn22

rr33

f(2,2)nn22

rr22

f(2,1)nn22

rr11

f(2,0)nn22

rr00

= 2 * f(2,3) = 2 * f(2,3)

= 2 * f(2,2) = 2 * f(2,2)

= 2 * f(2,1) = 2 * f(2,1)

= 2 * f(2,0) = 2 * f(2,0)

= 1 = 1 11

= 2 * 1 = 2 = 2 * 1 = 2 22

= 2 * 2 = 4 = 2 * 2 = 4 44

= 2 * 4 = 8 = 2 * 4 = 8 88

= 2 * 8 = 16 = 2 * 8 = 16 1616

Page 13: Data Structures Chapter 5 Recursion Andreas Savva.

1313

Divide and Conquer: The Towers of Divide and Conquer: The Towers of HanoiHanoi

Developed in the 19Developed in the 19thth century. century.

The problem:The problem:

At the creation of the world, the priests in the temple At the creation of the world, the priests in the temple of Brahma were given a brass platform on which were of Brahma were given a brass platform on which were 3 diamond needles. On the first needle there were 3 diamond needles. On the first needle there were stacked 64 golden disks, each one slightly smaller stacked 64 golden disks, each one slightly smaller than the one under it. The priests were assigned the than the one under it. The priests were assigned the task of moving all the golden disks from the first task of moving all the golden disks from the first needle to the third, subject to the conditions that:needle to the third, subject to the conditions that: only one disk can be moved at a time, andonly one disk can be moved at a time, and no disk is allowed to be placed on top of a smaller no disk is allowed to be placed on top of a smaller

disk.disk.

The priest were told that when they had finished The priest were told that when they had finished moving the 64 disks, it would be the end of the world.moving the 64 disks, it would be the end of the world.

Page 14: Data Structures Chapter 5 Recursion Andreas Savva.

1414

The Towers of HanoiThe Towers of Hanoi

1 2 3

move(64,1,3,2)

meansmeans

““Move 64 disks from tower 1 to tower 3 using tower 2 as temporaryMove 64 disks from tower 1 to tower 3 using tower 2 as temporary

Page 15: Data Structures Chapter 5 Recursion Andreas Savva.

1515

The SolutionThe Solution

move(63,1,2,3) // Move 63 disks from tower 1 to tower 2cout << ”Move disk 64 from tower 1 to tower 3” << endl;move(63,2,3,1) // Move 63 disks from tower 2 to tower 3

1 2 3

63

62. . .

4

3

2

1

6464

63

62. . .

4

3

2

1

63

62. . .

4

3

2

1

Page 16: Data Structures Chapter 5 Recursion Andreas Savva.

1616disks = 3disks = 3

1 2 3

The ProgramThe Programconst int disks = 64;void move(int count, int start, int finish, int temp) {

if (count > 0) {move(count – 1, start, temp, finish);cout << ”Move disk ” << count << ” from ” << start << ” to “ << finish << endl;move(count – 1 , temp, finish, start);

}}int main() {

move(disks, 1, 3, 2); return 0;}

Page 17: Data Structures Chapter 5 Recursion Andreas Savva.

1717

Analysis (disks = 3)Analysis (disks = 3)

Move disk 1 from tower 1 to tower 3Move disk 2 from tower 1 to tower 2Move disk 1 from tower 3 to tower 2Move disk 3 from tower 1 to tower 3Move disk 1 from tower 2 to tower 1Move disk 2 from tower 2 to tower 3Move disk 1 from tower 1 to tower 3move(3,1,3,2)

move(2,1,2,3)move(1,1,3,2)move(0,1,2,3)move(0,2,3,1)move(1,3,2,1)move(0,3,1,2)move(0,1,2,3)

move(2,2,3,1)move(1,2,1,3)move(0,2,3,1)move(0,3,1,2)move(1,1,3,2)move(0,1,2,3)move(0,2,3,1)

move(3,1,3,2)move(3,1,3,2)

move(2,1,2,3)move(2,1,2,3) move(2,2,3,1)move(2,2,3,1)

move(1,1,3,2)move(1,1,3,2)move(1,3,2,1move(1,3,2,1))

move(1,2,1,3)move(1,2,1,3) move(1,1,3,2)move(1,1,3,2)

move(0,1,2,3)move(0,1,2,3)move(0,2,3,1)move(0,2,3,1)

move(0,3,1,2)move(0,3,1,2)move(0,1,2,3)move(0,1,2,3)

move(0,2,3,1)move(0,2,3,1)move(0,3,1,2)move(0,3,1,2)

move(0,1,2,3)move(0,1,2,3)move(0,2,3,1)move(0,2,3,1)

Page 18: Data Structures Chapter 5 Recursion Andreas Savva.

1818

No of Moving Disks (disks=64)No of Moving Disks (disks=64) No of recursions:No of recursions:1 + 2 + 4 + … + 21 + 2 + 4 + … + 26464 == 2 200 + 2 + 21 1 + 2+ 222 + … + 2 + … + 26464 == 2 26565 – –

11== 36,893,488,147,419,103,231 36,893,488,147,419,103,231

No of moving disks:No of moving disks: Excluding the calls with Excluding the calls with count == 0count == 0, which do nothing:, which do nothing:

2200 + 2 + 21 1 + 2+ 222 … + 2 … + 26363 == 2 26464 – 1 – 1== 18,446,744,073,709,551,615 18,446,744,073,709,551,615

No of Seconds in a year:No of Seconds in a year: 32,000,00032,000,000

No of years the priests need to solve the No of years the priests need to solve the problem if they move one disk in every problem if they move one disk in every second:second:

576,460,752,303576,460,752,303

Page 19: Data Structures Chapter 5 Recursion Andreas Savva.

1919

Designing Recursive Designing Recursive AlgorithmsAlgorithms

Find the key step. Begin by asking yourself, “How Find the key step. Begin by asking yourself, “How can this problem be divided into parts?”can this problem be divided into parts?”

Find a stopping rule. This stopping rule is usually Find a stopping rule. This stopping rule is usually the small, special case that is trivial or easy to the small, special case that is trivial or easy to handle without recursion.handle without recursion.

Combine the stopping rule and the key step, Combine the stopping rule and the key step, using an using an if-statementif-statement to select between them.to select between them.

Check termination. Verify that the recursion will Check termination. Verify that the recursion will always terminate. Be sure that your algorithm always terminate. Be sure that your algorithm correctly handles extreme cases.correctly handles extreme cases.

Draw a recursion tree. The height of the tree is Draw a recursion tree. The height of the tree is closely related to the amount of memory that the closely related to the amount of memory that the program will require, and the total size of the tree program will require, and the total size of the tree reflects the number of times the key step will be reflects the number of times the key step will be done.done.

Page 20: Data Structures Chapter 5 Recursion Andreas Savva.

2020

When not to use RecursionWhen not to use RecursionConsider the following two functions for calculating Consider the following two functions for calculating

factorial:factorial:

Recursive:Recursive:

int factorial(int n){if (n == 0) return 1;else return n * factorial(n − 1);

}

Non-recursive:Non-recursive:

int factorial(int n){int count, product = 1;for (count = 1; count <= n; count++)

product *= count;return product;

}

Page 21: Data Structures Chapter 5 Recursion Andreas Savva.

2121

factorial(5) - Recursivefactorial(5) - Recursive

Example:Example:

factorial(5) = 5 * factorial(4)= 5 * (4 * factorial(3))= 5 * (4 * (3 * factorial(2)))= 5 * (4 * (3 * (2 * factorial(1))))= 5 * (4 * (3 * (2 * (1 *

factorial(0)))))= 5 * (4 * (3 * (2 * (1 * 1))))= 5 * (4 * (3 * (2 * 1)))= 5 * (4 * (3 * 2))= 5 * (4 * 6)= 5 * 24= 120

Page 22: Data Structures Chapter 5 Recursion Andreas Savva.

2222

QuestionQuestion

Which of the two functions uses less storage space?Which of the two functions uses less storage space? The recursive one has one variableThe recursive one has one variable The iterative one has three variablesThe iterative one has three variables

But actually the recursive program will set up a But actually the recursive program will set up a stack and fill it in with n+1 numbers:stack and fill it in with n+1 numbers:

n, n-1, n-2, … , 2, 1, 0n, n-1, n-2, … , 2, 1, 0

Thus, the recursive function keeps more storage, Thus, the recursive function keeps more storage, and it will take more time as well, since it must and it will take more time as well, since it must store and retrieve all the numbers as well as store and retrieve all the numbers as well as multiply them.multiply them.

Page 23: Data Structures Chapter 5 Recursion Andreas Savva.

2323

Fibonacci recursive functionFibonacci recursive function

Definition:Definition: Fibonacci numbers Fibonacci numbers are denoted by the are denoted by the

recurrence relationrecurrence relationFF00 = 0 = 0, F, F11 = 1, = 1, F Fnn = = FFnn−1−1 + + FFnn−2−2 for for n n ≥ 2≥ 2

int fibonacci(int n){ if (n == 0) return 0; else if (n == 1) return 1; else return fibonacci(n-1) + fibonacci(n-2); }

00thth 11stst 22ndnd 33rdrd 44thth 55thth 66thth 77thth 88thth ……

00 11 11 22 33 55 88 1313 2121 ……

termterm

Page 24: Data Structures Chapter 5 Recursion Andreas Savva.

2424

fibonacci(7)fibonacci(7)

No of calculations of F(n) grows exponentially with n

Page 25: Data Structures Chapter 5 Recursion Andreas Savva.

2525

Fibonacci iterative functionFibonacci iterative function

int fibonacci(int n){

}

No of calculations of F(n) increases linearly in n

Page 26: Data Structures Chapter 5 Recursion Andreas Savva.

2626

Comparison between Recursion and Comparison between Recursion and IterationIteration

RecursionRecursion IterationIteration

ReadabilityReadability Duplicate tasksDuplicate tasks

Page 27: Data Structures Chapter 5 Recursion Andreas Savva.

2727

Towers of Hanoi without tail recursionTowers of Hanoi without tail recursion

const int disks = 64;

void move(int count, int start, int finish, int temp) { int swap; // temporary storage to swap towers

while (count > 0) { // Replace the if statement with a loop.move(count – 1, start, temp, finish); // first recursive callcout << ”Move disk ” << count << ” from ” << start << ” to “ << finish <<

endl;count--; // Change parameters to mimic the second recursive call.swap = start;start = temp;temp = swap;

}}

int main() {move(disks, 1, 3, 2);

return 0;}

Page 28: Data Structures Chapter 5 Recursion Andreas Savva.

2828

Towers of Hanoi (disks=64)Towers of Hanoi (disks=64) With one recursive call:With one recursive call:

No of recursions No of recursions == 64 + 63 + 62 + … + 1 = 2080 64 + 63 + 62 + … + 1 = 2080

No of variables No of variables == No of Recursions * 5 No of Recursions * 5 == 10,400 10,400

No of variables needed at one time No of variables needed at one time = tree height * 5= tree height * 5== 64 * 5 64 * 5 == 320 320

With two recursive calls:With two recursive calls: No of recursions No of recursions == 36,893,488,147,419,103,231 36,893,488,147,419,103,231

No of variables No of variables == No of Recursions * 4 No of Recursions * 4 == 147,573,952,589,676,412,924 147,573,952,589,676,412,924

No of variables needed at one time No of variables needed at one time = tree height * 4= tree height * 4== 65 * 4 65 * 4 == 260 260

Page 29: Data Structures Chapter 5 Recursion Andreas Savva.

2929

Exercise 1Exercise 1

What is the output of the following program?What is the output of the following program?

#include <iostream>using namespace std;void display(int n){ if (n != 0) { cout << n; display(n-1); cout << n; }}void main(){ display(5);}

Page 30: Data Structures Chapter 5 Recursion Andreas Savva.

3030

Exercise 2Exercise 2

Write a recursive function “Sum” that will Write a recursive function “Sum” that will take an integer number take an integer number nn and it will return and it will return the summation of all the numbers between 1 the summation of all the numbers between 1 and and nn. If . If nn ≤≤ 0 the function should return 0 the function should return zero.zero.

ExamplesExamples:: Sum(4) = 1 + 2 + 3 + 4 = 10Sum(4) = 1 + 2 + 3 + 4 = 10 Sum(0) = 0Sum(0) = 0 Sum(-4) = 0Sum(-4) = 0

Write the same function without recursion.Write the same function without recursion.

Page 31: Data Structures Chapter 5 Recursion Andreas Savva.

3131

Exercise 3Exercise 3

Write a recursive function “Summation” that Write a recursive function “Summation” that will take two integer numbers will take two integer numbers nn and and mm and it and it will return the summation of all the numbers will return the summation of all the numbers between between nn and and mm. If . If nn > > mm the function the function should return zero.should return zero.

ExamplesExamples:: Summation(3, 7) = 3 + 4 + 5 + 6 + 7 = 25Summation(3, 7) = 3 + 4 + 5 + 6 + 7 = 25 Summation(7, 2) = 0Summation(7, 2) = 0 Summation(4,4) = 4Summation(4,4) = 4 Summation(-3,1) = -5Summation(-3,1) = -5

Write the same function without recursion.Write the same function without recursion.

Page 32: Data Structures Chapter 5 Recursion Andreas Savva.

3232

Exercise 4Exercise 4

Write a recursive procedure “Display” that Write a recursive procedure “Display” that will take an integer number will take an integer number nn and display and display all the numbers between 1 and all the numbers between 1 and nn in in reverse order. If reverse order. If nn ≤≤ 0 it should not 0 it should not display anything.display anything.

ExamplesExamples:: Display(5);Display(5); will display: will display: 5 4 3 2 15 4 3 2 1 Display(3);Display(3); will display:will display: 3 2 1 3 2 1

Write the same function without recursion.Write the same function without recursion.

Page 33: Data Structures Chapter 5 Recursion Andreas Savva.

3333

Exercise 5Exercise 5

Write a recursive function “Multiply” that will Write a recursive function “Multiply” that will take two integer numbers take two integer numbers nn and and mm and it will and it will return the multiplication of all the numbers return the multiplication of all the numbers between between nn and and mm. If . If nn > > mm the function the function should return zero.should return zero.

ExamplesExamples:: Multiply(2, 5) = 2 Multiply(2, 5) = 2 ×× 3 3 ×× 4 4 ×× 5 = 120 5 = 120 Multiply(7, 2) = 0Multiply(7, 2) = 0 Multiply(4, 4) = 4Multiply(4, 4) = 4 Multiply(-3, 1) = 0Multiply(-3, 1) = 0

Write the same function without recursion.Write the same function without recursion.

Page 34: Data Structures Chapter 5 Recursion Andreas Savva.

3434

Exercise 6Exercise 6

Write a recursive function “SumEven” that Write a recursive function “SumEven” that will take two integer numbers will take two integer numbers nn and and mm and it and it will return the summation of all the even will return the summation of all the even numbers between numbers between nn and and mm. If . If nn > > mm the the function should return zero.function should return zero.

ExamplesExamples:: SumEven(3, 10) = 4 + 6 + 8 + 10 = 28SumEven(3, 10) = 4 + 6 + 8 + 10 = 28 SumEven(7, 2) = 0SumEven(7, 2) = 0 SumEven(4,4) = 4SumEven(4,4) = 4 SumEven(3,3) = 0SumEven(3,3) = 0

Write the same function without recursion.Write the same function without recursion.

Page 35: Data Structures Chapter 5 Recursion Andreas Savva.

3535

Exercise 7Exercise 7 The The greatest common divisorgreatest common divisor (gcd) of two positive (gcd) of two positive

integers is the largest integer that divides both of them. integers is the largest integer that divides both of them. i.e.i.e.

gcd(8,12) = 4gcd(8,12) = 4

gcd(9,18) = 9gcd(9,18) = 9

gcd(16,25) = 1gcd(16,25) = 1

a)a) Write a non-recursive function, gcd(x,y) that searches through Write a non-recursive function, gcd(x,y) that searches through the positive integers until it finds the largest integer dividing the positive integers until it finds the largest integer dividing both x and y.both x and y.

b)b) Write a recursive function, gcd(x,y) that implements Write a recursive function, gcd(x,y) that implements Euclid’s Euclid’s algorithm:algorithm: if y = 0, then the gcd of x and y is x; otherwise the if y = 0, then the gcd of x and y is x; otherwise the gcd of x and y is the same as the gcd of y and x % y.gcd of x and y is the same as the gcd of y and x % y.

c)c) Rewrite the function of part (b) into iterative form.Rewrite the function of part (b) into iterative form.

d)d) Discuss the advantages and disadvantages of each of these Discuss the advantages and disadvantages of each of these methods.methods.

Page 36: Data Structures Chapter 5 Recursion Andreas Savva.

3636

Exercise 8Exercise 8 The The binomial coefficientsbinomial coefficients can be defined by the can be defined by the

following recurrence relation, which is the idea of following recurrence relation, which is the idea of Pascal’s triangle.Pascal’s triangle.

C(n, 0)C(n, 0) = 1 = 1

C(n, n)C(n, n) = 1 for = 1 for nn ≥ 0≥ 0

C(n, k)C(n, k) = = C(n-1, k)C(n-1, k) + + C(n-1, k-1)C(n-1, k-1) for for n n > > kk > 0 > 0

Page 37: Data Structures Chapter 5 Recursion Andreas Savva.

3737

Exercise 8 (continue)Exercise 8 (continue)

a)a) Write a recursive function to generate Write a recursive function to generate C(n, k)C(n, k) by the by the formula.formula.

b)b) Draw the recursion tree for calculating Draw the recursion tree for calculating C(6, 4)C(6, 4)..

c)c) Use the square array with Use the square array with nn indicating the row and k indicating the row and k the column, and write a non-recursive program to the column, and write a non-recursive program to generate Pascal’s triangle in the lower left half of the generate Pascal’s triangle in the lower left half of the array, that is, in the entries for which array, that is, in the entries for which kk ≤ ≤ nn..

d)d) Write a non recursive program that uses neither an Write a non recursive program that uses neither an array nor a stack to calculate array nor a stack to calculate C(n, k)C(n, k) for arbitrary for arbitrary nn ≥ ≥ kk ≥ 0.≥ 0.

e)e) Determine the approximate space and time Determine the approximate space and time requirements for each of the algorithms devised in (a), requirements for each of the algorithms devised in (a), (c), and (d).(c), and (d).

Page 38: Data Structures Chapter 5 Recursion Andreas Savva.

3838

Exercise 9Exercise 9

What is the output of the following program?What is the output of the following program?

#include <iostream>using namespace std;void display(int n){ if (n > 0) { display(n-1); cout << n; display(n-1); }}void main(){ display(4);}

Page 39: Data Structures Chapter 5 Recursion Andreas Savva.

3939

Exercise 10Exercise 10

What is the output of the following program?What is the output of the following program?

#include <iostream>using namespace std;void display(int n){ if (n > 0) { display(n-1); display(n-1); cout << n; }}void main(){ display(4);}

Page 40: Data Structures Chapter 5 Recursion Andreas Savva.

4040

Exercise 11Exercise 11

What is the output of the following program?What is the output of the following program?

#include <iostream>using namespace std;void display(int n){ if (n > 0) { display(n-1); display(n-2); cout << n; }}void main(){ display(4);}

Page 41: Data Structures Chapter 5 Recursion Andreas Savva.

4141

Exercise 12Exercise 12 What is the output of the following program?What is the output of the following program?

#include <iostream>using namespace std;void display(int n){ if (n > 0) { display(n-1); display(n-2); cout << n; display(n-1); }}void main(){ display(4);}

Page 42: Data Structures Chapter 5 Recursion Andreas Savva.

Exercise 13Exercise 13 An integer is printed with commas inserted An integer is printed with commas inserted

every 3 positions from the right. That is, to every 3 positions from the right. That is, to print the number 12345678 as 12,345,678, the print the number 12345678 as 12,345,678, the 678 cannot be printed until 678 cannot be printed until afterafter the preceding the preceding part of the number is printed. Write a recursive part of the number is printed. Write a recursive function “PrintWithCommas” that will print its function “PrintWithCommas” that will print its longlong integer parameter with commas inserted integer parameter with commas inserted properly.properly.

You must be careful with leading zeros to You must be careful with leading zeros to ensure, for example, that the number 12,003 is ensure, for example, that the number 12,003 is printed properly.printed properly.

4242

Page 43: Data Structures Chapter 5 Recursion Andreas Savva.

4343

Backtracking – The Eight-Queen PuzzleBacktracking – The Eight-Queen Puzzle

Problem:Problem: How to place eight queens on a How to place eight queens on a chessboard so that no queen can take another.chessboard so that no queen can take another.

Even the great C. F. Gauss did not obtain a Even the great C. F. Gauss did not obtain a complete solution when he considered it in 1850.complete solution when he considered it in 1850.

SolutionsSolutions

Page 44: Data Structures Chapter 5 Recursion Andreas Savva.

4444

AlgorithmAlgorithm A more complex recursive applicationA more complex recursive application The choice of data structure can affect a recursive The choice of data structure can affect a recursive

programprogram

Example:Example: 4 Queens (4 x 4 Board) 4 Queens (4 x 4 Board)

Page 45: Data Structures Chapter 5 Recursion Andreas Savva.

4545

Analysis of BacktrackingAnalysis of Backtracking8 Queens8 Queens Check all the cellsCheck all the cells

Amount of work = = 4,426,165,368Amount of work = = 4,426,165,368

Only one queen in each rowOnly one queen in each row

Amount of work = … = 8Amount of work = … = 888 = 16,777,216 = 16,777,216

Only one queen in each columnOnly one queen in each column

Amount of work = … = 8! = 40,320Amount of work = … = 8! = 40,320

648

81

81

81

81

8 times

81

71

61

11

Page 46: Data Structures Chapter 5 Recursion Andreas Savva.

4646

The Main ProgramThe Main Program

void main(){

int board_size; cout << ”What is the size of the board? ”;cin >> board_size;if (board_size < 1 || board_size > max_board)

cout << ”The number must be between 1 and “ << max_board << endl;else{

Queens configuration(board_size);solve(configuration);

}}

Page 47: Data Structures Chapter 5 Recursion Andreas Savva.

4747

The RecursionThe Recursionvoid solve(Queens &configuration){

if (configuration.is_solved()){

confiquration.print();cout << endl;

}else

for (int col = 0; col < configuration.board_size; col++)if (configuration.unguarded(col)){

configuration.insert(col);solve(configuration); // Recursively continue to add queensconfiguration.remove(col);

}}

Page 48: Data Structures Chapter 5 Recursion Andreas Savva.

4848

The Queens classThe Queens class

const max_board = 30;

class Queens {public:

Queens(int size);bool is_solved() const;void print() const;bool unguarded(int col) const;void insert(int col);void remove(int col);int board_size;

private:int count; // current number of queens = first unoccupied rowbool queen_square[max_board][max_board];

}

Page 49: Data Structures Chapter 5 Recursion Andreas Savva.

4949

The ConstructorThe Constructor

Queens::Queens(int size){

board_size = size;count = 0;for (int row = 0; row < board_size; row++)

for (int col = 0; col < board_size; col++)queen_square[row][col] = false;

}

Page 50: Data Structures Chapter 5 Recursion Andreas Savva.

5050

Is_Solved & PrintIs_Solved & Printbool Queens::is_solved() const{

return count == board_size;}

void Queens::print() const{

for (int row = 0; row < board_size; row++){

for (int col = 0; col < board_size; col++)if (queen_square[row][col]) cout <<

”Q”;else cout << ”+”;

cout << endl;}

}

+Q+++++QQ+++++Q+

Page 51: Data Structures Chapter 5 Recursion Andreas Savva.

5151

Insert & RemoveInsert & Remove

void Queens::insert(int col){

queen_square[count++][col] = true;}

void Queens::remove(int col){

queen_square[--count][col] = false;}

Page 52: Data Structures Chapter 5 Recursion Andreas Savva.

5252

UnguardedUnguarded

Page 53: Data Structures Chapter 5 Recursion Andreas Savva.

5353

UnguardedUnguarded

bool Queens::unguarted(int col) const{

int i;bool ok = true;for (i = 0; ok && i < count; i++)

ok = !queen_square[i][col]; // check upper part of columnfor (i = 1; ok && count – i >= 0 && col – i >= 0; i++)

ok = !queen_square[count – i][col – i]; // check upper-left diagonalfor (i = 1; ok && count – i >= 0 && col + i < board_size; i++)

ok = !queen_square[count – i][col + i]; // check upper-right diagonalreturn ok;

}

Page 54: Data Structures Chapter 5 Recursion Andreas Savva.

5454

Review and RefinementReview and Refinement

SizeSize 88 99 10101111 1212 1313Number of solutionsNumber of solutions 9292 352352 7247242,6802,68014,20014,200 73,71273,712Time (seconds)Time (seconds) 0.050.05 0.210.21 1.171.176.626.62 39.1139.11 243.05243.05Time per solution (ms.)Time per solution (ms.) 0.540.54 0.600.60 1.621.622.472.47 2.752.75 3.303.30

Page 55: Data Structures Chapter 5 Recursion Andreas Savva.

5555

The Revised Queens classThe Revised Queens classconst max_board = 30;

class Queens {public:

Queens(int size);bool is_solved() const;void print() const;bool unguarded(int col) const;void insert(int col);void remove(int col);int board_size;

private:int count;bool col_free[max_board];bool upwart_free[2 * max_board – 1];bool downward_free[2 * max_board – 1];int queen_in_row[max_board]; // column number of queen in each row

}

Page 56: Data Structures Chapter 5 Recursion Andreas Savva.

5656

The ConstructorThe Constructor

Queens::Queens(int size){

int i;board_size = size;count = 0;for (i = 0; i < board_size; i++) col_free[i] = true;for (i = 0; i < (2 * board_size – 1); i++)

upward_free[i] = downward_free[i] = true;}

Page 57: Data Structures Chapter 5 Recursion Andreas Savva.

5757

InsertInsert

void Queens::insert(int col){

queen_in_row[count] = col;col_free[col] = false;upward_free[count + col] = false;downward_free[count – col + board_size – 1] = false;count++;

}

Page 58: Data Structures Chapter 5 Recursion Andreas Savva.

5858

RemoveRemove

void Queens::remove(int col){

count--;col_free[col] = true;upward_free[count + col] = true;downward_free[count – col + board_size – 1] = true;

}

Page 59: Data Structures Chapter 5 Recursion Andreas Savva.

5959

UnguardedUnguarded

bool Queens::unguarted(int col) const{

return col_free[col] && upward_free[count + col] && downward_free[count – col + board_size – 1];

}

Homework:Homework: is_solved() print()

Page 60: Data Structures Chapter 5 Recursion Andreas Savva.

6060

Review and RefinementReview and Refinement

SizeSize 88 99 10101111 1212 1313Number of solutionsNumber of solutions 9292 352352 7247242,6802,68014,20014,200 73,71273,712Time (seconds)Time (seconds) 0.050.05 0.210.21 1.171.176.626.62 39.1139.11 243.05243.05Time per solution (ms.)Time per solution (ms.) 0.540.54 0.600.60 1.621.622.472.47 2.752.75 3.303.30

SizeSize 88 99 1010 1111 12121313

Number of solutionsNumber of solutions 9292 352352 724724 2,6802,680 14,20014,20073,71273,712

Time (seconds)Time (seconds) 0.010.01 0.050.05 0.220.22 1.061.06 5.945.9434.4434.44

Time per solution (ms.)Time per solution (ms.) 0.110.11 0.140.14 0.300.30 0.390.39 0.420.420.470.47

First program:First program:

Second program:Second program:

Page 61: Data Structures Chapter 5 Recursion Andreas Savva.

6161

Artificial IntelligenceArtificial IntelligenceLook-ahead in GamesLook-ahead in Games

Game-tree (two players)Game-tree (two players) Even levels denote the legal moves of the first player (root Even levels denote the legal moves of the first player (root

is at level 0)is at level 0) Odd levels denote the legal moves of the second playerOdd levels denote the legal moves of the second player

Example: Example: The game of The game of EightEight:: The first player chooses one of the numbers 1, 2, or 3. At The first player chooses one of the numbers 1, 2, or 3. At

each later turn the appropriate player chooses one of 1, 2, each later turn the appropriate player chooses one of 1, 2, or 3, but the number chosen by the previous player is not or 3, but the number chosen by the previous player is not allowed.allowed.

A running sum of the numbers chosen is kept, and if a A running sum of the numbers chosen is kept, and if a player brings this sum to exactly eight, then the player wins.player brings this sum to exactly eight, then the player wins.

If the player takes the sum over eight, then the other player If the player takes the sum over eight, then the other player wins.wins.

Page 62: Data Structures Chapter 5 Recursion Andreas Savva.

6262

Tree for the game of EightTree for the game of Eight

1

99FF

1010FF

99SS

2 3

1 3

2 3

1 3

2 3

88FF

99SS

1 2

99SS

1010SS

88SS

2 3

21

2 3

1 2

88FF

1010SS

88SS

2 3

1 3

1

99FF

3

99SS

1010SS

2 3

1 3 1 2

11STST

11STST

11STST

22NDND

22NDND

22NDND

Page 63: Data Structures Chapter 5 Recursion Andreas Savva.

6363

Evaluation FunctionEvaluation Function

Examine the current situation and Examine the current situation and return a value assessing its benefits.return a value assessing its benefits.

Usually large integers reflect Usually large integers reflect favorable situations for the first favorable situations for the first player, and small (or more negative) player, and small (or more negative) show an advantage for the second show an advantage for the second player.player.

Page 64: Data Structures Chapter 5 Recursion Andreas Savva.

6464

22FF

The Minimax MethodThe Minimax Method

1

11FF

11FF

-2-2SS

2 3

1 3

2 3

1 3

2 3

22FF

-2-2SS

1 2

-2-2SS

-2-2SS

-3-3SS

2 3

21

2 3

1 2

-2-2SS

-3-3SS

2 3

1 3

1

33FF

3

-2-2SS

-2-2SS

2 3

1 3 1 2

11STST

11STST

11STST

22NDND

22NDND

22NDND Evaluation functionEvaluation function

• 11stst win +ve win +ve• 22ndnd win -ve win -ve

The moveThe move

Page 65: Data Structures Chapter 5 Recursion Andreas Savva.

6565

The Minimax MethodThe Minimax Method

11 11

-2-2

1 3

2 3

1 3

2 3

22 -2-2

1 2

-2-2 -2-2

-3-3

21

2 3

11ST (max)ST (max)

11ST (max)ST (max)

22ND (min)ND (min)

22ND (min)ND (min)

1

11 -2-2

1 3

2 3

3

22 -2-2

1 2

-2-2 -2-2

-3-3

21

2 3

1

11

1 3

2 3

22 -2-2 -3-3

2

11

1 3

-3-3

Should playShould play

Page 66: Data Structures Chapter 5 Recursion Andreas Savva.

6666

Tic-Tac-ToeTic-Tac-Toe

Page 67: Data Structures Chapter 5 Recursion Andreas Savva.

6767

The BoardThe Boardclass Board {public:

Board();bool done() const;void print() const;void Instructions() const;bool better(int value,int old_value) const;void play(Move try_it);int worst_case() const;int evaluate() const;int legal_moves(Stack &moves) const;void operator = (const Board &original);int the_winner() const;

private:int squares[3][3];int moves_done;

};

class Move {public:

Move(int r, int c);int row;int col;

};

Move::Move(int r, int c)

{row = r;col = c;

}

Page 68: Data Structures Chapter 5 Recursion Andreas Savva.

6868

Data StructureData Structure

00 – Empty – Empty 11 – Player 1 – Player 1 22 – Player 2 – Player 2

moves_done = 6moves_done = 6220022

001111

110022

Page 69: Data Structures Chapter 5 Recursion Andreas Savva.

6969

Board methodsBoard methodsBoard::Board() {

for (int i=0; i<3; i++)for (int j=0; j<3; j++)

squares[i][j] = 0;moves_done = 0;

}void Board::play(Move try_it) {

squares[try_it.row][try_it.col] = moves_done % 2 + 1;moves_done++;

}bool Board::better(int a, int b) const { if (moves_done % 2 == 0) return a>=b; else return a<=b;}int Board::worst_case() const { if (moves_done % 2 == 0) return -10; else return 10;}

Player 1 Player 1 always always

starts firststarts first

Page 70: Data Structures Chapter 5 Recursion Andreas Savva.

7070

int Board::the_winner() const { int i; for(i = 0; i < MaxBoard; i++) if (squares[i][0] && squares[i][0] == squares[i][1] && squares[i][0] == squares[i][2]) return squares[i][0];

for(i = 0; i < MaxBoard; i++) if (squares[0][i] && squares[0][i] == squares[1][i] && squares[0][i] == squares[2][i]) return squares[0][i];

if (squares[0][0] && squares[0][0] == squares[1][1] && squares[0][0] == squares[2][2])

return squares[0][0];

if (squares[0][2] && squares[0][2] == squares[1][1] && squares[2][0] == squares[0][2])

return squares[0][2];

return 0;}

Page 71: Data Structures Chapter 5 Recursion Andreas Savva.

7171

int Board::legal_moves(Stack &moves) const {

int count = 0; while(!moves.empty()) moves.pop(); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (squares[i][j] == 0) { Move can_play(i,j); moves.push(can_play); count++; } return count;}

bool Board::done() const { return moves_done == 9 || the_winner()

> 0;}

int Board::evaluate() const { int winner = the_winner(); if (winner == 1) return 10 - moves_done; else if (winner == 2) return moves_done

- 10; else return 0;}

void Board::print() const{ cout << "Move " << moves_done <<

endl; for (int i=0; i<3; i++) { for (int j=0; j<3; j++) cout << squares[i][j]; cout << endl; }}

void Board::operator = (const Board &original)

{ for (int i=0;i<3;i++) for (int j=0;j<3;j++) squares[i][j] = original.squares[i][j]; moves_done = original.moves_done;}

Page 72: Data Structures Chapter 5 Recursion Andreas Savva.

7272

Look AheadLook Aheadint look_ahead(const Board &game, int depth, Move

&recommented) { if (game.done() || depth == 0) return game.evaluate(); else { Stack moves; game.legal_moves(moves); int value, best_value = game.worst_case();

while (!moves.empty()) { Move try_it, reply; moves.top(try_it); Board new_game = game; new_game.play(try_it); value = look_ahead(new_game,depth - 1, reply); if (game.better(value,best_value)) { best_value = value; recommented = try_it; } moves.pop(); } return best_value; }}

Page 73: Data Structures Chapter 5 Recursion Andreas Savva.

7373

The main programThe main programvoid main() { Board game; int depth = 5; Move recomented; int count = 0;

while (!game.done()) { if (count % 2 == 0) { cout << "Enter a Move: "; cin >> recomented.row >> recomented.col; game.play(recomented);

} else { look_ahead(game,depth,recomented); game.play(recomented); } count++; game.print(); } if (game.the_winner() == 1) cout << "You Won" <<

endl; else if (game.the_winner()==2) cout << "You Lost" <<

endl; else cout << “It is a Draw" << endl;}

Player 1 is a Player 1 is a human human playerplayer

Player 2 is Player 2 is the the

computercomputer