CS100A Lecture 25 1 December 1998 Chance to replace grade on Prelim 3, Question 2. Everyone is expected to be in lecture on Thursday, 3 December. A short quiz concerning the development of a loop from a invariant will be given --you will have to develop a loop with initialization given the invariant. We will raise your grade on Question 2 of Prelim 3 to your grade on this quiz (but we won’t lower anyone’s grade on Prelim 3) IF: • (0) Your grade on the quiz is larger than your grade on Question 2 of Prelim3 and • (1) You turn in your Prelim3 with the Quiz. Also, we will hand out course evaluations for you to complete and hand in at the end of the lecture. CS100A, Lecture 25, 1 December 1998 1 Memorize this slide A loop invariant is a true-false statement about the variables used in a loop that is true before and after each iteration. Given an invariant P, we can develop a loop with initialization in four steps: • (1) Create initialization that makes P true. • (2) Determine the condition B so that from !B and P you can see that the desired result is true. (Or, equivalently, determine the condition B such that you know the desired result is not true.) • (3) Figure out what statement(s) to put in the loop body to make progress toward termination of the loop. • (4) Figure out what else the loop body should do to ensure that after execution of the loop body invariant P is still true. init; // invariant P: … S must make progress while ( B ) and keep P true {S} CS100A, Lecture 25, 1 December 1998 2 Recursion A method is recursive if it calls itself. Many algorithms are most easily written using recursive methods. To see that recursive method calls (calls of a method from within the body of a method) work, you have only to execute a method call of a recursive method yourself, using the rules that you already know. We’ll show that for a simple case in this lecture. However, to understand that a particular recursive method is correct, you should not think about executing it. Rather, do two things: •(0) Understand that each recursive method call is correct in terms of the specification of the method. •(2) Make sure that the recursion “terminates” (much like making sure that a loop terminates). That is, see to it that in some sense the arguments of the recursive call are “smaller” than the parameters of the method and that when the parameters are “as small as possible”, the method terminates without calling itself recursively. We’ll see this in the examples. CS100A, Lecture 25, 1 December 1998 3 Return the reverse of a string // Return the reverse of string s. For example, if s is // “abcd”, return the string “dcba”. public static String rev(String s) { // If the string is empty or contains one character, return it if (s.length( ) <= 1) return s; // The string has the form C c, where C is a character; // c is a string. C is s.charAt(0). c is s.substring(1). // Return the reverse of c catenated with C return rev(s.substring(1)) + charAt(0); } Note that the argument to the recursive call rev(s.substring(1)) has one less character than parameter s. Therefore, the “depth” of recursion --the maximum number of recursive calls with frames that will exist at any time-- is the number of characters in s. CS100A, Lecture 25, 1 December 1998 4 Execution of rev // Return the reverse of string s. public static String rev(String s) { if (s.length( ) <= 1) return s; return rev(/*L2:*/s.substring(1)) + charAt(0); } ------------------ in main method:--------------String t= /*L1:*/ rev(“abc”); M0: frame for main. Called from system t ____ F0: first frame for rev. Called from main.L1, frame M0 s “abc” F2: second frame for rev. Called from rev.L2, frame F1 s “bc” F3: third frame for rev. Called from rev.L2, frame F2 s “c” CS100A, Lecture 25, 1 December 1998 5 Method to remove blanks // Return a copy of s, but with blanks removed public static String removeBlanks (String s) { if (s.length() = 0) return s; if (s.charAt(0) = ‘ ‘) return s.substring(1); // first character of s is not a blank. // Return first character followed by rest of s // but with blanks removed return s.charAt(0) + removeBlanks(s.substring(1)); } Method to duplicate each character // Return a copy of s but with each character repeated public static String dup(String s) { if s.length() == 0) return s; return s.charAt(0) + s.charAt(0) + dup(s.substring(1)); } CS100A, Lecture 25, 1 December 1998 6 Recursive method to lower-case a String // Return a copy of s with all capital letters lower-cased public static lowerCase(String s) { if (s.length()= 0) return s; // Store into c the first character, lower-cased // if necessary char c= s.charAt(0); if (‘A’ <=s.charAt(0) && s.charAt(0) <=‘Z’) c= (char) ((int)s.charAt(0) -26); return c + lowerCase(s.substring(1)); } Recursive method for logarithmic exponentiation // Given b>= 0, return ab public static int exp(int a, int b) { if (b == 0) return 1; if (b is odd) return a * exp ( b-1); // b is even, so ab = (a*a)b/2 return exp(a*a, b/2); } CS100A, Lecture 25, 1 December 1998 7 Tiling a kitchen with L-shaped squares Our house has a kitchen which is 2n x 2n feet square (for some integer n). A small, 1 x 1 refrigerator sits on one square of the room. How can we tile the floor with Lshaped tiles that look like this (2 x 2 feet with a 1 x 1 section missing)? 2n Kitchen, showing two possible locations for the refrigerator 2n CS100A, Lecture 25, 1 December 1998 8 // Given n >= 0 and a 2n x 2n feet square room with one // square filled, tile room with L-shaped squares (see // previous slide) public static tile(Floor p, int n) { if (n=0) return; Draw horizontal and vertical lines in middle of room p, as shown to the right. One of the four quadrants has a 2n-1 a 1 x 1 square filled . (example shown). Place an L-shaped tile as shown to the 2n-1 right, so that each of the other quad2n-1 rants has a square 2n-1 filled. Now call tile(p1,n-1) four times, where each time p1 is one of the four quadrants, to tile the four quadrants. } CS100A, Lecture 25, 1 December 1998 9 // Given n>=0, return !n = 1*2*3*…*n public static factorial(int n) { if (n<=1) return 1; return n * factorial(n-1); } // Binary search --Given is b[0..h] <= x < b[k..n-1] and // h < k and b is sorted (in ascending order). // Return an integer j satisfying b[0..j] <= x < b[j+1]. Public static bsearch(int[ ] b, int h, int k) { if (h+1 = k) return h; int e= (h+k)/2; if (b[e] <= x) return bsearch(b, e, k); else return bsearch(b, h, e); } CS100A, Lecture 25, 1 December 1998 10 Fibonacci numbers Fn given by: F0 = 0 F1 = 1 Fn = Fn-1 + f n-2 for n>1 // Given n>= 0, return Fn --inefficient version public static fib(int n) { if (n<=1) return n; return fib(n-1) + fib(n-2); } -----------------------------------------------------------------------// Given n>= 0, return Fn --efficient version public static fibe(int n) { if (n=0) return n; return fibh(n,0,1,1) } // Given: 0<m<=n and Fm-1 = a and Fm=b, return Fn public static fibh(int n, int a, int b, int m) { if (m=n) return b; return fibh(n, b, a+b, m+1); } CS100A, Lecture 25, 1 December 1998 11