0% found this document useful (0 votes)
9 views33 pages

lec15-recursion

Uploaded by

Mamat Rahmat
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views33 pages

lec15-recursion

Uploaded by

Mamat Rahmat
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

CSCI1540

Fundamental Computing
with C++
Recursion

Fall, 2024
What is Recursion?

“In order to understand recursion,


you must first understand recursion”

2
Basic Elements of Recursion
• A recursive function is a function that contains a call
to itself either directly or indirectly
• It can be considered an advanced form of control flow,
an alternative to iteration/repetition
int foo(…) {

… foo(…) …; // Calls itself

}

• Recursion usually leads to more elegant and


simpler solutions, but incurs larger memory and
time overhead
3
Basic Elements of Recursion
• Writing recursive programs requires “recursive
thinking style” and “recursive problem-solving
skills”, which can only be acquired through practice
and experience

• An important recursive problem-solving skill is


divide-and-conquer
• Divide the problem into smaller pieces
• Tackle each sub-task either directly or by recursion
• Combine the solutions of the parts to form the solution
of the whole

4
Counting Down (Iterative):
Example
• Suppose we need to write a function that counts
down from 𝑁 (> 0) to 1, printing 𝑁, … , 2,1 in turn
An iterative 1 #include <iostream>
solution: 2 using namespace std;
3
4 void countDown(int n) {
5 for (int i = n; i > 0; i--)
6 cout << i << endl;
7 }
8 5
9 int main() { 4
10 countDown(5); 3
11 return 0; 2
12 } 1
5
Counting Down (Recursion):
Example
• A recursive solution:
• If 𝑁 < 1, then do nothing and done!
• If 𝑁 ≥ 1, then the solution consists of two sub-tasks:
i. Print 𝑁; and
ii. Count down from 𝑁 − 1 to 1

1 void countDown(int n) { Test


2
3 if (n >= 1) {
4 cout << n << endl;
5 countdown( n - 1 );
6 } // else nothing
7 Recursive call
8 }
Base case (do nothing) 6
Basic Elements of Recursion
• Any recursive function will include the following
three basic elements:

• A test to stop or continue the recursion

• A base case that terminates the recursion

• A recursive call that continues the recursion

7
Tracing Recursion
void countDown(int n) {
if (n >= 1) {
int main() { cout << n << endl;
countDown(5); countdown( n - 1 );
return 0; } // else nothing
} }
cout << 5 << endl;
countdown( 4 );
cout << 4 << endl;
countdown( 3 );
cout << 3 << endl;
countdown( 2 );
5 cout << 2 << endl;
4 countdown( 1 );
3 cout << 1 << endl;
2 countdown( 0 );
1 (Do nothing!) 8
Iteration vs Recursion
Iteration Recursion
(while, do-while, for)
• Maintains and modifies loop • Keeps producing simpler
variables in a termination versions of the original
condition problem
• Until the condition is met • Until some base cases are
reached
void countDown(int n) { void countDown(int n) {
for (int i = n; i > 0; i--) if (n >= 1) {
cout << i << endl; cout << n << endl;
} countdown(n - 1);
} // else nothing
}
9
Summation 1 + 2 + ⋯ + 𝑛:
Example
𝑛
• To compute:
෍𝑖 = 1 + 2 + 3 + ⋯+ 𝑛
𝑖=1
= 1 + 2 + ⋯+ 𝑛 − 1 +𝑛
𝑛−1

(Assume 𝑛 > 0) =𝑛+ ෍𝑖


𝑖=1

1 int summation(int n) { Test


2 if (n == 1)
3 return 1; Base case
4 else
5 return n + summation( n - 1 );
6 }
Recursive call 10
Summation 1 + 2 + ⋯ + 𝑛:
Example
1 int summation(int n) {
2 if (n == 1)
3 return 1;
4 else
5 return n + summation( n - 1 );
6 }
7
8 int main() {
9 int n;
10 cout << "Enter n: "; Enter n: 5↵
11 cin >> n; Sum = 15
12 cout << "Sum = " << summation(n) << endl;
13 return 0; Enter n: 14↵
14 } Sum = 105

11
Summation 1 + 2 + ⋯ + 𝑛:
Example
summation(5)
Recursive

→ 5 + summation(4)
calls

→ 5 + (4 + summation(3))
→ 5 + (4 + (3 + summation(2)))
→ 5 + (4 + (3 + (2 + summation(1))))
→ 5 + (4 + (3 + (2 + 1)))
Combining
solution

→ 5 + (4 + (3 + 3))
→ 5 + (4 + 6)
int summation(int n) {
→ 5 + 10 if (n == 1)
→ 15 return 1;
else
return n + summation(n - 1);
} 12
String Reversal: Example
• rev("abcde") → “edcba”
• rev("CSCI1357") → “7531ICSC”
• Reversing an empty string gets an empty string
• Reversing a non-empty string gets…
1 string rev(string s) { rev("abcde")
2 if (s == "") → rev("bcde") + 'a'
3 return "";
4 else
5 return rev(s.substr(1)) + s.at(0);
6 }

The substring of s substr(…) is a member


from index 1 till end function of the string class 13
Exercise
• Write a recursive function (no loop inside)
int count(string s, char ch);
that counts the number of times that character ch
appears in string s
• E.g.:
count("Computer Science", 'e') → 3
count("Computer Science", 'a') → 0
if (…) // Base case
• You need > 1 recursive case

else if (…) // Recur. case 1

else // Recur. case 2
… 14
Tower of Hanoi: Example
• The Tower of Hanoi is a puzzle consisting of 3 pegs
and 𝑁 disks of different sizes

𝑁 disks 𝑁=4
Peg 1 Peg 2 Peg 3

15
Tower of Hanoi
• The goal is to move the 𝑁 disks from peg 1 to peg 3
satisfying the following constraints:
• Only one disk can be moved at a time
• A larger disk cannot be on top of a smaller disk

(Move
disks)

Peg 1 Peg 2 Peg 3 Peg 1 Peg 2 Peg 3


Start Goal
16
Tower of Hanoi: Recursion
• Solution for 𝑁 = 1 is trivial: (Base case)

• Move the (only) disk to the required destination

Peg 1 Peg 2 Peg 3

17
Tower of Hanoi: Recursion
• Solution for 𝑁 > 1: (Recursive case)

• “Step” 1: Move the top 𝑁 − 1 disks from peg 1 to peg 2

• Step 2: Move the remaining disk from peg 1 to peg 3

• “Step” 3: Move the 𝑁 − 1 disks from peg 2 to peg 3

“Step” 1 “Step” 3

Step 2

Peg 1 Peg 2 Peg 3 18


Tower of Hanoi Solution
Recursion
“Step” 1
Peg 1 Peg 2 Peg 3 Peg 1 Peg 2 Peg 3
Move 𝑁 − 1 disks
from Peg 1 to Peg 2

Move one

Step 2
disk from Peg
1 to Peg 3
Recursion
Move 𝑁 − 1 disks
from Peg 2 to Peg 3

“Step” 3
Peg 1 Peg 2 Peg 3 Peg 1 Peg 2 Peg 3
19
Tower of Hanoi Solution Original peg
Destination peg
1 void hanoi(int n, int from, int to, int buffer) {
2 if ( n == 1 ) { “Middle” peg
3 cout << from << " --> " << to << endl;
4 } else {
5 hanoi(n - 1, from, buffer, to); // "Step" 1
6 cout << from << " --> " << to << endl; // Step 2
7 hanoi(n - 1, buffer, to, from); // "Step" 3
8 }
9 }
10
11 int main() {
12 int n;
13 cout << "Enter n: ";
14 cin >> n;
15 hanoi(n, 1, 3, 2); // From peg 1 to 3 via 2
16 return 0;
17 } 20
Enter n: 5↵
1 --> 3
1 --> 2
3 --> 2
Tower of Hanoi Solution 1 -->
2 -->
3
1
2 --> 3
1 --> 3
1 --> 2
Enter n: 1↵ Enter n: 4↵ 3 --> 2
1 --> 3 1 --> 2 3 --> 1
2 --> 1
1 --> 3 3 --> 2
Enter n: 2↵ 2 --> 3 1 --> 3
1 --> 2 1 --> 2 1 --> 2
1 --> 3 3 --> 1 3 --> 2
2 --> 3 1 --> 3
3 --> 2 2 --> 1
1 --> 2 2 --> 3
Enter n: 3↵ 1 --> 3
1 --> 3 2 --> 1
1 --> 3
2 --> 3 3 --> 2
1 --> 2
2 --> 1 3 --> 1
3 --> 2 2 --> 1
3 --> 1
1 --> 3 2 --> 3
2 --> 3 1 --> 3
2 --> 1
1 --> 2 1 --> 2
2 --> 3 3 --> 2
1 --> 3
1 --> 3 1 --> 3
2 --> 3 2 --> 1
2 --> 3
1 --> 3 21
Tower of Hanoi: 𝑁 = 3
void hanoi(int n, int from, int to, int buffer) { Enter n: 3↵
if ( n == 1 ) { 1 --> 3
cout << from << " --> " << to << endl; 1 --> 2
} else { 3 --> 2
hanoi(n - 1, from, buffer, to); // "Step" 1 1 --> 3
cout << from << " --> " << to << endl; // Step 2 2 --> 1
hanoi(n - 1, buffer, to, from); // "Step" 3 2 --> 3
} 1 --> 3
}
hanoi(3, 1, 3, 2); (3 disks, Peg 1 to 3 via 2)

hanoi(2, 1, 2, 3); hanoi(1, 1, 3, 2); cout << "1 --> 3\n";


cout << "1 --> 3\n"; cout << "1 --> 2\n";
hanoi(2, 2, 3, 1); hanoi(1, 3, 2, 1); cout << "3 --> 2\n";

hanoi(1, 2, 1, 3); cout << "2 --> 1\n";


cout << "2 --> 3\n";
hanoi(1, 1, 3, 2); cout << "1 --> 3\n";
22
Tower of Hanoi: 𝑁 = 3

Enter n: 3↵
Peg 1 Peg 2 Peg 3 1 --> 3
1 --> 2
3 --> 2
1 --> 3
1→3 2 --> 1
Peg 1 Peg 2 Peg 3 2 --> 3
1 --> 3

1→2
Peg 1 Peg 2 Peg 3

3→2
Peg 1 Peg 2 Peg 3 23
Tower of Hanoi: 𝑁 = 3

1→3 Enter n: 3↵
Peg 1 Peg 2 Peg 3 1 --> 3
1 --> 2
3 --> 2
1 --> 3
2→1 2 --> 1
Peg 1 Peg 2 Peg 3 2 --> 3
1 --> 3

2→3
Peg 1 Peg 2 Peg 3

1→3 Done!
Peg 1 Peg 2 Peg 3 24
Tower of Hanoi: 𝑁 = 4
hanoi(4, 1, 3, 2); (4 disks, Peg 1 to 3 via 2)
Enter n: 4↵
1 --> 2 hanoi(1, 1, 2, 3);
1 --> 3 hanoi(2, 1, 3, 2);
2 --> 3 hanoi(1, 2, 3, 1);
1 --> 2 hanoi(3, 1, 2, 3);
3 --> 1 hanoi(1, 3, 1, 2);
3 --> 2 hanoi(2, 3, 2, 1);
1 --> 2 hanoi(1, 1, 2, 3);
1 --> 3
2 --> 3 hanoi(1, 2, 3, 1);
2 --> 1 hanoi(2, 2, 1, 3);
3 --> 1 hanoi(1, 3, 1, 2);
2 --> 3 hanoi(3, 2, 3, 1);
1 --> 2 hanoi(1, 1, 2, 3);
1 --> 3 hanoi(2, 1, 3, 2);
2 --> 3 hanoi(1, 2, 3, 1);
25
Pitfall of Recursion
• Recursive function calls incur both time and
memory overheads since a runtime stack must be
maintained for the function calls

• Space to store the growing runtime stack

• Time to add and remove information from the runtime


stack

26
Tower of Hanoi
• It has been proved that a Tower of Hanoi of 𝑁 disks
can be solved in 2𝑁 − 1 moves

• 3 disks → 7 moves
• 4 disks → 15 moves

• 10 disks → 1,023 moves

• 64 disks → 18,446,744,073,709,551,615 moves

27
Fibonacci Series: Example
• The Fibonacci Series

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …

• Begins with 0 and 1

• Each subsequent Fibonacci number is the sum of the


previous two Fibonacci numbers in the series

28
Fibonacci Series: Recursion
0 𝑛=0
𝑓𝑖𝑏(𝑛) = ቐ 1 𝑛=1
𝑓𝑖𝑏 𝑛 − 2 + 𝑓𝑖𝑏(𝑛 − 1) 𝑛≥2

• 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, …


1 long long fib( int n ) {
2 if (n == 0)
3 return 0;
4 else if (n == 1)
5 return 1;
6 else
7 return fib(n - 2) + fib(n - 1);
8 }
29
Excessive Repetition
• Carelessly designed recursive functions can lead to
very inefficient and unacceptable solutions
fib(5)
Recursive Fibonacci ends up
repeating the same
fib(3) + fib(4)
computation numerous times!

fib(1) + fib(2) fib(2) + fib(3)

fib(0) + fib(1) fib(0) + fib(1) fib(1) + fib(2)

fib(0) + fib(1)
30
Non-Recursive Fibonacci (Iteration)
1 long long fib( int n ) {
2 long long fibN, fibN1, fibN2;
3
4 if (n == 0) {
5 return 0;
6 } else if (n == 1) {
7 return 1;
8 } else {
9 fibN1 = 0;
10 fibN2 = 1;
11 for (int cnt = 2; cnt <= n; cnt++) {
12 fibN = fibN1 + fibN2; // Get the next fib num
13 fibN1 = fibN2;
14 fibN2 = fibN;
15 }
16 return fibN;
17 }
18 } 31
When (Not) to Use Recursion?
• In general, use recursion if:

• A recursive solution is natural and easy to understand

• A recursive solution does not result in excessive


duplicate computation

• The equivalent iterative solution is too complex

No really clear cut guidelines!!!

32
Summary
• Recursive functions have the following elements
• Different cases are governed by selection (if-else)

• One or more base cases have simple and non-recursive


solution

• Recursion is used to reduce the problem to cases that


are simpler and closer to the base case

• Recursion continues until a base case is reached and


answers of the parts are returned and combined to form
the answer of the whole

Next: Dynamic Memory Management 33

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy