48
CHAPTER 10 RECURSION

CHAPTER 10 RECURSION

Embed Size (px)

DESCRIPTION

CHAPTER 10 RECURSION. In this chapter, you will: Learn about recursive definitions Explore the base case and the general case of a recursive definition Discover what is a recursive algorithm Learn about recursive functions - PowerPoint PPT Presentation

Citation preview

Page 1: CHAPTER  10 RECURSION

CHAPTER 10

RECURSION

Page 2: CHAPTER  10 RECURSION

In this chapter, you will: Learn about recursive definitions Explore the base case and the general case of a

recursive definition Discover what is a recursive algorithm Learn about recursive functions Explore how to use recursive functions to

implement recursive algorithms

Page 3: CHAPTER  10 RECURSION

• The process of solving a problem by reducing it to smaller versions of itself is called recursion.

The factorial of an integer is defined as follows:

0! = 1 (11-1)n! = n (n-1)! if n 0 (11-2)

• Find 3!. •n = 3. Since n 0, we use equation (11-2) to obtain

3! = 3 2!

• Next, we find 2! Here n = 2. Since n 0, we use equation (11-2) to obtain

2! = 2 1!

• Now to find 1!, we again use equation (11-2) since n = 1 0. Thus

1! = 1 0!

Page 4: CHAPTER  10 RECURSION

• Use equation (11-1) to find 0! which is 1. • Substituting, 0! into 1! gives 1! = 1. This gives 2! = 2 1! = 2 1 = 2, which in turn gives 3! = 3 2! = 3 2 = 6.

• The definition of factorial as given by equations (11-1) and (11-2) is called a recursive definition.

• Equation (11-1) is called the base case (that is, for which the solution is direct).

• Equation (11-2) is called the general case.

Recursive definition: A definition in which something is defined in terms of a smaller version of itself.

Page 5: CHAPTER  10 RECURSION

1. Every recursive definition must have one (or more) base cases.2. The general case must eventually reduce to a base case.3. The base case stops the recursion.

An algorithm which finds the solution of a given problem by reducing the problem to smaller versions of itself is called a recursive algorithm.

The recursive algorithm must have one (or more) base cases. The general solution must eventually reduce to a base case. A function that calls itself is called a recursive function. Recursive algorithms are implemented using recursive functions.

Page 6: CHAPTER  10 RECURSION

int fact(int num){ if(num == 0) return 1; else return num * fact(num – 1);}

cout<<fact(4)<<endl;

Page 7: CHAPTER  10 RECURSION
Page 8: CHAPTER  10 RECURSION

Logically, you can think of a recursive function as having infinitely many copies of itself.

Every call to a recursive function—that is, every recursive call—has its own code and its own set of parameters and local variables.

After completing a particular recursive call, the control goes back to the calling environment, which is the previous call.

The current (recursive) call must execute completely before the control goes back to the previous call.

The execution in the previous call begins from the point immediately following the recursive call.

Page 9: CHAPTER  10 RECURSION

A recursive function in which the last statement executed is the recursive call is called a tail recursive function.

The function fact is an example of a tail recursive function.

Page 10: CHAPTER  10 RECURSION

Example 11-1: Largest Element in the Array

Suppose list is the name of the array containing the list elements. list[a]...list[b] stands for the array elements list[a], list[a+1], ..., list[b].

list[0]...list[5] represents the array elements list[0], list[1], list[2], list[3], list[4], and list[5].

list[1]...list[5] represents the array elements list[1], list[2], list[3], list[4], and list[5].

To write a recursive algorithm to find the largest element in list, let us think in terms of recursion.

Page 11: CHAPTER  10 RECURSION

If list is of length 1, then list has only one element, which is the largest element.

Suppose the length of list is greater than 1. To find the largest element in list[a]...list[b], we first find the largest element in list[a+1]...list[b] and then compare this largest element with list[a].

maximum(list[a], largest(list[a+1]...list[b]))

The largest element in given by list[0]...list[5] .

maximum(list[0], largest(list[1]...list[5]))

The largest element in list[1]...list[5] is

maximum(list[1], largest(list[2]...list[5]))

and so on.

Page 12: CHAPTER  10 RECURSION

if the size of the list is 1 the only element in the list is the largest elementelse to find the largest element in list[a]...list[b] a. find the largest element in list[a+1]...list[b] and call it max

b. compare the elements list[a] and max if(list[a] >= max) the largest element in list[a]...list[b] is

list[a] otherwise the largest element in list[a]...list[b] is max

Page 13: CHAPTER  10 RECURSION

int largest(const int list[], int lowerIndex, int upperIndex)

{ int max;

if(lowerIndex == upperIndex) //size of the sublist is 1 return list[lowerIndex]; else {

max = largest(list, lowerIndex + 1, upperIndex); if(list[lowerIndex] >= max)

return list[lowerIndex];else

return max; }}

Page 14: CHAPTER  10 RECURSION

cout<<largest(list,0,3);

Page 15: CHAPTER  10 RECURSION
Page 16: CHAPTER  10 RECURSION

//Largest Element in an Array

#include <iostream>

using namespace std;

int largest(const int list[], int lowerIndex, int upperIndex);

int main(){

int intArray[10] = {23, 43, 35, 38, 67, 12, 76, 10, 34, 8};

cout<<"The largest element in intArray: " <<largest(intArray,0,9);cout<<endl;

return 0;}//Place the definition of the function largest hereSample Run:The largest element in intArray: 76

Page 17: CHAPTER  10 RECURSION

Example 11-2: Fibonacci NumberThe following recursive algorithm calculates the nth Fibonacci number, where a denotes the first Fibonacci number, b the second Fibonacci number, and n the nth Fibonacci number:

.2 if)2,rFibNum()1rFibNum(

2 if1 if

),rFibNum(nna,ba,b,nnbna

na,b

(11-3)

Page 18: CHAPTER  10 RECURSION

Determine recFibNumber(2,5,4)

Here a = 2, b = 5, and n = 4. Because n is 4 > 2,

1. rFibNum(2,5,4) = rFibNum(2,5,3) + rFibNum(2,5,2)

Next, we determine rFibNum(2,5,3) and rFibNum(2,5,2). First determine rFibNum(2,5,3). Here, a = 2, b = 5, and n is 3. Since n is 3,

1.a rFibNum(2,5,3) = rFibNum(2,5,2)+ rFibNum(2,5,1)

Determine rFibNum(2,5,2)and rFibNum(2,5,1). In rFibNum(2,5,2), a = 2, b = 5, and n = 2. From the definition given in Equation 11-3, it follows that

1.a.1 rFibNum(2,5,2) = 5

Page 19: CHAPTER  10 RECURSION

Find rFibNum(2,5,1); a = 2, b = 5, and n = 1. By the definition given in Equation 11-3,

1.a.2 rFibNum(2,5,1) = 2

Substitute the values of rFibNum(2,5,2)and rFibNum(2,5,1) into (1.a) to get

rFibNum(2,5,3) = 5 + 2 = 7

Next, determine rFibNum(2,5,2). As in (1.a.1), rFibNum(2,5,2) = 5. We can substitute the values of rFibNum(2,5,3)and rFibNum(2,5,2) into (1) to get

rFibNum(2,5,4) = 7 + 5 = 12

Page 20: CHAPTER  10 RECURSION

int rFibNum(int a, int b, int n)

{

if(n == 1)

return a;

else if(n == 2)

return b;

else

return rFibNum(a, b, n - 1) + rFibNum(a, b, n - 2);

}

cout<<recFibNumber(2, 3, 5)<<endl;

Page 21: CHAPTER  10 RECURSION
Page 22: CHAPTER  10 RECURSION

//Chapter 10: Fibonacci Number

#include <iostream>

using namespace std;

int rFibNum(int a, int b, int n);

int main(){ int firstFibNum; int secondFibNum; int nth;

cout<<"Enter first Fibonacci number: "; cin>>firstFibNum; cout<<endl;

cout<<"Enter second Fibonacci number: "; cin>>secondFibNum; cout<<endl;

Page 23: CHAPTER  10 RECURSION

cout<<"Enter desired Fibonacci number: "; cin>>nth; cout<<endl;

cout<<"Fibonacci number at position "<<nth<<" is: " << rFibNum(firstFibNum, secondFibNum, nth)<<endl;

return 0;}

//Place the definition of the function rFibNum here

Sample Runs: In these sample runs, the user input is in red.Sample Run 1

Enter first Fibonacci number: 2

Enter second Fibonacci number: 5

Enter desired Fibonacci number: 6

Fibonacci number at position 6 is: 31

Page 24: CHAPTER  10 RECURSION

Sample Run 2Enter first Fibonacci number: 3

Enter second Fibonacci number: 4

Enter desired Fibonacci number: 6

Fibonacci number at position 6 is: 29

Sample Run 3Enter first Fibonacci number: 12

Enter second Fibonacci number: 18

Enter desired Fibonacci number: 15

Fibonacci number at position 15 is: 9582

Page 25: CHAPTER  10 RECURSION

Example 11-3: Tower of Hanoi At the creation of the universe, priests in the temple of Brahama were

supposedly given three diamond needles, with one needle containing 64 golden disks.

Each golden disk is slightly smaller than the disk below it. The priests’ task is to move all 64 disks from the first needle to the third needle.

The rules for moving the disks are as follows:

1. Only one disk can be moved at a time.2. The removed disk must be placed on one of the needles.3. A larger disk cannot be placed on top of a smaller disk.

Page 26: CHAPTER  10 RECURSION
Page 27: CHAPTER  10 RECURSION

Let us first consider the case when the first needle contains only one disk. In this case, the disk can be moved directly from needle 1 to needle 3.

Consider the case when the first needle contains only two disks. First we move the first disk from needle 1 to needle 2, and then we

move the second disk from needle 1 to needle 3. Finally, we move the first disk from needle 2 to needle 3.

Suppose that needle 1 contains three disks. To move disk number 3 to needle 3, the top two disks must first be

moved to needle 2. Disk number 3 can then be moved from needle 1 to needle 3. To move the top two disks from needle 2 to needle 3, we use the same

strategy as before. This time we use needle 1 as the intermediate needle.

Page 28: CHAPTER  10 RECURSION
Page 29: CHAPTER  10 RECURSION

• Suppose that needle 1 contains n disks, where n 1. 1. Move the top n - 1 disks from needle 1 to needle 2 using needle

3 as the intermediate needle. 2. Move disk number n from needle 1 to needle 3.3. Move the top n - 1 disks from needle 2 to needle 3 using needle

1 as the intermediate needle.

void moveDisks(int count, int needle1, int needle3, int needle2)

{ if(count > 0) { moveDisks(count-1, needle1, needle2, needle3); cout<<"Move disk "<<count<<" from "<<needle1

<<" to "<<needle3<<"."<<endl; moveDisks(count-1, needle2, needle3, needle1);

}}

Page 30: CHAPTER  10 RECURSION

If needle 1 contains 3 disks, then the number of moves required to move all 3 disks from needle 1 to needle 3 is 23- 1 = 7.

If needle 1 contains 64 disks, then the number of moves required to move all 64 disks from needle 1 to needle 3 is 264 - 1. 210 = 1024 1000 = 103, 264 = 24 * 260 24 * 1018 = 1.6 * 1019

The number of seconds in one year is approximately 3.2 * 107. Suppose the priests move one disk per second and they do not rest. Now

1.6 * 1019 = 5 * 3.2 * 1018 = 5 * (3.2 *107) * 1011 = (3.2 *107) * (5 * 1011)

The time required to move all 64 disks from needle 1 to needle 3 is roughly 5 * 1011 years.

It is estimated that our universe is about 15 billion = 1.5 * 1010 years old. 5 * 1011 = 50 * 1010 33 *(1.5 * 1010).

Page 31: CHAPTER  10 RECURSION

This calculation shows that our universe would last about 33 times as long as it already has.

Assume that a computer can generate 1 billion = 109 moves per second. Then the number of moves that the computer can generate in one year is

(3.2 *107) * 109 = 3.2 * 1016

So the computer time required to generate 264 moves is

264 1.6 * 1019 = 1.6 * 1016 * 103 = (3.2 * 1016) * 500

Thus, it would take about 500 years for the computer to generate 264 moves at the rate of 1 billion moves per second.

Page 32: CHAPTER  10 RECURSION

RECURSION OR ITERATION? Iterative control structures use a looping structure, such as while, for, or do...while, to repeat a set of statements.

There are usually two ways to solve a particular problem—iteration and recursion.

The obvious question is which method is better—iteration or recursion?

In addition to the nature of the problem, the other key factor in determining the best solution method is efficiency.

Example 7-6 (Chapter 7), while tracing the execution of the problem, showed us that whenever a function is called, memory space for its formal parameters and (automatic) local variables is allocated.

When the function terminates, that memory space is then deallocated.

This chapter, while tracing the execution of recursive functions, also shows us that every (recursive) call has its own set of parameters and (automatic) local variables.

Page 33: CHAPTER  10 RECURSION

There is overhead associated with executing a (recursive) function both in terms of memory space and computer time.

A recursive function executes more slowly than its iterative counterpart.

On slower computers, especially those with limited memory space, the (slow) execution of a recursive function would be visible.

Today’s computers, however, are fast and have inexpensive memory. Therefore, the execution of a recursion function is not noticeable.

Keeping the power of today’s computer in mind, the choice between the two alternatives—iteration or recursion—depends on the nature of the problem.

For problems such as mission control systems, efficiency is absolutely critical and, therefore, the efficiency factor would dictate the solution method.

If an iterative solution is more obvious and easier to understand than a recursive solution, use the iterative solution, which would be more efficient.

Page 34: CHAPTER  10 RECURSION

On the other hand, problems exist for which the recursive solution is more obvious or easier to construct, such as the Tower of Hanoi problem.

Keeping the power of recursion in mind, if the definition of a problem is inherently recursive, then you should consider a recursive solution.

Page 35: CHAPTER  10 RECURSION

PROGRAMMING EXAMPLE: CONVERTING A NUMBER FROM BINARY TO DECIMAL

To convert a number from base 2 to base 10, we first find the weight of each bit in the binary number.

The weight of each bit in the binary number is assigned from right to left.

The weight of the rightmost bit is 0. The weight of the bit immediately to the left of the rightmost bit is 1, the weight of the bit immediately to the left of it is 2, and so on.

Consider the binary number 1001101. The weight of each bit is as follows:

weight 6 5 4 3 2 1 0 1 0 0 1 1 0 1

Page 36: CHAPTER  10 RECURSION

For the above binary number the equivalent decimal number is

1 * 26 + 0 * 25 + 0 * 24 + 1 * 23 + 1 * 22 + 0 * 21 + 1 * 20 = 64 + 0 + 0 + 8 + 4 + 0 + 1= 77

Page 37: CHAPTER  10 RECURSION

To write a program that converts a binary number into the equivalent decimal number, we note two things: (1) the weight of each bit in the binary number must be known, and (2) the weight is assigned from right to left.

Because we do not know in advance how many bits are in the binary number, we must process the bits from right to left.

After processing a bit, we can add 1 to its weight, giving the weight of the bit immediately to the left to it.

Each bit must be extracted from the binary number and multiplied by 2 to the power of its weight.

To extract a bit, we can use the mod operator.

Page 38: CHAPTER  10 RECURSION

void binToDec(int binaryNumber, int& decimal, int& weight){

//Add your code here}

Page 39: CHAPTER  10 RECURSION

decimalNumber = 0;bitWeight = 0;binToDec(1101,decimalNumber,bitWeight);

Page 40: CHAPTER  10 RECURSION
Page 41: CHAPTER  10 RECURSION

//Chapter 10: Program - Binary to Decimal

#include <iostream>#include <cmath>

using namespace std;void binToDec(int binaryNumber, int& decimal, int& weight);

int main(){

int decimalNum;int bitWeight;int binaryNum;

decimalNum = 0;bitWeight = 0;cout<<"Enter number in binary: ";cin>>binaryNum;cout<<endl;binToDec(binaryNum, decimalNum, bitWeight);cout<<"Binary "<<binaryNum<<" = "<<decimalNum <<" decimal"<<endl;return 0;

}

Page 42: CHAPTER  10 RECURSION

//Place the definition of the function binToDec here

Sample Run: In this sample run, the user input is in red.

Enter number in binary: 11010110

Binary 11010110 = 214 decimal

Page 43: CHAPTER  10 RECURSION

PROGRAMMING EXAMPLE: CONVERTING A NUMBER FROM DECIMAL TO BINARY

This programming example discusses and designs a program that uses recursion to convert a non-negative integer in decimal format—that is, base 10—into the equivalent binary number—that is, base 2. First we define some terms.

Let x be an integer. We call the remainder of x after division by 2 the rightmost bit of x. The rightmost bit of 33 is 1 because 33 % 2 is 1. The rightmost bit of 28 is 0 because 28 % 2 is 0. Find the binary representation of 35. First, we divide 35 by 2. The

quotient is 17 and the remainder—that is, the rightmost bit of 35—is 1. Next, we divide 17 by 2. The quotient is 8 and the remainder—that is, the rightmost bit of 17—is 1. Next, we divide 8 by 2. The quotient is 4 and the remainder—that is, the rightmost bit of 8—is 0. We continue this process until the quotient becomes 0.

Page 44: CHAPTER  10 RECURSION

The rightmost bit of 35 cannot be printed until we have printed the rightmost bit of 17. The rightmost bit of 17 cannot be printed until we have printed the rightmost bit of 8, and so on.

The binary representation of 35 is the binary representation of 17 (that is, the quotient of 35 after division by 2), followed by the rightmost bit of 35.

1. binary(num) = num if num = 0.2. binary(num) = binary(num/2) followed by num%2 if num > 0.

Page 45: CHAPTER  10 RECURSION

void decToBin(int num, int base){ if(num > 0) {decToBin(num/base, base);cout<<num % base;

}}

decToBin(13, 2);

• Here num is 13 and base is 2.

Page 46: CHAPTER  10 RECURSION
Page 47: CHAPTER  10 RECURSION

//Chapter 10: Program - Decimal to Binary

#include <iostream>

using namespace std;

void decToBin(int num, int base);

int main(){

int decimalNum;int base;

base = 2;

cout<<"Enter number in decimal: ";cin>>decimalNum;cout<<endl;cout<<"Decimal "<<decimalNum<<" = ";decToBin(decimalNum, base);cout<<" binary"<<endl;

return 0;}

Page 48: CHAPTER  10 RECURSION

void decToBin(int num, int base){ if(num > 0) {

decToBin(num/base, base);cout<<num % base;

}}

Sample Run: In this sample run, the user input is in red.

Enter number in decimal: 57

Decimal 57 = 111001 binary