University of Phoenix – DAT/305 – Individual: Recursion, Section 5.3Resource: Ch. 5, “Recursion”, of Data Structures: Abstraction and Design Using Java, Exercises for Section 5.3; Self-Check #4Complete Self-Check #4 within the “Exercises for Section 5.3” subsection in Section 5.3, “Recursive Array Search” of Ch. 5, “Recursion” in Data Structures: Abstraction and Design Using Java.Submit the pseudocode to the Assignment Files tab.

University of Phoenix – DAT/305 – Individual: Recursion, Section 5.3Resource: Ch. 5, “Recursion”, of Data Structures: Abstraction and Design Using Java, Exercises for Section 5.3; Self-Check #4Complet

Chapter 5 Recursion Chapter Objectives To understand how to think recursively To learn how to trace a recursive method To learn how to write recursive algorithms and methods for searching arrays To learn about recursive data structures and recursive methods for a LinkedList class To understand how to use recursion to solve the Towers of Hanoi problem To understand how to use recursion to process two-dimensional images To learn how to apply backtracking to solve search problems such as finding a path through a maze This chapter introduces a programming technique called recursion and shows you how to think recursively. You can use recursion to solve many kinds of programming problems that would be very difficult to conceptualize and solve without recursion. Computer scientists in the field of artificial intelligence (AI) often use recursion to write programs that exhibit intelligent behavior: playing games such as chess, proving mathematical theorems, recognizing patterns, and so on. In the beginning of the chapter, you will be introduced to recursive thinking and how to design a recursive algorithm and prove that it is correct. You will also learn how to trace a recursive method and use activation frames for this purpose. Recursive algorithms and methods can be used to perform common mathematical operations, such as computing a factorial or a greatest common divisor(gcd). Recursion can be used to process familiar data structures, such as strings, arrays, and linked lists, and to design a very efficient array search technique called binary search. You will also see that a linked list is a recursive data structure and learn how to write recursive methods that perform common list-processing tasks. Recursion can be used to solve a variety of other problems. The case studies in this chapter use recursion to solve a game, to search for “blobs” in a two-dimensional image, and to find a path through a maze. Recursion 5.1 Recursive Thinking 5.2 Recursive Definitions of Mathematical Formulas 5.3 Recursive Array Search 5.4 Recursive Data Structures 5.5 Problem Solving with Recursion Case Study: Towers of Hanoi Case Study: Counting Cells in a Blob 5.6 Backtracking Case Study: Finding a Path through a Maze 5.1 Recursive Thinking Recursion is a problem-solving approach that can be used to generate simple solutions to certain kinds of problems that would be difficult to solve in other ways. In a recursive algorithm, the original problem is split into one or more simpler versions of itself. For example, if the solution to the original problem involved n items, recursive thinking might split it into two problems: one involving n − 1 items and one involving just a single item. Then the problem with n − 1 items could be split again into one involving n − 2 items and one involving just a single item, and so on. If the solution to all the one-item problems is “trivial,” we can build up the solution to the original problem from the solutions to the simpler problems. As an example of how this might work, consider a collection of nested wooden figures as shown in Figure 5.1. If you wanted to write an algorithm to “process” this collection in some way (such as counting the figures or painting a face on each figure), you would have difficulty doing it because you don’t know how many objects are in the nest. But you could use recursion to solve the problem in the following way. Recursive Algorithm to Process Nested Figures 1. if there is one figure in the nest 2. Do whatever is required to the figure. else 3. Do whatever is required to the outer figure in the nest. 4. Process the nest of figures inside the outer figure in the same way. image FIGURE 5.1 A Set of Nested Wooden Figures In this recursive algorithm, the solution is trivial if there is only one figure: perform Step 2. If there is more than one figure, perform Step 3 to process the outer figure. Step 4 is the recursive operation—recursively process the nest of figures inside the outer figure. This nest will, of course, have one less figure than before, so it is a simpler version of the original problem. As another example, let’s consider searching for a target value in an array. Assume that the array elements are sorted and are in increasing order. A recursive approach, which we will study in detail in Section 5.3, involves replacing the problem of searching an array of n elements with one of searching an array of n/2 elements. How do we do that? We compare the target value to the value of the element in the middle of the sorted array. If there is a match, we have found the target. If not, based on the result of the comparison, we either search the elements that come before the middle one or the elements that come after the middle one. So we have replaced the problem of searching an array with n elements to one that involves searching a smaller array with only n/2 elements. The recursive algorithm follows. Recursive Algorithm to Search an Array 1. if the array is empty 2. Return –1 as the search result. else if the middle element matches the target 3. Return the subscript of the middle element as the result. else if the target is less than the middle element 4. Recursively search the array elements before the middle element and return the result. else 5. Recursively search the array elements after the middle element and return the result. The condition in Step 1 is true when there are no elements left to search. Step 2 returns –1 to indicate that the search failed. Step 3 executes when the middle element matches the target. Otherwise, we recursively apply the search algorithm (Steps 4 and 5), thereby searching a smaller array (approximately half the size), and return the result. For each recursive search, the region of the array being searched will be different, so the middle element will also be different. The two recursive algorithms we showed so far follow this general approach: General Recursive Algorithm 1. if the problem can be solved for the current value of n 2. Solve it. else 3. Recursively apply the algorithm to one or more problems involving smaller values of n. 4. Combine the solutions to the smaller problems to get the solution to the original. Step 1 involves a test for what is called the base case: the value of n for which the problem can be solved easily. Step 3 is the recursive case because we recursively apply the algorithm. Because the value of n for each recursive case is smaller than the original value of n, each recursive case makes progress toward the base case. Whenever a split occurs, we revisit Step 1 for each new problem to see whether it is a base case or a recursive case. Steps to Design a Recursive Algorithm From what we have seen so far, we can summarize the characteristics of a recursive solution: There must be at least one case (the base case), for a small value of n, that can be solved directly. A problem of a given size (say, n) can be split into one or more smaller versions of the same problem (the recursive case). Therefore, to design a recursive algorithm, we must Recognize the base case and provide a solution to it. Devise a strategy to split the problem into smaller versions of itself. Each recursive case must make progress toward the base case. Combine the solutions to the smaller problems in such a way that each larger problem is solved correctly. Next, we look at a recursive algorithm for a common programming problem. We will also provide a Java method that solves this problem. All of the methods in this section and in the next will be found in class RecursiveMethods.java on this textbook’s Web site. EXAMPLE 5.1 Let’s see how we could write our own recursive method for finding the string length. How would you go about doing this? If there is a special character that marks the end of a string, then you can count all the characters that precede this special character. But if there is no special character, you might try a recursive approach. The base case is an empty string—its length is 0. For the recursive case, consider that each string has two parts: the first character and the “rest of the string.” If you can find the length of the “rest of the string,” you can then add 1 (for the first character) to get the length of the larger string. For example, the length of “abcde” is 1 + the length of “bcde”. Recursive Algorithm for Finding the Length of a String 1. if the string is empty (has no characters) 2. The length is 0. else 3. The length is 1 plus the length of the string that excludes the first character. We can implement this algorithm as a static method with a String argument. The test for the base case is a string reference of null or a string that contains no characters (“”). In either case, the length is 0. In the recursive case, return 1 + length(str.substring(1)); the method call str.substring(1) returns a reference to a string containing all characters in string str except for the character at position 0. Then we call method length again with this substring as its argument. The method result is one more than the value returned from the next call to length. Each time we reenter the method length, the if statement executes with str referencing a string containing all but the first character in the previous call. Method length is called a recursive method because it calls itself. /** Recursive method length (in RecursiveMethods.java). @param str The string @return The length of the string */ public static int length(String str) { if (str == null || str.isEmpty()) return 0; else return 1 + length(str.substring(1)); EXAMPLE 5.2 Method printChars is a recursive method that displays each character in its string argument on a separate line. In the base case (an empty or nonexistent string), the method return occurs immediately and nothing is displayed. In the recursive case, printChars displays the first character of its string argument and then calls itself to display the characters in the rest of the string. If the initial call is printChars(“hat”), the method will display the lines h a t Unlike the method length in Example 5.1, printChars is a void method. However, both methods follow the format for the general recursive algorithm shown earlier. /** Recursive method printChars (in RecursiveMethods.java). post: The argument string is displayed, one character per line. @param str The string */ public static void printChars(String str) { if (str == null || str.isEmpty()) { return; } else { System.out.println(str.charAt(0)); printChars(str.substring(1)); } } You get an interesting result if you reverse the two statements in the recursive case. /** Recursive method printCharsReverse (in RecursiveMethods.java). post: The argument string is displayed in reverse, one character per line. @param str The string */ public static void printCharsReverse(String str) { if (str == null || str.isEmpty()) { return; } else { printCharsReverse(str.substring(1)); System.out.println(str.charAt(0)); } } Method printCharsReverse calls itself to display the rest of the string before displaying the first character in the current string argument. The effect will be to delay displaying the first character in the current string until all characters in the rest of the string are displayed. Consequently, the characters in the string will be displayed in reverse order. If the initial call is printCharsReverse(“hat”), the method will display the lines t a Proving that a Recursive Method Is Correct To prove that a recursive method is correct, you must verify that you have performed correctly the design steps listed earlier. You can use a technique that mathematicians use to prove that a theorem is true for all values of n. A proof by induction works the following way: Prove the theorem is true for the base case of (usually) n = 0 or n = 1. Show that if the theorem is assumed true for n, then it must be true for n + 1. We can extend the notion of an inductive proof and use it as the basis for proving that a recursive algorithm is correct. To do this: Verify that the base case is recognized and solved correctly. Verify that each recursive case makes progress toward the base case. Verify that if all smaller problems are solved correctly, then the original problem is also solved correctly. If you can show that your algorithm satisfies these three requirements, then your algorithm will be correct. EXAMPLE 5.3 To prove that the length method is correct, we know that the base case is an empty string and its length is correctly set at 0. The recursive case involves a call to length with a smaller string, so it is making progress toward the base case. Finally, if we know the length of the rest of the string, adding 1 gives us the length of the longer string consisting of the first character and the rest of the string. Tracing a Recursive Method Figure 5.2 traces the execution of the method call length(“ace”). The diagram shows a sequence of recursive calls to the method length. After returning from each call to length, we complete execution of the statement return 1 + length(…); by adding 1 to the result so far and then returning from the current call. The final result, 3, would be returned from the original call. The arrow alongside each word return shows which call to length is associated with that result. For example, 0 is the result of the method call length(“”). After adding 1, we return 1, which is the result of the call length(“e”), and so on. This process of returning from the recursive calls and computing the partial results is called unwinding the recursion. image FIGURE 5.2 Trace of length(“ace”) The Run-Time Stack and Activation Frames You can also trace a recursive method by showing what Java does when one method calls another. Java maintains a run-time stack, on which it saves new information in the form of an activation frame. The activation frame contains storage for the method arguments and any local variables as well as the return address of the instruction that called the method. Whenever a method is called, Java pushes a new activation frame onto the run-time stack and saves this information on the stack. This is done whether or not the method is recursive. The left side of Figure 5.3 shows the activation frames on the run-time stack after the last recursive call (corresponding to length(“”)) resulting from an initial call to length(“ace”). At any given time, only the frame at the top of the stack is accessible, so its argument values will be used when the method instructions execute. When the return statement executes, control will be passed to the instruction at the specified return address, and this frame will be popped from the stack (Figure 5.3, right). The activation frame corresponding to the next-to-last call (length(“e”)) is now accessible. image FIGURE 5.3 Run-Time Stack before and after Removal of Frame for length(“”) You can think of the run-time stack for a sequence of calls to a recursive method as an office tower in which an employee on each floor has the same list of instructions1. The employee in the bottom office carries out part of the instructions on the list, calls the employee in the office above, and is put on hold. The employee in the office above starts to carry out the list of instructions, calls the employee in the next higher office, is put on hold, and so on. When the employee on the top floor is called, that employee carries out the list of instructions to completion and then returns an answer to the employee below. The employee below then resumes carrying out the list of instructions and returns an answer to the employee on the next lower floor, and so on, until an answer is returned to the employee in the bottom office, who then resumes carrying out the list of instructions. To make the flow of control easier to visualize, we will draw the activation frames from the top of the page down (see Figure 5.4). For example, the activation frame at the top, which would actually be at the bottom of the run-time stack, represents the first call to the recursive method. The downward-pointing arrows connect each statement that calls a method with the frame for that particular execution of the method. The upward-pointing arrows show the return point from each lower-level call with the value returned alongside the arrow. For each frame, the return point is to the addition operator in the statement return 1 + length(…);. For each frame, the code in the gray screen is executed prior to the creation of the next activation frame; the rest of the code shown is executed after the return. image FIGURE 5.4 Trace of length(“ace”) Using Activation Frames EXERCISES FOR SECTION 5.1 SELF-CHECK Trace the execution of the call mystery(4) for the following recursive method using the technique shown in Figure 5.2. What does this method do? public static mystery(int n) { if (n == 0) return 0; else return n * n + mystery(n – 1); } Answer Exercise 1 above using activation frames. Trace the execution of printChars(“tic”) (Example 5.2) using activation frames. Trace the execution of printCharsReverse(“toc”) using activation frames. Prove that the printChars method is correct. Trace the execution of length(“tictac”) using a diagram like Figure 5.2. Write a recursive algorithm that determines whether a specified target character is present in a string. It should return true if the target is present and false if it is not. The stopping steps should be a string reference to null or a string of length 0, the result is false the first character in the string is the target, the result is true. The recursive step would involve searching the rest of the string. PROGRAMMING Write a recursive method toNumber that forms the integer sum of all digit characters in a string. For example, the result of toNumber(“3ac4”) would be 7. Hint: If next is a digit character (‘0’ through ‘9’), Character.isDigit(next) is true and the numeric value of next is Character.digit(next, 10). Write a recursive method stutter that returns a string with each character in its argument repeated. For example, if the string passed to stutter is “hello”, stutter will return the string “hheelllloo”. Write a recursive method that implements the recursive algorithm for searching a string in Self-Check Exercise . The method heading should be public static boolean searchString(String str, char ch) 5.2 Recursive Definitions of Mathematical Formulas Mathematicians often use recursive definitions of formulas. These definitions lead very naturally to recursive algorithms. EXAMPLE 5.4 The factorial of n, or n!, is defined as follows: 0!=1n!=n×(n−1)! The first formula identifies the base case: n equal to 0. The second formula is a recursive definition. It leads to the following algorithm for computing n!. Recursive Algorithm for Computing n! 1. if n equals 0 2. n! is 1. else 3. n! = n × (n – 1)! To verify the correctness of this algorithm, we see that the base case is solved correctly (0! is 1). The recursive case makes progress toward the base case because it involves the calculation of a smaller factorial. Also, if we can calculate (n – 1)!, the recursive case gives us the correct formula for calculating n!. The recursive method follows. The statement return n * factorial(n – 1); implements the recursive case. Each time factorial calls itself, the method body executes again with a different argument value. An initial method call such as factorial(4) will generate four recursive calls, as shown in Figure 5.5. /** Recursive factorial method (in RecursiveMethods.java). pre: n >= 0 @param n The integer whose factorial is being computed @return n! */ public static int factorial(int n) { if (n == 0) return 1; else return n * factorial(n – 1); image FIGURE 5.5 Trace of factorial(4) image PITFALL Infinite Recursion and Stack Overflow If you call method factorial with a negative argument, you will see that the recursion does not terminate. It will continue forever because the stopping case, n equals 0, can never be reached, as n gets more negative with each call. For example, if the original value of n is –4, you will make method calls factorial(–5), factorial(–6), factorial(–7), and so on. You should make sure that your recursive methods are constructed so that a stopping case is always reached. One way to prevent the infinite recursion in this case would be to change the terminating condition to n <= 0. However, this would incorrectly return a value of 1 for n! if n is negative. A better solution would be to throw an IllegalArgumentException if n is negative. If your program does not terminate properly, you may see an extremely long display on the console (if the console is being used to display its results). Eventually the exception StackOverflowError will be thrown. This means that the memory area used to store information about method calls (the run-time stack) has been used up because there have been too many calls to the recursive method. Because there is no memory available for this purpose, your program can't execute any more method calls. EXAMPLE 5.5 Let's develop a recursive method that raises a number x to a power n, where n is positive or zero. You can raise a number to a power by repeatedly multiplying that number by itself. So if we know xk, we can get xk+1 by multiplying xk by x. The recursive definition is xn=x×xn–1 This gives us the recursive case. You should know that any number raised to the power 0 is 1, so the base case is x0=1 Recursive Algorithm for Calculating xn (n ≥ 0) 1. if n is 0 2. The result is 1. else 3. The result is x×xn–1 . We show the method next. /** Recursive power method (in RecursiveMethods.java). pre: n >= 0 @param x The number being raised to a power @param n The exponent @return x raised to the power n */ public static double power(double x, int n) { if (n == 0) return 1; else return x * power(x, n – 1); EXAMPLE 5.6 The greatest common divisor (gcd) of two numbers is the largest integer that divides both numbers. For example, the gcd of 20, 15 is 5; the gcd of 36, 24 is 12; the gcd of 36, 18 is 18. The mathematician Euclid devised an algorithm for finding the greatest common divisor (gcd) of two integers, m and n, based on the following definition. Definition of gcd(m, n) for m > n gcd(m, n) = n if n is a divisor of m gcd(m, n) = gcd(n, m % n) if n isn’t a divisor of m This definition states that gcd(m, n) is n if n divides m. This is correct because no number larger than n can divide n. Otherwise, the definition states that gcd(m, n) is the same as gcd(n, m % n), where m % n is the integer remainder of m divided by n. Therefore, gcd(20, 15) is the same as gcd(15, 5), or 5, because 5 divides 15. This recursive definition leads naturally to a recursive algorithm. Recursive Algorithm for Calculating gcd(m, n) for m > n 1. if n is a divisor of m 2. The result is n. else 3. The result is gcd(n, m % n). To verify that this is correct, we need to make sure that there is a base case and that it is solved correctly. The base case is “n is a divisor of m.” If so, the solution is n (n is the gcd), which is correct. Does the recursive case make progress to the base case? It must because both arguments in each recursive call are smaller than in the previous call, and the new second argument is always smaller than the new first argument (m % n must be less than n). Eventually a divisor will be found, or the second argument will become 1. Since 1 is a base case (1 divides every integer), we have verified that the recursive case makes progress toward the base case. Next, we show method gcd. Note that we do not need a separate clause to handle arguments that initially are not in the correct sequence. This is because if m < n, then m % n is m and the recursive call will transpose the arguments so that m > n in the first recursive call. /** Recursive gcd method (in RecursiveMethods.java). pre: m > 0 and n > 0 @param m The larger number @param n The smaller number @return Greatest common divisor of m and n */ public static double gcd(int m, int n) { if (m % n == 0) return n; else return gcd(n, m % n); Tail Recursion versus Iteration Method gcd above is an example of tail recursion. In tail recursion, the last thing a method does is to call itself. You may have noticed that there are some similarities between tail recursion and iteration. Both techniques enable us to repeat a compound statement. In iteration, a loop repetition condition in the loop header determines whether we repeat the loop body or exit from the loop. We repeat the loop body while the repetition condition is true. In tail recursion, the condition usually tests for a base case. In a recursive method, we stop the recursion when the base case is reached (the condition is true), and we execute the method body again when the condition is false. We can always write an iterative solution to any problem that is solvable by recursion. However, the recursive solutions will be easier to conceptualize and should, therefore, lead to methods that are easier to write, read, and debug—all of which are very desirable attributes of code. EXAMPLE 5.7 In Example 5.4, we wrote the recursive method. public static int factorial(int n) { if (n == 0) return 1; else return n * factorial(n – 1); } It is a straightforward process to turn this method into an iterative one, replacing the if statement with a loop, as we show next. /** Iterative factorial method. pre: n >= 0 @param n The integer whose factorial is being computed @return n! */ public static int factorialIter(int n) { int result = 1; while (n > 0){ result *= n; n = n – 1; } return result; Efficiency of Recursion The iterative method factorialIter multiplies all integers between 1 and n to compute n!. It may be slightly less readable than the recursive method factorial, but not much. In terms of efficiency, both algorithms are O(n) because the number of loop repetitions or recursive calls increases linearly with n. However, the iterative version is probably faster because the overhead for a method call and return would be greater than the overhead for loop repetition (testing and incrementing the loop control variable). The difference, though, would not be significant. Generally, if it is easier to conceptualize an algorithm using recursion, then you should code it as a recursive method because the reduction in efficiency does not outweigh the advantage of readable code that is easy to debug. EXAMPLE 5.8 The Fibonacci numbers fibn are a sequence of numbers that were invented to model the growth of a rabbit colony. Therefore, we would expect this sequence to grow very quickly, and it does. For example, fib10 is 55, fib15 is 610, fib20 is 6765, and fib25 is 75,025 (that’s a lot of rabbits!). The definition of this sequence follows: fib0=0fib1=1fibn=fibn−1+fibn−2 Next, we show a method that calculates the nth Fibonacci number. The last line codes the recursive case. /** Recursive method to calculate Fibonacci numbers (in RecursiveMethods.java). pre: n >= 0 @param n The position of the Fibonacci number being calculated @return The Fibonacci number */ public static int fibonacci(int n) { if (n == 0) return 0; else if (n == 1) return 1; else return fibonacci(n – 1) + fibonacci(n – 2); } Unfortunately, this solution is very inefficient because of multiple calls to fibonacci with the same argument. For example, calculating fibonacci(5) results in calls to fibonacci(4) and fibonacci(3). Calculating fibonacci(4) results in calls to fibonacci(3) (second call) and also fibonacci(2). Calculating fibonacci(3) twice results in two more calls to fibonacci(2) (three calls total), and so on (see Figure 5.6). image FIGURE 5.6 Method Calls Resulting from fibonacci(5) Because of the redundant method calls, the time required to calculate fibonacci(n) increases exponentially with n. For example, if n is 100, there are approximately 2100 activation frames. This number is approximately 1030. If you could process one million activation frames per second, it would still take 1024 seconds, which is approximately 3 × 1016 years. However, it is possible to write recursive methods for computing Fibonacci numbers that have O(n) performance. We show one such method next. /** Recursive O(n) method to calculate Fibonacci numbers (in RecursiveMethods.java). pre: n >= 1 @param fibCurrent The current Fibonacci number @param fibPrevious The previous Fibonacci number @param n The count of Fibonacci numbers left to calculate @return The value of the Fibonacci number calculated so far */ private static int fibo(int fibCurrent, int fibPrevious, int n) { if (n == 1) return fibCurrent; else return fibo(fibCurrent + fibPrevious, fibCurrent, n – 1); } Unlike method fibonacci, method fibo does not follow naturally from the recursive definition of the Fibonacci sequence. In the method fibo, the first argument is always the current Fibonacci number and the second argument is the previous one. We update these values for each new call. When n is 1 (the base case), we have calculated the required Fibonacci number, so we return its value (fibCurrent). The recursive case return fibo(fibCurrent + fibPrevious, fibCurrent, n – 1); passes the sum of the current Fibonacci number and the previous Fibonacci number to the first parameter (the new value of fibCurrent); it passes the current Fibonacci number to the second parameter (the new value of fibPrevious); and it decrements n, making progress toward the base case. To start this method executing, we need the following wrapper method, which is not recursive. This method is called a wrapper method because its main purpose is to call the recursive method and return its result. Its parameter, n, specifies the position in the Fibonacci sequence of the number we want to calculate. After testing for the special case n equals 0, it calls the recursive method fibo, passing the first Fibonacci number as its first argument and n as its third. /** Wrapper method for calculating Fibonacci numbers (in RecursiveMethods.java). pre: n >= 0 @param n The position of the desired Fibonacci number @return The value of the nth Fibonacci number */ public static int fibonacciStart(int n) { if (n == 0) return 0; else return fibo(1, 0, n); } Figure 5.7 traces the execution of the method call fibonacciStart(5). Note that the first arguments for the method calls to fibo form the sequence 1, 1, 2, 3, 5, which is the Fibonacci sequence. Also note that the result of the first return (5) is simply passed on by each successive return. That is because the recursive case does not specify any operations other than returning the result of the next call. Note that the method fibo is an example of tail recursion. image FIGURE 5.7 Trace of fibonacciStart(5) EXERCISES FOR SECTION 5.2 SELF-CHECK Does the recursive algorithm for raising x to the power n work for negative values of n? Does it work for negative values of x? Indicate what happens if it is called for each of these cases. Trace the execution of fibonacciStart(5) using activation frames. Trace the execution of the following using activation frames. gcd(33, 12) gcd(12, 33) gcd(11, 5) For each of the following method calls, show the argument values in the activation frames that would be pushed onto the run-time stack. gcd(6, 21) factorial(5) gcd(31, 7) fibonacci(6) fibonacciStart(7) See for what value of n the method fibonacci begins to take a long time to run on your computer (over 1 minute). Compare the performance of fibonacciStart and fibo for this same value. PROGRAMMING Write a recursive method for raising x to the power n that works for negative n as well as positive n. Use the fact that x−n=1xn . Modify the factorial method to throw an IllegalArgumentException if n is negative. Modify the Fibonacci method to throw an illegal argument exception if its argument is less than or equal to zero. Write a class that has an iterative method for calculating Fibonacci numbers. Use an array that saves each Fibonacci number as it is calculated. Your method should take advantage of the existence of this array so that subsequent calls to the method simply retrieve the desired Fibonacci number if it has been calculated. If not, start with the largest Fibonacci number in the array rather than repeating all calculations. 5.3 Recursive Array Search Searching an array is an activity that can be accomplished using recursion. The simplest way to search an array is a linear search. In a linear search, we examine one array element at a time, starting with the first element or the last element, to see whether it matches the target. The array element we are seeking may be anywhere in the array, so on average we will examine n2 items to find the target if it is in the array. If it is not in the array, we will have to examine all n elements (the worst case). This means linear search is an O(n) algorithm. Design of a Recursive Linear Search Algorithm Let’s consider how we might write a recursive algorithm for an array search that returns the subscript of a target item. The base case would be an empty array. If the array is empty, the target cannot be there, so the result should be –1. If the array is not empty, we will assume that we can examine just the first element of the array, so another base case would be when the first array element matches the target. If so, the result should be the subscript of the first array element. The recursive step would be to search the rest of the array, excluding the first element. So our recursive step should search for the target starting with the current second array element, which will become the first element in the next execution of the recursive step. The algorithm follows. Algorithm for Recursive Linear Array Search 1. if the array is empty 2. The result is –1. else if the first element matches the target 3. The result is the subscript of the first element. else 4. Search the array excluding the first element and return the result. Implementation of Linear Search The following method, linearSearch (part of class RecursiveMethods), shows the linear search algorithm. /** Recursive linear search method (in RecursiveMethods.java). @param items The array being searched @param target The item being searched for @param posFirst The position of the current first element @return The subscript of target if found; otherwise –1 */ private static int linearSearch(Object[] items, Object target, int posFirst) { if (posFirst == items.length) return –1; else if (target.equals(items[posFirst])) return posFirst; else return linearSearch(items, target, posFirst + 1); } The method parameter posFirst represents the subscript of the current first element. The first condition tests whether the array left to search is empty. The condition (posFirst == items.length) is true when the subscript of the current first element is beyond the bounds of the array. If so, method linearSearch returns –1. The statement return linearSearch(items, target, posFirst + 1); implements the recursive step; it increments posFirst to exclude the current first element from the next search. To search an array x for target, you could use the method call RecursiveMethods.linearSearch(x, target, 0) However, since the third argument would always be 0, we can define a nonrecursive wrapper method (also called linearSearch) that has just two parameters: items and target. /** Wrapper for recursive linear search method (in RecursiveMethods.java). @param items The array being searched @param target The object being searched for @return The subscript of target if found; otherwise –1 */ public static int linearSearch(Object[] items, Object target) { return linearSearch(items, target, 0); } The sole purpose of this method is to call the recursive method, passing on its arguments with 0 as a third argument, and return its result. This method definition overloads the previous one, which has private visibility. Figure 5.8 traces the execution of the call to linearSearch in the second statement. String[] greetings = {“Hi”, “Hello”, “Shalom”}; int posHello = linearSearch(greetings, “Hello”); The value returned to posHello will be 1. image FIGURE 5.8 Trace of linearSearch(greetings, “Hello”) Design of a Binary Search Algorithm A second approach to searching an array is called binary search. Binary search can be performed only on an array that has been sorted. In binary search, the stopping cases are the same as for linear search: When the array is empty. When the array element being examined matches the target. However, rather than examining the last array element, binary search compares the “middle” element of the array to the target. If there is a match, it returns the position of the middle element. Otherwise, because the array has been sorted, we know with certainty which half of the array must be searched to find the target. We then can exclude the other half of the array (not just one element as with linear search). The binary search algorithm (first introduced in Section 5.1) follows. Binary Search Algorithm 1. if the array is empty 2. Return –1 as the search result. else if the middle element matches the target 3. Return the subscript of the middle element as the result. else if the target is less than the middle element 4. Recursively search the array elements before the middle element and return the result. else 5. Recursively search the array elements after the middle element and return the result. Figure 5.9 illustrates binary search for an array with seven elements. The shaded array elements are the ones that are being searched each time. The array element in bold is the one that is being compared to the target. In the first call, we compare “Dustin” to “Elliot”. Because “Dustin” is smaller, we need to search only the part of the array before “Elliot” (consisting of just three candidates). In the second call, we compare “Dustin” to “Debbie”. Because “Dustin” is larger, we need to search only the shaded part of the array after “Debbie” (consisting of just one candidate). In the third call, we compare “Dustin” to “Dustin”, and the subscript of “Dustin” (2) is our result. If there were no match at this point (e.g., the array contained “Duncan” instead of “Dustin”), the array of candidates to search would become an empty array. image FIGURE 5.9 Binary Search for “Dustin” Efficiency of Binary Search Because we eliminate at least half of the array elements from consideration with each recursive call, binary search is an O(log n) algorithm. To verify this, an unsuccessful search of an array of size 16 could result in our searching arrays of size 16, 8, 4, 2, and 1 to determine that the target was not present. Thus, an array of size 16 requires a total of 5 probes in the worst case (16 is 24, so 5 is log 216 + 1). If we double the array size, we would need to make only 6 probes for an array of size 32 in the worst case (32 is 25, so 6 is log2 32 + 1). The advantages of binary search become even more apparent for larger arrays. For an array with 32,768 elements, the maximum number of probes required would be 16 (log2 32,768 is 15), and if we expand the array to 65,536 elements, we would increase the number of probes required only to 17. The Comparable Interface We introduced the Comparable interface in Section 2.8. Classes that implement this interface must define a compareTo method that enables its objects to be compared in a standard way. The method compareTo returns an integer whose value indicates the relative ordering of the two objects being compared (as described in the @return tag below). If the target is type Comparable, we can apply its compareTo method to compare the target to the objects stored in the array. T represents the type of the object being compared. /** Instances of classes that realize this interface can be compared. @param

#### Why Choose Us

- 100% non-plagiarized Papers
- 24/7 /365 Service Available
- Affordable Prices
- Any Paper, Urgency, and Subject
- Will complete your papers in 6 hours
- On-time Delivery
- Money-back and Privacy guarantees
- Unlimited Amendments upon request
- Satisfaction guarantee

#### How it Works

- Click on the “Place Order” tab at the top menu or “Order Now” icon at the bottom and a new page will appear with an order form to be filled.
- Fill in your paper’s requirements in the "
**PAPER DETAILS**" section. - Fill in your paper’s academic level, deadline, and the required number of pages from the drop-down menus.
- Click “
**CREATE ACCOUNT & SIGN IN**” to enter your registration details and get an account with us for record-keeping and then, click on “PROCEED TO CHECKOUT” at the bottom of the page. - From there, the payment sections will show, follow the guided payment process and your order will be available for our writing team to work on it.