4 - Recursion - V2
4 - Recursion - V2
4 - Recursion - V2
rec2(x-1);
printf("%d ", x); //this line (including the value of x) is kept in the stack for each call of rec(x-1) in the above line
}
printf("%d ", x); //prints first then recursion printf("\nCalling rec2: ");
rec1(x-1); rec2(10);
} }
Output:
Calling rec1: 10 9 8 7 6 5 4 3 2 1
Calling rec2: 1 2 3 4 5 6 7 8 9 10
Explaining Example 1
• Can’t you print the same numbers using a
loop?
Function rec1:
for(i=10; i>0; i--)
printf(“%d” , i);
Function rec2:
for(i=1; i<=10; i++)
printf(“%d” , i);
Analyze rec1 of Example 1
void rec1(int x)
{
if (x==0)
return; //breaking condition
while (exponent != 0)
{
result *= base;
--exponent;
}
return result;
}
if ( exponent == 0 )
return 1;
else
return (base*Power(base, exponent-1));
}
return sum;
}
Example using construct 1
• Let’s write the recursive solution of the example:
• Step 1: We need to solve this problem is such a way that part of the
solution is a sub-problem of the exact same nature.
• Let f(n) denote the value 1+2+3+...+n
• Using our usual iterative logic, we have:
f(n) = 1 + (2 + 3 + ... + n)
• But, 2+3+... + n IS NOT a sub-problem of the form 1+2+...+n.
• But, let’s try this:
f(n) = 1 + 2 + ... + n = n + (1 + 2 + ... + (n-1))
f(10) = 1 + 2 + ... + 10 = 10 + (1 + 2 + ... + 9) = 10 + f(9)
• So, here we have gotten the expression 1 + 2 + ... + (n-1) which IS a
sub-problem we were looking for.
• Hence, we have
f(n) = 1 + 2 + ... + n = n + (1 + 2 + ... + (n-1)) = n + f(n-1)
Example using construct 1
• If we look at the construct 1, the first thing we need to determine is
a terminating condition.
– We know that f(0) = 0, so our terminating condition can be n=0.
• Furthermore, our recursive call needs to be returning an expression
for f(n) in terms of f(k), for some k<n.
– In this case, we just found that f(n) = n + f(n-1). So, now we can
write our function: can you write it?
if ( n == 0 )
return 0;
else
return (n + Triangle_Number(n-1));
}
Two Other Classic Examples that Use Construct #1
• For positive integers n, n! (read, “n factorial”), is defined as follows:
n! = 1x2x3x4x…xn
• What is a factorial?
– 4! = 4 * 3 * 2 * 1 = 24
– In general, we can say:
– n! = n * (n-1) * (n-2) * … * 2 * 1
• Also, 0! = 1(just accept it!)
• Mathematically, factorial is already defined recursively (Note that each factorial is
related to a factorial of the next smaller integer)
• 4! = 4*3*2*1 = 4 * (4-1)! = 4 * (3!)
• Another example:
– 10! = 10*9*8*7*6*5*4*3*2*1
– 10! = 10 * (9!)
• So:
– n! = n*(n-1)!
– What would be the stopping condition?
– We let 0! = 1;
• Why don’t you write the recursive function?
Two Other Classic Examples that Use Construct #1
• So, the recursive code for factorial would look like this:
#include <stdio.h>
void Fact(int n);
int main(void)
{
int factorial = Fact(10);
printf(“%d\n”, factorial);
return 0;
}
if (n <= 1)
return n;
else
return fib(n-1) + fib(n-2);
}
Illustration of the Fibonacci recursion process
using recursion tree
Example using construct 2
Construct 2
if (!(terminating condition) ) {
Take a step closer to terminating condition
Call function RECURSIVELY on smaller subproblem
}
• Let’s write a function to generate TIP chart:
• Write a function that takes in the lowest dollar value and highest dollar value on
the chart. You know the TIP rate. The method header would look like the:
// The function prints out a chart with the appropriate tips
// for meals ranging from first_val to last_val number of
// dollars, for every whole dollar amount. Both parameters
// must be positive integers.
void Tip_Chart (int first_val, int last_val)
• Now, let’s consider writing this function recursively.
• First, we need to determine a terminating condition.
– if the lowest dollar amount is greater than the highest dollar amount, then the
chart is empty and we are done.
• Next, we need to figure out how to break down our task into two steps: one that
does part of the job, and secondly a recursive step.
Example using construct 2
• Tip Chart:
• What would be the first print out and what is next?
– It is clear that the first value we have to print of the chart is associated with
the lowest dollar value, since that must appear on the chart first.
– Printing out this line of the tip chart can be the part of the job we
accomplish.
• Now, are we left with a sub-problem of the same nature?
– Yes! We simply now need to print a tip chart from the lowest dollar value+1
to the highest dollar value.
Example using construct 2
#define TIP_RATE 0.15
// Pre-condition: Both parameters are integers with the first one being less than or equal to the
second one.
// Post-condition: A tip chart will be printed out, with a row for each dollar amount ranging in
between the value of the two parameters.
void Tip_Chart (int first_val, int last_val)
{
// Solve the problem recursively: print the last character, then reverse
// the substring without that last character.
else {
printf("%c", string[n-1]);
print_reverse(string, n-1);
}
}
Solving using construct 2
// recursive function
int lucas(int n)
{
// Base cases
if (n == 1)
return 1;
else if (n == 2)
return 3;
else
return lucas(n - 1) + lucas(n - 2);
}
// Driver Code
int main()
{
int n = 9;
printf("%d", lucas(n));
return 0;
}
Try this
• How can you use recursion to convert and
print Decimal to Binary?
• Remember the steps: division and reminder
technique.
• The reminders should be printed from bottom
to top.
• Next slide is copied from Number system slide
to remind you about the steps
• Converting from base 10 to a new base
(division- remainder technique)
11710 = ?2
Step 1 117 / 2 58 1
Step 2 58 / 2 29 0
Step 3 29/ 2 14 1
Step 4 14 / 2 7 0
Step 5 7/2 3 1
Step 6 3/2 1 1
Read reverse order 11101012
void dectobin(int n) {
if (n < 2)
printf("%d", n);
else {
dectobin(n/2);
printf("%d", n%2);
}
}
Towers of Hanoi
• Problem:
• we have:
• three rods ( or tower)
• n disks in the left most tower. The disks are arranged with
the largest diameter disks at the bottom
• Some monk has the daunting task of moving disks from one
tower to another tower
– Often defined as moving from Tower #1 to Tower #3
• Tower #2 is just an intermediate pole
• Input : 3
Output :
Disk 1 moved from A to C
Disk 2 moved from A to B The pattern here is :
Disk 1 moved from C to B Shift 'n-1' disks from 'A' to 'B'.
Disk 3 moved from A to C Shift last disk from 'A' to 'C'.
Shift 'n-1' disks from 'B' to 'C'.
Disk 1 moved from B to A
Disk 2 moved from B to C
Disk 1 moved from A to C
Towers of Hanoi
#include <stdio.h>
int main()
{
int n = 4; // Number of disks
towerOfHanoi(n, 'A', 'C', 'B'); // A, B and C are names of rods
return 0;
}
Output:
Move disk 1 from rod A to rod B
Move disk 2 from rod A to rod C
Move disk 1 from rod B to rod C
Towers of Hanoi
Move disk 3 from rod A to rod B
Move disk 1 from rod C to rod A For n disks, total 2n – 1 moves are required.
Move disk 2 from rod C to rod B
Move disk 1 from rod A to rod B eg: For 4 disks 24 – 1 = 15 moves are required.
Move disk 4 from rod A to rod C
Move disk 1 from rod B to rod C For n disks, total 2n-1 function calls are made.
Move disk 2 from rod B to rod A
Move disk 1 from rod C to rod A eg: For 4 disks 24-1 = 8 function calls are made.
Move disk 3 from rod B to rod C
Move disk 1 from rod A to rod B
Move disk 2 from rod A to rod C
Move disk 1 from rod B to rod C
Illustration of the
recursion
Fast Exponent
int Power(int base, int exponent) {
if ( exponent == 0 )
return 1;
else
return (base*Power(base, exponent-1));
}
• Our recursive power function works just fine
• But, it becomes VERY slow for large exponents
– If the exponent was 10,000, that would be 9,999
multiplications!
• How can we do better?
– Rememer the laws of exponents:
• 28 = 24 * 24
• Now 24 = 22 * 22
• And 22 = 2 * (2)
– So: 2*(2) = 4, 4*(4) = 16, 16*(16) = 256 = 28
– So we’ve calculated 28 using only three multiplications
– MUCH better than 7 multiplications
Fast Exponent
• So, we see that bn = bn/2 * bn/2
• It will be log n number of multiplication (much better than n
multiplication)
• But can you guess what problem we have here: bn = bn/2 * bn/2
• It works when n is even. How about if n is not even?
• See: 29= 24*24*2
• So, we need to handle this case. We can say:
int main()
{
printf("%d", powerB(2,5));
return 0;
}
Let us try to find the result of f(4) for
the following recursive function using
recursion tree
int f(int n)
{
int ans;
int i;
if(n<3)
return n;
ans = f(n/2);
for(i=0; i<n; i++)
ans += f(i);
return ans;
}
int f(int n)
{
int ans;
int i;
if(n<3)
return n;
ans = f(n/2);
for(i=0; i<n; i++)
ans += f(i);
return ans;
}
More Recursion: Permutations
• The permutation problem is as follows:
• Given a list of items,
– list all the possible orderings of those items.
– The items can be numbers or letters or other object
• For example: all the permutations of 0,1,2:
• 0, 1, 2
• 0, 2, 1
• 1, 0, 2
• 1, 2, 0
• 2, 0, 1
• 2, 1, 0.
• Another example: All the permutations of the letters CAT:
CAT ACT TAC
CTA ATC TCA
• ExchangeCharacters function:
– This function will take in the string (str) and it will swap
two characters within that string.
– The character at index k will swap with the one at index j
// Pre-condition: str is a valid C String and i and j are valid indexes to that
string.
// Post-condition: The characters at index i and j will be swapped in str.
void ExchangeCharacters(char str[], int i, int j) {
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
Permutations
for (j=k; j<strlen(str); j++) {
ExchangeCharacters(str, k, j);
RecursivePermute(str, k+1);
ExchangeCharacters(str, j, k);
}
• ExchangeCharacters function:
– Remember: We need to find all permutations
with C as the first character, A as the first, and
with T as the first (for “CAT”)
– The ExchangeCharacters function swaps the two
characters at the indices passed in.
– We then recursively call the permute function
– Then we swap the characters back to their spots.
Permutations
void RecursivePermute(char str[], int k) {
int j;
// Base-case: Since all letters are fixed, we can ONLY print what's stored in str.
if (k == strlen(str))
printf("%s\n", str);
else {
// Loop through each possible starting letter for index k, the first index for which we have a choice.
for (j=k; j<strlen(str); j++) {
// Place the character stored in index j in location k.
ExchangeCharacters(str, k, j);
// Print out all of the permutations with that character just chosen above fixed.
RecursivePermute(str, k+1);
// Put the original character that used to be there back in its place.
ExchangeCharacters(str, j, k);
}
}
}
Permutation
void RecursivePermute(char str[], int k) {
int j;
// Base-case: Since all letters are fixed, we can ONLY print what's stored in str.
if (k == strlen(str))
printf("%s\n", str);
// Print out all of the permutations with that character just chosen above fixed.
RecursivePermute(str, k+1);
// Put the original character that used to be there back in its place.
ExchangeCharacters(str, j, k);
}
Permutation
• For all possible chracters tht could be placed at
index k:
– ExchangeCharacters (str, k, j)
– It means swap the charcaters at index k and j
– Meaning, try all possible (remaining) values at index k
// Print out all of the permutations with that character just chosen above fixed.
RecursivePermute(str, k+1);
// Put the original character that used to be there back in its place.
ExchangeCharacters(str, j, k);
}
Permutation
• For all possible characters at index k:
– So for our example for the first time:
• Input was CAT for the starting and k = 0;
• This loop would run three times(length of CAT=3)
– Each time, the first line would try each character at index 0
– It means C will be at 0, then A will be at 0 and then T will be at 0
// Print out all of the permutations with that character just chosen above fixed.
RecursivePermute(str, k+1);
// Put the original character that used to be there back in its place.
ExchangeCharacters(str, j, k);
}
Permutation
• So, the for loop iterates three times (for CAT)
– First line of code makes each letter the first spot of the
string
– The second line then recursively calls the function
• The arguments are string (updated with a new, 1st character)
• And the new value of k (referring to the #of Fixed spots)
– Third and final line of code simply switches back he
characters that we swapped with the first line of code (of
the for loop)
for (j=k; j<strlen(str); j++) {
// Place the character stored in index j in location k.
ExchangeCharacters(str, k, j);
// Print out all of the permutations with that character just chosen above fixed.
RecursivePermute(str, k+1);
// Put the original character that used to be there back in its place.
ExchangeCharacters(str, j, k);
}
Permutation
• The full code is available here:
https://www.cs.ucf.edu/courses/cop3502/spr2012
/programs/recursion/permute.c
- A tracing code is available here:
https://www.cs.ucf.edu/courses/cop3502/spr2012
/programs/recursion/permute2.c