This preview shows page 1. Sign up to view the full content.
Unformatted text preview: CS32 Discussion
Section 2C
Week 5 TA: Brian Choi Reminder • Homework 3 – Due Sunday, not Tuesday! • Midterm – 2/9 Wednesday – Open book, open notes, closed friends – Everything up through recursion is a fair game – Practice Problems posted • Solutions to be released by Monday evening… Recursion • Functionwriting technique where the function refers to itself. • Recall the following function: int factorial(int n) { if (n <= 1) return 1; return n * factorial(n – 1); } • Let us talk about how to come up with such a function. Decomposition of the problem • You’re all used to the following technique. int factorial(int n) { int temp = 1; for (int i = 1; i <= n; i++) temp *= i; return temp; } • n! = 1 * 2 * 3 * … * (n1) * n Decomposition of the problem • You re all used to the following technique. int factorial(int n) { int temp = 1; for (int i = 1; i <= n; i++) temp *= i; return temp; } • n! = 1 * 2 * 3 * … * (n1) * n = factorial(n1)! Decomposition of the problem • You’re all used to the following technique. int factorial(int n) { int temp = 1; for (int i = 1; i <= n; i++) temp *= i; return temp; } • n! = 1 * 2 * 3 * … * (n1) * n • n! = factorial(n1) * n Decomposition of the problem int factorial(int n) { int temp = factorial(n
1) * n; return temp; } • n! = 1 * 2 * 3 * … * (n1) * n • n! = factorial(n1) * n Power of Belief • BELIEVE factorial(n  1) will do the right thing. int factorial(int n) { int temp = factorial(n
1) * n; return temp; } •
•
•
• factorial(n) will believe that factorial(n1) will return the right value. factorial(n1) will believe that factorial(n2) will return the right value. … factorial(2) will believe that factorial(1) will return the right value. Power of Belief • BELIEVE factorial(n  1) will do the right thing. int factorial(int n) { int temp = factorial(n
1) * n; return temp; } •
•
•
• factorial(n) will believe that factorial(n1) will return the right value. factorial(n1) will believe that factorial(n2) will return the right value. … factorial(2) will believe that factorial(1) will return the right value. Power of Belief • BELIEVE factorial(n  1) will do the right thing. int factorial(int n) { int temp = factorial(n
1) * n; return temp; } •
•
•
•
• factorial(n) will believe that factorial(n1) will return the right value. factorial(n1) will believe that factorial(n2) will return the right value. … factorial(2) will believe that factorial(1) will return the right value. AND MAKE factorial(1) return the right value! Base Case • BELIEVE factorial(n  1) will do the right thing. int factorial(int n) { if (n <= 1) return 1; int temp = factorial(n
1) * n; return temp; } •
•
•
•
• factorial(n) will believe that factorial(n1) will return the right value. factorial(n1) will believe that factorial(n2) will return the right value. … factorial(2) will believe that factorial(1) will return the right value. AND MAKE factorial(1) return the right value! Base Case int factorial(int n) { if (n <= 1) return 1; int temp = factorial(n
1) * n; return temp; } 5 4 3 2 n=5 n=4 n=3 n=2 1 base case Pattern • How to Write a Recursive Function for Dummies 1. Find the base case(s). •
• What are the trivial cases? e.g. empty string, empty array, etc. When should the recursion stop? 2. Decompose the problem. • Example: Tail recursion –
Take the ﬁrst (or last) of the n items of information. –
Make a recursive call to the rest of n1 items, believing the recursive call will
give you the correct result. –
Given this result and the information you have on the ﬁrst (or last) item,
conclude about the n items. 3. Just solve this subproblem! Pattern • Write your function this way: recursive_function(set of data) •
• 1. Take care of all base cases 2. x = current data item 3. result = recursive_function(set of data – {x}) 4. combine x and result Lastly, look back and make sure every call to this function hits
some base case eventually. There are variations: –
– You may need to make multiple recursive calls. You may make a different recursive call based on x. Practice 1: Average double average(const double arr, int n) { // assume n > 0 } Practice 1: Average • What is the base case? • What is the relationship between (n)step and (n1)step?
That is, how do I get the average of n items, knowing the
average of n1 of them? Practice 1: Average •
• What is the base case? n = 1, where the average is just the value of the only item. What is the relationship between (n)step and (n1)step?
That is, how do I get the average of n items, knowing the
average of n1 of them? • average(arr, n)
= total(all n items) / n = {total(ﬁrst n1 items) + nth item} / n = average(arr, n1) * (n1) + nth item n • Practice 1: Average double average(const double arr, int n) { if (n == 1) return arr[0]; double prevAvg = average(arr, n – 1); return ((n – 1) * prevAvg + arr[n – 1]) / n; } Practice 2: Summing Digits int sumOfDigits(const int n) { // assume n >= 0 } Practice 2: Summing Digits • What is the base case? • What is the relationship between (n)step and (n1)step?
That is, how do I get the sum of n digits, knowing the sum of
digits of (n1) digits? Practice 2: Summing Digits •
• What is the base case? n < 10 (i.e. n is a single digit number), where the sum of digits
is simply n • What is the relationship between (n)step and (n1)step?
That is, how do I get the sum of n digits, knowing the sum of
digits of (n1) digits? Just add the last digit to the sum! • Practice 2: Summing Digits int sumOfDigits(const int n) { if (n < 10) return n; return n % 10 + sumOfDigits(n / 10); } Practice 3: Deleting characters string deleteChar(const string &s, const char c) { } Practice 3: Deleting characters • What is the base case? • What is the relationship between (n)step and (n1)step? Practice 3: Deleting characters •
• What is the base case? s == : There is no character to delete! Just return •
• What is the relationship between (n)step and (n1)step? Suppose the string is of length n, and you make a recursive
call on s.substr(1). (e.g. If the string is hello , the recursive
call will be made on ello .) What’s returned by deleteChar must not contain any c.You
only need to append s[0] to it if s[0] != c. If s[0] == c, just
return it. • . Practice 3: Deleting characters string deleteChar(const string &s, const char c) { if (s.empty()) return s; if (s[0] == c) return deleteChar(s.substr(1), c); else return s[0] + deleteChar(s.substr(1), c); } Practice 4: Fibonacci numbers • Fibonacci numbers refer to the sequence of numbers of the
following form: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, … –
–
– F(0) = 0 F(1) = 1 F(n) = F(n1) + F(n2), n >= 2 Practice 4: Fibonacci numbers // A little too obvious now, isn’t it? int fibo(const int n) { if (n == 0) return 0; if (n == 1) return 1; return fibo(n – 1) + fibo(n – 2); } Practice 4: Fibonacci numbers • Note that ﬁbo() makes two recursive calls. ﬁbo(4) ﬁbo(3) ﬁbo(2) • ﬁbo(1) ﬁbo(1) ﬁbo(0) Look at all this redundancy!!!! ﬁbo(2) ﬁbo(1) ﬁbo(0) Trick: Memoization int fibMem[100]; // global for (int i = 2; i < 100; ++i) fibMem[i] =
1; fibMem[0] = 0; fibMem[1] = 1; int fibo(const int n) { int fib1, fib2; if (fibMem[n
1] !=
1) fib1 = fibMem[n
1]; else fib1 = fibo(n
1); if (fibMem[n
2] !=
1) fib2 = fibMem[n
2]; else fib2 = fibo(n
2); fibMem[n] = fib1 + fib2; return fib1 + fib2; } Memoization is an optimization technique that
helps avoid computing the same value over and
over by remembering it. We like this because memory is cheap, but
computing time is not! Practice 5: Palindrome • Examples: eye , racecar , deed bool palindrome(const string &s) { } •
• Base case? General case? Practice 5: Palindrome • Examples: eye , racecar , deed bool palindrome(const string &s) { } • Cases: (1) size = 0, (2) size = 1, (3) the ﬁrst char differs from
the last one, (4) ﬁrst char = last char Practice 5: Palindrome • Examples: eye , racecar , deed bool palindrome(const string &s) { if (s.size() <= 1) return true; if (s[0] != s[s.size()
1]) return false; return palindrome(s.substr(1, s.size()
2)); } • Cases: (1) size = 0, (2) size = 1, (3) the ﬁrst char differs from
the last one, (4) ﬁrst char = last char More Practice • Write reverse(), which recursively reverses a string and
return the reversed version. string reverse(const string &s) { } More and More Practice •
• Generate mnemonic phone numbers (e.g.1800UCLACSD). Assume the following function is given: string digitToLetters(char digit) { switch (digit) { case '0': return "0"; case '1': return "1"; case '2': return "ABC"; case '3': return "DEF"; ... case '9': return "WXYZ"; default: cout << "ERROR" << endl; abort(); } } More and More Practice • Given digitToLetters(), write a function mnemonics, which
prints all possible mnemonic numbers given the preﬁx and
digits. (No restrictions here – you can use a loop.) void mnemonics(const string &prefix, const string &digits); mnemonics(“”, “723”); PAD PAE PAF PBD PBE PBF ... mnemonics(“1
800
”, “723”) 1
800
PAD 1
800
PAE 1
800
PAF 1
800
PBD 1
800
PBE 1
800
PBF ... Practice helps •
•
•
• Recursion is somewhat counterintuitive when confronted
for the ﬁrst time. Just do a lot of practice and you will see some patterns. Try ﬁnding more examples by googling. Again, the key to recursion is to believe ! Do not try to
track the call stack down and see what happens until you
really have to. Test Taking Tips •
•
• • I know it’s open book, but often it helps to create cheat
sheets anyways. Have some representative example codes available in your
notes. But do not try to copy from hw/proj solutions! We have seen
so many people using variable names and function calls from
projects, when they don t even exist in the exam questions!
(e.g. using Animal class s name() function when the problem
asks you to build a class called Tank.) Get a lot of sleep before coming into the exam site. :D ...
View
Full
Document
This note was uploaded on 02/20/2012 for the course CS 32 taught by Professor Davidsmallberg during the Winter '08 term at UCLA.
 Winter '08
 DavidSmallBerg
 Recursion

Click to edit the document details