pptx - Computing Science

advertisement
CMPT 128: Introduction to
Computing Science for
Engineering Students
Recursion
© Janice Regan, CMPT 128, February. 2007
0
Introduction to Recursion
 Recursion:
 A function that calls itself is said to be a recursive
function
 A function that calls itself results in direct recursion
 If function A calls function B, and in turn function B
calls function A this results in indirect recursion
 C++, like most high-level languages, allows
recursion

Recursion can result in elegant easy to understand
and develop code (‘efficient’ development and
maintenance)
 Recursion may be less ‘efficient’ to execute than an
equivalent iterative solution,
© Janice Regan, CMPT 128,2007-2013
1
Recursive void Functions
 Recursion is based on the design technique
know as ‘divide and conquer’

Divide: break the task into smaller parts
 Conquer: solve a large and complex problem
efficiently
 When solving a problem recursively
 Divide: each smaller part of the task is the same as
the whole task

The same algorithm or series of steps is used for the whole
problem and for each smaller task the problem is divided
into
© Janice Regan, CMPT 128,2007-2013
2
Example: quick sort
 Consider large task: sort a large array into descending
order



Choose pivot from ‘middle’ of array, Switch the pivot and first
element in array
Sort the array into two parts, one with all numbers larger than
the pivot, one with all numbers smaller than the pivot
Move the pivot back between the two parts
 Subtasks must be smaller versions of original task


Subtask 1: repeat the main task on the part of the array with
elements larger than the pivot
Subtask 2: repeat the main task on the part of the array with
elements smaller than the pivot.
 Quick sort is a method of the type that is well suited to
be solved by recursion
© Janice Regan, CMPT 128,2007-2013
3
Recursive void Function:
a simple example
 Task: calculate the sum of the squares of all
integers from 1 to j, for all integers j from 1 to n.
Display sums of integers vertically, one line for
each j, beginning with j=1
 Example call:
sumSqIntegers(4);
Produces output:
1
5
14
30
© Janice Regan, CMPT 128,2007-2013
4
Sums of squares: Recursive Definition
 Break problem into two cases
 Base case: if n=1
 Simply write number n to screen (1*1=1)
 Do not call the function again
 Return to the calling function (previous recursive call)
 Recursive case: if n>1, two subtasks:
 Calculate and print all sums for j=1,..,n-1
 Calculate and print the sum for j=n
 Return to the calling function
© Janice Regan, CMPT 128,2007-2013
5
Sums of squares: Recursive Definition
 Example: argument 4:
 1st subtask calculates the sums for each j
j=1,…,3 and prints them one per line 1, 5, 14

Call the function sumSqIntegers for j-1
 2nd subtask calculates the sum for j=4 and
prints it on a new line, 30
 Return to the calling program
© Janice Regan, CMPT 128,2007-2013
6
sumSqIntegers: Function Definition
void sumSqIntegers(int maxInteger, int& value)
{
if (maxInteger == 1)
{
cout << maxInteger << endl;
//Base case
value = maxInteger;
}
else
{
sumSqIntegers(maxInteger-1, value);
value += maxInteger * maxInteger;
//Recursive case
cout << value << endl;
}
}
© Janice Regan, CMPT 128,2007-2013
7
Sums of squares: Trace (1)
 Example call:
sumSqIntegers(4,value);
sumSqIntegers(3,value);
sumSqIntegers(2,value);
sumSqIntegers(1,value);
cout << 1 << endl;
cout << 2*2 + 1 << endl;
cout << 3*3 + 5 << endl;
cout << 4*4 +14 << endl;
© Janice Regan, CMPT 128,2007-2013
//1st call
//2nd call
//3rd call
//4th call
//4th call
//3rd call
//2nd call
//1st call
8
Sums of squares: Trace (2)







During 1st call n=4, and the function is called for n=3 (recursive case)
During 2nd call n=3, and the function is called for n=2 (recursive case)
During 3rd call n=2, and the function is called for n=1 (recursive case)
During 4th call n=1, 1is printed to the screen and the cursor moves to
the next line (stopping case) then returns to 3rd case
During the remainder of the 3rd call n=2, 5 is printed to the screen and
the cursor moves to the next line (completes recursive case) then
returns to 2nd case
During the remainder of the 2nd call n=3, 14 is printed to the screen
and the cursor moves to the next line (completes recursive case) then
returns to 1st case
During the remainder of the 1st call n=4, 30 is printed to the screen
and the cursor moves to the next line (completes recursive case) then
returns to calling program
© Janice Regan, CMPT 128,2007-2013
9
Sums of squares: Trace (3)
Calling function:
sumSqIntegers(4, value)
void sumSqIntegers(int maxInteger, int& value)
{
if (maxInteger == 1)
{
1st call:
sumSqIntegers(3, value)
//Base case
cout << maxInteger << endl;
value = maxInteger;
2nd call:
sumSqIntegers(2, value)
}
else
{
//Recursive case
sumSqIntegers(maxInteger-1, value);
value += maxInteger * maxInteger;
cout << value << endl;
}
3rd call:
sumSqIntegers(1, value)
4th call:
Print 1, value=1
© Janice Regan, CMPT 128,2007-2013
}
10
Sums of squares: Trace (4)
Calling function:
sumSqIntegers(4, value)
void sumSqIntegers(int maxInteger, int& value)
{
if (maxInteger == 1)
{
1st call:
sumSqIntegers(3, value)
//Base case
cout << maxInteger << endl;
value = maxInteger;
}
else
{
//Recursive case
sumSqIntegers(maxInteger-1, value);
value += maxInteger * maxInteger;
cout << value << endl;
}
2nd call:
sumSqIntegers(2, value)
3rd call:
determine value
value = 1+2*2
Print 5
}
© Janice Regan, CMPT 128,2007-2013
11
Sums of squares: Trace (5)
Calling function:
sumSqIntegers(4, value)
void sumSqIntegers(int maxInteger, int& value)
{
if (maxInteger == 1)
{
1st call:
sumSqIntegers(3, value)
//Base case
cout << maxInteger << endl;
value = maxInteger;
}
else
{
//Recursive case
sumSqIntegers(maxInteger-1, value);
value += maxInteger * maxInteger;
cout << value << endl;
}
2nd call:
determine value
value = 5 + 3*3
Print 14
}
© Janice Regan, CMPT 128,2007-2013
12
Sums of squares: Trace (6)
Calling function:
sumSqIntegers(4, value)
void sumSqIntegers(int maxInteger, int& value)
{
if (maxInteger == 1)
{
1st call:
determine value
value = 14+4*4
Print 30
//Base case
cout << maxInteger << endl;
value = maxInteger;
}
else
{
//Recursive case
sumSqIntegers(maxInteger-1, value);
value += maxInteger * maxInteger;
cout << value << endl;
}
}
© Janice Regan, CMPT 128,2007-2013
13
Infinite Recursion
 Base case MUST eventually be entered
 If there is no base case OR
 If the base case is never reached
 Then recursion continues for ever (or at least until
memory for new function frames is exhausted)
 In our example (sumSqIntegers):
 Base case happened when we reached 1, the sum of
the squares of integers 1,..,1 is 1
 That’s when recursion stopped and we began
returning up through the stack of recursive frames
© Janice Regan, CMPT 128,2007-2013
14
Infinite Recursion: Example
 Consider alternate function definition:
void altSumSqIntegers(int maxInteger, int& value)
{
altsumSqIntegers(maxInteger-1, value);
value += maxInteger * maxInteger;
cout << value << endl;
}
 Seems logical on the surface but there is no stopping
case so recursion never stops
© Janice Regan, CMPT 128,2007-2013
15
Recursion: Review
 A recursive function must have:

One or more recursive cases where the function
accomplishes it’s task by:


Making one or more recursive calls to solve
smaller versions of original task
One or more base cases or stopping cases where
the function accomplishes it’s task by simple
calculation without recursive call
© Janice Regan, CMPT 128,2007-2013
16
Stacks for Recursion
 A stack
 Specialized memory structure
 Like stack of paper



Place each new page (frame) on top
When you finish with one page (frame) then take the page
(frame) from the top of the stack and continue
Called "last-in/first-out“ (LIFO) memory structure
 Recursion uses stacks
 Each recursive call placed on stack
 When one completes, last call is removed
from stack
© Janice Regan, CMPT 128,2007-2013
17
Stack Overflow
 Size of stack limited
 Memory is finite
 Long chain of recursive calls continually
adds to stack

All are added before base case causes removals
 If stack attempts to grow beyond limit:
 Stack overflow error
 Infinite recursion always causes this
© Janice Regan, CMPT 128,2007-2013
18
Why Use Recursion
 Recursion is not always the ‘best solution’
 Some languages do not allow recursion
 Any task accomplished with recursion can
also be done using iteration
 Recursive:

Recursion can result in elegant easy to understand
and develop code (‘efficient’ development and
maintenance)
 Recursion may be less ‘efficient’ to execute than an
equivalent iterative solution (may run slower)
© Janice Regan, CMPT 128,2007-2013
19
Recursive Functions can have any type
 Recursion not limited to void functions
 Can return value of any type
 Same approach as for our original example
 Let’s recast that original example so that the
recursive function has type int rather than type
void
© Janice Regan, CMPT 128,2007-2013
20
sumSqIntegers: Function Definition
int sumSqIntegers(int maxInteger)
{
int value;
if (maxInteger == 1)
{
cout << maxInteger << endl;
return(maxInteger);
}
else
{
sumSqIntegers(maxInteger-1);
value += maxInteger * maxInteger;
cout << value << endl;
return(value);
}
}
© Janice Regan, CMPT 128,2007-2013
//Base case
//Recursive case
21
Sums of squares: Trace (1)
 Example call:
sumSqIntegers(4);
sumSqIntegers(3);
sumSqIntegers(2);
sumSqIntegers(1);
cout << 1 << endl;
cout << 2*2 + 1 << endl;
cout << 3*3 + 5 << endl;
cout << 4*4 +14 << endl;
© Janice Regan, CMPT 128,2007-2013
//1st call
//2nd call
//3rd call
//4th call
//4th call
//3rd call
//2nd call
//1st call
22
Return a Value
Recursion Example: Powers
 Recall predefined function pow():
result = pow(2.0,3.0);
 Returns 2 raised to power 3 (8.0)
 Takes two double arguments
 Returns double value
 Let’s write recursively
 For simple example
© Janice Regan, CMPT 128,2007-2013
23
Function Definition for power()
int power(int x, int n)
{
if (n<0)
{
cout << "Illegal argument";
exit(1);
}
if (n>0)
{ return (power(x, n-1)*x); }
else
{ return (1); }
}
© Janice Regan, CMPT 128,2007-2013
24
Calling Function power()
 Larger example:
power(2,3);
 power(2,2)*2
 power(2,1)*2
power(2,0)*2
1
 Reaches base case
 Recursion stops
 Values "returned back" up stack
© Janice Regan, CMPT 128,2007-2013
25
Recursive Design Techniques


Start simple
Make sure the problem can be broken into parts that
are copies of each other and the ‘whole’ problem
Define your recursive cases



Define your stopping case or cases



Do the recursive cases return or produce the correct results
When will the series of recursive calls end
Do the stopping cases return or produce the correct results
Make sure that you stop your recursive case and enter
the stopping cases when conditions are correct
© Janice Regan, CMPT 128,2007-2013
26
Recursive design: power
 Consider power() again
 Can the problem be broken down into smaller parts:


xn = xi*xk where n=i+k
this problem can be broken down into parts that are equivalent
to the ‘whole’ problem
 Design the recursive case


power(x, n) returns: power(x, n – 1) * x
Is this correct? xn = xn-1*x so yes
 Design the stopping case



x0=1, x1=x When do we stop?
When n=0 we know the answer regardless of the value of x
So out stopping case is n=0, x0=1
© Janice Regan, CMPT 128,2007-2013
27
Recursive Design Check: power()
 Can infinite recursion happen with the power()
function we have designed


2nd argument decreases by 1 each call
Eventually we will reach the base case of n=0
 Does the stopping case return the correct value:
 n=0 is base case which implies power(x,0)
 power(x,0) returns 1, which is correct for x0
 Does the recursive case return the correct
value:


For n>1, power(x,n) returns power(x,n-1)*x
xn = xn-1*x so this is correct
© Janice Regan, CMPT 128,2007-2013
28
Another recursive example
 Now lets return to our discussion of quick
sort and see the application of recursion to
that algorithm
© Janice Regan, CMPT 128,2007-2013
29
Download