0% found this document useful (0 votes)
42 views

Recursion - Writing A Recursive Function - Recursion Rules

The document discusses recursion, including: 1) The key concepts of recursion including base cases, simplifying steps, and using functions to call themselves on smaller instances of a problem. 2) An example of the "lazy person's sort" recursive algorithm that breaks a sorting problem into smaller sorted sub-problems. 3) The two main rules for writing recursive functions: including a stopping condition and passing a smaller problem on each call. 4) A six step process for writing recursive functions, using calculating factorials as an example.

Uploaded by

Amna Yaqoob
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views

Recursion - Writing A Recursive Function - Recursion Rules

The document discusses recursion, including: 1) The key concepts of recursion including base cases, simplifying steps, and using functions to call themselves on smaller instances of a problem. 2) An example of the "lazy person's sort" recursive algorithm that breaks a sorting problem into smaller sorted sub-problems. 3) The two main rules for writing recursive functions: including a stopping condition and passing a smaller problem on each call. 4) A six step process for writing recursive functions, using calculating factorials as an example.

Uploaded by

Amna Yaqoob
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 32

1

Lecture #8
• Recursion
• Writing a recursive function
• Recursion Rules
2

Recursion

WONDERS WHY HE CAN’T GET A DATE


Recursion
Why should you care?
Recursion is one of the most difficult…
but powerful computer science topics.

Use it for things like…


Solving
AI for Games Cracking Codes
SuDoKu

And they love to ask you to write recursive


functions during job interviews.

So pay attention!
4

Idea Behind Problem


RecursionSolving
SolveAProblem(problem)

Just return
Is the problem trivially solved Yes
the answer
No
Break the problem into two
or more simpler sub-problems

SolveAProblem(sub-problem1)
Solve each sub-problem j SomeOtherFunction(sub-problem1)
...
bybycalling
callingsome
ourself!
other SolveAProblem(sub-problem )
SomeOtherFunction(sub-problemn)
n

function on the sub-problem j

Collect all the solution(s)


to the sub-problems

Use the sub-solutions to construct Return the


a solution to the complete problem solution
5

“The Lazy Person’s Sort”


Let’s design a new sorting algorithm,
called the “lazy person’s sort”…

The input to this sort


622
are a bunch of index 17395
14
cards with #s.

Lazy Person’s Sort:


Split the cards into two roughly-equal piles
Hand one pile to student A and ask them to sort it
Hand the other pile to student B and ask them to sort it
Take the two sorted piles and merge them into a single sorted pile

6 17 22 3 14 95
6

“The Lazy Person’s Sort”


99322
2774
61492
17

6 17 22 3 14 95

Lazy Person’s Sort:


Split the cards into two roughly-equal piles
Hand one pile to student A and ask them to sort it
Hand the other pile to student B and ask them to sort it
Take the two sorted piles and merge them into a single sorted pile
7

“The Lazy Person’s Sort”


99322
2774
61492
17

Lazy Person’s Sort:


Split the cards into two roughly-equal piles
Hand one pile to student A and ask
say them to Lazy
“do the sort it
Person’s Sort”
Hand the other pile to student B andsay “do
ask the to
them Lazy Person’s
sort it Sort”
Take the two sorted piles and merge them into a single sorted pile
8

“The Lazy Person’s Sort”


99322
2774
61492
17

Lazy Person’s
If you’re Sort:
handed just one card, then just give it right back.
Split the cards into two roughly-equal piles
nerdy student
Hand one pile to student Asay
A and askand ask
them
“do them
to
the sorttoit
Lazy sort it Sort”
Person’s
Hand the other pile to nerdy student B and ask say them
“do theto Lazy
sort Person’s
it Sort”
Take the two sorted piles and merge them into a single sorted pile
9

“The Lazy Person’s Sort”


void MergeSort(an array)
{
if (array’s size == 1)
Lazy return;
Person’s Sort: // array has just 1 item, all done!
If you’re handed
OtherSort
MergeSort( first just
half one card,);then
of array //just give it
process theright back.
1st half of the array
Split the cards
MergeSort(
OtherSort intohalf
second two of
roughly-equal piles
array); // process the 2nd half of the array
Hand one pile to person A and say “do the Lazy Person’s Sort”
Merge(the two array
Hand the other halves);
pile to person B and//saymerge theLazy
“do the two sorted
Person’shalves
Sort”
// nowthe
Take thetwo
complete
sortedarray is sorted
piles and merge them into a single sorted pile
}
The Lazy Person’s Sort (also known as Merge Sort) is a
perfect
When youexample
write aofrecursive
a recursive algorithm!
function…
Every time our MergeSort function is called, it breaks up its input
intoYour
two job is toparts
smaller figure outcalls
and howitself
the function
to solve can use
each itself
sub-part.
(on a subset of the problem) to get the complete problem solved.
It’s hard to believe it works!

When you Ok
add– the
but code
wouldtoyou agree
make it definitely
a function works you
call itself, if we
need to
have faith that thatchange
call willthe algorithm
work properlylike
(onthis?
the subset of data).
If we can rely upon OtherSort to somehow properly sort each sub-array,
It takes somethat
we agree timeourto udpated
learn to MergeSort
think in thiswill
way, but Correct?
work. once you
“get it,” you’ll be a programming Great!
10

The Two Rules of Recursion


RULE ONE:
Every recursive function must have a “stopping condition!” 

The Stopping Condition (aka Base Case):


Your recursive function must be able to solve the
simplest, most basic problem without using recursion.

Remember: A recursive function calls itself. 

Therefore, every recursive function must have some


mechanism to allow it to stop calling itself. 
11

The Two Rules of Recursion


RULE TWO:
Every recursive function must have a “simplifying step”.

Simplifying Step:
Every time a recursive function calls itself, it must pass
in a smaller sub-problem that ensures the algorithm will
eventually reach its stopping condition.

Remember: A recursive function must eventually reach its


stopping condition or it’ll run forever. 
12

Writing (Your Own) Recursive Functions: 6 Steps


What if we want to write our own recursive function?
Here’s a proven six-step method to help you!

Step #1:
Write the function header
Let’s use these steps
Step #2: to write a recursive
Define your magic function function to calculate
Step #3: factorials.
Add your base case code
Step #4: Recall, the definition of
Solve the problem w/the magic function fact(N) is:

Step #5: 1 for N = 0


Remove the magic N * fact (N-1) for N > 0
Step #6:
Validate your function
13

Example #1: Factorial


14

Step #1: Write the function header


Figure out what argument(s) your function will
take and what it needs to return (if anything).

First, a factorial function takes in an


integer as a parameter, e.g., factorial(6).
int fact(int n)
{
Second, the factorial computes (and
should return) an integer result. Let’s
add a return type of int.

And here’s how we’d call our factorial


function to solve a problem of size n…
}

So far, so good. Let’s go on to step #2. int main()


{
int n = 6, result;

result = fact( n );

}
15

Step #2: Define your magic function


Pretend that you are given a magic function that can compute a factorial.
It’s already been written for you and is guaranteed to work!
// provided
int for your use!
fact(int n)
For example, perhaps
It takes the same parameters as your {int magicfact(int x) { … }
magicfact looks
factorial function and returns the
like this?!?! int fact(int n)
same type of result/value. { // don’t worry about how your
int magicfact(int x) // function will actually work!
{
There’s only one catch! You are // we’ll figure that out later!!
forbiddenint f = 1;
from passing in a value of n
towhile
this (x > 1) function.
magic }
{
f *= use
So you can’t x; it to compute n!
x--; }
} use it to solve smaller
But you can
return f; int main()
problems, like (n-1)! or (n/2)!, etc. {
} int n = 6, result;
// use magicfact to solve subproblems
Show how you could use this magic result
result =
= magicfact(
magicfact( n-1
n ); );
function to compute (n-1)!.
}
16

Step #3: Add your base case Code


Determine your base case(s) and write the
code to handle them without recursion!
Our goal in this step is to identify the // provided
int for your use!
fact(int n)
simplest possible input(s) to our function… {int magicfact(int x) { … }

And then have our function process int fact(int n)


those input(s) without calling itself { // don’t worry about how your
//
if function
(n == 0) will actually work!
(i.e., just like a normal function would).
// we’ll figure
return 1; //that
baseout later!!
case
Ok, so what is the simplest factorial // Always consider all possible
we might be asked to compute? } // base cases and add checks
// for them before proceeding!
Well, the user could pass 0 into our function.
}
0!, by definition, is equal to 1.
Let’s add a check for this and handle it int main()
{
without using any recursion.
int n = 6, result;
// use magicfact to solve subproblems
In this example, this is the only base
result = magicfact( n-1 );
condition, but some problems may require
2 or 3 different checks. }
17
Step #4: Solve the problem using the magic function
Now try to figure out how to use the magic function in your
new function to help you solve the problem.
But computing the factorial of
It’s trivial to compute N, since
N-1 is not so easy.
we already know
Unfortunately, youits value!
can’t use the magic // provided for your use!
int fact(int n)
function to do all the work for you… {int magicfact(int
This is definitelyx)a {smaller
…}
So (it
there’s
can’t no need
solve to use our
problems of size n)
problem, perfect
int fact(int n) for our magic
magic function to help.
{ // don’tto
function worry
solveabout
for how
us! your
So let’s try to break our problem into //
if function
(n == 0) will actually work!
two Hopefully, we can
(or more) simpler agree and
sub-problems // we’ll figure
return 1; //that
baseout later!!
case
use our if
that magic
thisfunction
magic to solve those.
function int
int part1
result==n;
magicfact( n );
does what
Well, by it’s supposed
definition, N! = N * (N-1)! } int part2 =
to…
So it’s already split into two parts for us, & return result;
return part1 * part2;
each part is simpler than the original problem. }

Thenfigure
Let’s our out
new function
a way will of
to solve each int main()
work
thesecorrectly! {
sub-problems.
int n = 6, result;
// use magicfact to solve subproblems
Cool! Now we can combine the results result = magicfact( n-1 );
of our sub-problems to get the
overall result! }
18

Step #5: Remove the magic


int magicfact(int x)
{
return fact(x);
OK, so let’s see what this magic function really
} looks like!

Wait
But if our afunction
second! calls
Ouritself,
magicfact
what
function basically // provided for your use!
stops it from runningjust calls fact!
on forever? int fact(int n)
{int magicfact(int x) { … }

That
Right! Ourmeans
base that
case fact
code is really
ensures int fact(int n)
just calling itself! stops { // don’t worry about how your
that our function eventually //
calling itself! if function
(n == 0) will actually work!
// we’ll figure
return 1; //that
baseout later!!
case
The magicfact function hid this from
us, but that’s what’s really happening! int part1 = n;
} int part2 = magic fact( n-1 );
Let’s replace our call(s) to the magic
return part1 * part2;
function with calls directly to our }
own function.
int main()
{
int n = 6, result;
// use magicfact to solve subproblems
result = magicfact( n-1 );
}
19

Step #6: Validating our Function


You SHOULD do this step EVERY time your write a recursive function!

Start by testing your function with the simplest possible input.

Next test your function with incrementally more complex inputs.


(You can usually stop once you’ve validated at least one recursive call)
0
int fact(int n) Excellent! We’ve tested all of the base
{ 0 == 0 case(s) as well as validated a single
if (n == 0) level of recursion…
return 1 1;
We can be pretty certain our function
return n * fact(n-1); works now…
}
Good. This result is
01 Good. 0
correct. This
! resulttois 1.
is equal
int fact(int n)
correct too. 1! is equal to int main()
{ 1 ==
0 == 00 {
1 * 0!, aka 1 * 1, aka 1.
if (n == 0) cout << fact( 0 );
return 1; cout << fact( 1 );
return 1n * fact(n-1); }
0
}
20

Factorial Trace-through
int fact(int n) n 0
{ 0 == 0
if (n == 0)
1
return (1);
return(n * fact(n-1));
}
int fact(int n) n 1
{ 1 == 0
if (n == 0)
return (1);
return(n * 1*1=1
1 0
fact(n-1));
} result 2
int fact(int n) n 2 int main()
{ 2 == 0 {
if (n == 0)
int result;
return (1);
2
result = fact(2);
return(n * 2*1=2
1
2
fact(n-1)); cout << result;
} }
21

Example #2: Recursion on an Array


For our next example, let’s learn how to use recursion
to get the sum of all the items in an array.

arr 10 20 70 14 39
0 n-1
22
You could also have written:
Step #1: Write the function header int *arr
It’s the same thing!
Figure out what argument(s) your
function will take and what it needs
to return (if anything).
int sumArr(int arr[ ], int n)
To sum up all of the items in an array, we {

need a pointer to the array and its size.

Our function will return the total sum


of items in the array, so we can make
the return type an int.
}

And here’s how we’d call our int main()


array-summer function to {

solve a problem of size n… const int n = 5;


int arr[n] = { 10, 100, 42, 72, 16}, s;

So far, so good. s = sumArr( arr , n); // whole array

Let’s go on to step #2.

}
23

Step #2: Define your magic function


Pretend that you are given a // provided for your use!
magic function that sums upSince we used int
the values n/2magicsumArr(int
to specify the #arr[],
of items
int x) { … }
in
in an array and returns the result… the first half of the array.
int sumArr(int arr[ ], int n)
There’s only one catch! You areThere are
{ n – n/2 items in the
second half of the array.
forbidden from passing in an array
with n elements to this function. If you
e.g., if n=5, recall
then from
n/2 == then-n/2
2 and pointer
== lecture,
3
this is called “pointer arithmetic.”
So you can’t use it to sum up an
This means “give me a pointer to the
entire array (one with all n items)…
item
} in the array that is 1 element
from the array’s start,” e.g., &arr[1]
But you can use it to sum up smaller int main()
{
arrays (e.g., with n-1 elements)! const int n = 5;
int arr[n] = { 10, 100, 42, 72, 16}, s;
Finally
Show
Now
Now show
show show
howhow
how tohow
use
to
to to
use
use use
thethe
the the
magic
magic
magic s = magicsumArr( arr, n-1 ); // first n-1
magic function
function
function
function to to
to
sumsumto
sum
thesum
the
the thehalf
first
last
first last
n-1of
n-1 s = magicsumArr( arr+1,
arr
arr+1,
, n n-1
); ); // last n-1
half the
items ofofthe
thearray.
array.array.
s = magicsumArr( arr, n/2 ); // sums 1 half
st

s = magicsumArr( arr+n/2, n – n/2 ); // 2 nd

}
24

Step #3: Add your base case Code


Determine your base case(s) and // provided for your use!
write the code to handle them int magicsumArr(int arr[], int x) { … }
without recursion!
int sumArr(int arr[ ], int n)
Ok, so what is the smallest array that {
might be passed into our function? if (n == 0) return 0;
if (n == 1) return arr[0];
Well, someone could pass in a totally
empty array of size n = 0. What
should we do in that case?

Well, what’s the sum of an empty }


array? Obviously it’s zero. Let’s add
the code to deal with this case. int main()
{

Do we have any other base cases? const int n = 5;


For example, what if the user passes int arr[n] = { 10, 100, 42, 72, 16}, s;
in an array with just one element? s = magicsumArr( arr, n-1 ); // first n-1
s = magicsumArr( arr+1, n-1 ); // last n-1
Let’s see what that would look like…
s = magicsumArr( arr, n/2 ); // sums 1 half
st

Good. Let’s keep both of those. s = magicsumArr( arr+n/2, n – n/2 ); // 2 nd

}
25
Step #4: Solve the problem using the magic function
Now try to figure out how to use the // provided for your use!
magic function in your new function to int magicsumArr(int arr[], int x) { … }
help you solve the problem.
int sumArr(int arr[ ], int n)
Unfortunately, you can’t use the magic {
function to do all the work for you… if (n == 0) return 0;
(it can’t solve problems of size n)
if (n == 1) return arr[0];
So let’s try to break our problem into two int s = magicsumArr( arr, n );
(or more) simpler sub-problems and use our
magic function to solve those. return s;
}

int main()
{
const int n = 5;
int arr[n] = { 10, 100, 42, 72, 16}, s;
s = magicsumArr( arr, n-1 ); // first n-1
s = magicsumArr( arr+1, n-1 ); // last n-1
s = magicsumArr( arr, n/2 ); // sums 1 half
st

s = magicsumArr( arr+n/2, n – n/2 ); // 2 nd

}
26
Step #4: Solve the problem using the magic function
Now try to figure out how to use the // provided for your use!
magic function in your new function to int magicsumArr(int arr[], int x) { … }
help you solve the problem.
int sumArr(int arr[ ], int n)
Unfortunately, you can’t use the magic {
Hopefully,
function to dowe all can agree
the work for you… if (n == 0) return 0;
(itif
that can’t
the solve problems
magic of size n)
function if (n == 1) return arr[0];
does
So what
let’s try it’s supposed
to break our problem into two int front =
(or more) simplerto…sub-problems and use our int total = front + arr[n-1];
magic function to solve those.
return total;
}
Then our new function will
Strategy #1: Front to back int main()
work correctly! {
Your function uses the magic function
const int n = 5;
to process the first n-1 elements of
int arr[n] = { 10, 100, 42, 72, 16}, s;
the array, ignoring the last element.
s = magicsumArr( arr, n-1 ); // first n-1
Once it gets the result from the magic
function, it combines it with the last s = magicsumArr( arr+1, n-1 ); // last n-1
element in the array. s = magicsumArr( arr, n/2 ); // sums 1 half
st

s = magicsumArr( arr+n/2, n – n/2 ); // 2 nd

It then returns the full result. }


27
Step #4: Solve the problem using the magic function
Now try to figure out how to use the // provided for your use!
magic function in your new function to int magicsumArr(int arr[], int x) { … }
help you solve the problem.
int sumArr(int arr[ ], int n)
Unfortunately, you can’t use the magic {
Hopefully,
function to dowe all can agree
the work for you… if (n == 0) return 0;
(itif
that can’t
the solve problems
magic of size n)
function if (n == 1) return arr[0];
does
So what
let’s try it’s supposed
to break our problem into two int rear =
(or more) simplerto…sub-problems and use our int total = arr[0] + rear;
magic function to solve those.
return total;
}
Then our new function will
Strategy #2: Back to front int main()
work correctly! {
Your function uses the magic function const int n = 5;
to process the last n-1 elements of the int arr[n] = { 10, 100, 42, 72, 16}, s;
array, ignoring the first element.
s = magicsumArr( arr, n-1 ); // first n-1
Once it gets the result from the magic
s = magicsumArr( arr+1, n-1 ); // last n-1
function, it combines it with the first
element in the array. s = magicsumArr( arr, n/2 ); // sums 1 half
st

s = magicsumArr( arr+n/2, n – n/2 ); // 2 nd

It then returns the full result. }


28
Step #4: Solve the problem using the magic function
Now try to figure out how to use the // provided for your use!
magic function in your new function to int magicsumArr(int arr[], int x) { … }
help you solve the problem.
int sumArr(int arr[ ], int n)
Unfortunately, you can’t use the magic {
Hopefully,
function to dowe all can agree
the work for you… if (n == 0) return 0;
(itif
that can’t
the solve problems
magic of size n)
function if (n == 1) return arr[0];
does
So what
let’s try it’s supposed
to break our problem into two int first =
(or more) simplerto…sub-problems and use our int last =
magic function to solve those.
return first + last;
}
Then our new function will
Strategy #3: Divide and conquer int main()
work correctly! {
Your function uses the magic function const int n = 5;
to process the first half of the array. int arr[n] = { 10, 100, 42, 72, 16}, s;
Your function uses the magic function s = magicsumArr( arr, n-1 ); // first n-1
to process the last half of the array.
s = magicsumArr( arr+1, n-1 ); // last n-1
Once it gets both results, it combines s = magicsumArr( arr, n/2 ); // sums 1 half
st

them and returns the full result. s = magicsumArr( arr+n/2, n – n/2 ); // 2 nd

}
29
int magicsumArr(int arr[], int x)
{ Step #5: Remove the magic
return sumArr(arr,x);
But
} if our function calls itself, what // provided for your use!
stops it from running on forever? int magicsumArr(int arr[], int x) { … }
OK, so let’s see what this magic
Right!function
Our basereally
case looks like!
code ensures int sumArr(int arr[ ], int n)
{
that
Waitour functionOur
a second! eventually stops
magicsumArr if (n == 0) return 0;
calling
function just itself!
calls sumArr! if (n == 1) return arr[0];
This means that sumArr is really int first = magic sumArr( arr, n/2 );
just calling itself! int scnd = magic sumArr( arr+n/2,
n – n/2 );
The magic function hid this from us, return first + scnd;
}
but that’s what’s really happening!
int main()
{
OK, well in that case, let’s replace const int n = 5;
our calls to the magic function with int arr[n] = { 10, 100, 42, 72, 16}, s;
calls directly to our own function.
s = magicsumArr( arr, n-1 ); // first n-1
Will that work? Yup! s = magicsumArr( arr+1, n-1 ); // last n-1
s = magicsumArr( arr, n/2 ); // sums 1 half
Woohoo! We’ve just created our
st

second recursive function! s = magicsumArr( arr+n/2, n – n/2 ); // 2 nd

}
30

Step #6: Validating our Function

As before, make sure to test your function with


at least one input that exercises the base case…

and one input that causes a recursive call.

int sumArr(int arr[], int n)


{
if (n == 0) return 0;
if (n == 1) return arr[0]; int main()
int first = sumArr( arr, n/2 ); {
int scnd = sumArr( arr+n/2, n-n/2); int arr[2] = { 10, 20 };
return first + scnd;
}
cout << sumArr( arr, 0 );

cout << sumArr( arr, 2 );


}
31

Array-summer Trace-through
int sumArr(int arr[], int n)
{
if (n == 0) return 0; 42
20
if (n == 1) return arr[0];
int first = sumArr( arr, n/2 );
int sumArr(int arr[], int n) int scnd = sumArr( arr+n/2, n-n/2);
{
if (n == 0) return 0; 10 return first + scnd;
}
if (n == 1) return arr[0];
20 1
n/2 );1
int first = sumArr( arr,42
int scnd = sumArr( arr+n/2, n-n/2);
return first62
+ scnd;
}

int main()
int sumArr(int arr[], int n) {
{
const int n = 3;
if (n == 0) return 0;
int nums[n] = { 10, 20, 42 };
if (n == 1) return arr[0];
10 1
int first = sumArr( 20arr, 42
n/2 ); 2 nums 10 20 42
3
int scnd = sumArr( arr+n/2, n-n/2);
return first72+ scnd; cout << sumArr( nums , n );
} }
32

Your Turn: Recursion Challenge


Write a recursive function called printArr that prints
out an array of integers in reverse from bottom to top.

Step #1:
Write the function header
Step #2:
Define your magic function
Step #3:
Add your base case code
Step #4:
Solve the problem w/the magic function
Step #5:
Remove the magic
Step #6:
Validate your function
Solve this problem and Get Bonus marks in mid term

You might also like