- 76 Views
- Uploaded on
- Presentation posted in: General

CHAPTER 10 RECURSION

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

CHAPTER 10RECURSION

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

- 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!

- 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.

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.

int fact(int num)

{

if(num == 0)

return 1;

else

return num * fact(num – 1);

}

cout<<fact(4)<<endl;

- 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.

- 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.

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.

- 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.

if the size of the list is 1

the only element in the list is the largest element

else

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

int largest(constint 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;

}

}

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

//Largest Element in an Array

#include <iostream>

using namespace std;

int largest(constint 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 here

Sample Run:

The largest element in intArray: 76

Example 11-2: Fibonacci Number

The 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:

(11-3)

- 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.1rFibNum(2,5,2) = 5

- 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

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;

//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;

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

Sample Run 2

Enter first Fibonacci number: 3

Enter second Fibonacci number: 4

Enter desired Fibonacci number: 6

Fibonacci number at position 6 is: 29

Sample Run 3

Enter first Fibonacci number: 12

Enter second Fibonacci number: 18

Enter desired Fibonacci number: 15

Fibonacci number at position 15 is: 9582

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.

- 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.

- 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);

}

}

- 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 * 1011years.
- It is estimated that our universe is about 15 billion = 1.5 * 1010 years old.
5 * 1011 = 50 * 1010 33 *(1.5 * 1010).

- 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.

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.

- 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.

- 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.

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:
weight6 5 4 3 2 1 0

1 0 0 1 1 0 1

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

- 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.

void binToDec(int binaryNumber, int& decimal,

int& weight)

{

//Add your code here

}

decimalNumber = 0;

bitWeight = 0;

binToDec(1101,decimalNumber,bitWeight);

//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;

}

//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

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.

- 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.

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.

//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;

}

- 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